Lambda Stream
Lambda
Lambda 表达式的本质: 函数式接口的实例;
函数式接口:@FunctionalInterface 标识的接口,只有一个抽象方法;
核心函数式接口
接口名称 | 抽象方法 |
---|---|
Consumer | void accept(T t) |
Supplier | T get() |
Predicate | boolean test(T t) |
Function<T,R> | R apply(T) |
Comparator | int compare(T t1, T t2) |
其它常用接口
Function 接口的子接口:
UnaryOperator # T apply(T t);
BiFunction<T,U,R> # R apply(T t , U u);
子接口:BinaryOperator # T apply(T t1 , T t2);
BiConsumer<T,U> # void accept(T t , U u);
BiPredicate<T,U> # boolean test(T t , U u );
方法引用
如果要传递给 Lambda 体的操作,已经有现成的实现方法了,可以使用方法引用;
要求:接口中抽象方法的参数列表和返回值类型,必须与方法引用的参数列表和返回值类型保持一致;
方法引用的格式
- 对象::实例方法名;
例:employeeObj.getName() 与 Supplier 接口中的 T get() —> employeeObj::getName; - 类::静态方法名;
例:Comparator 接口中 int compare(T t1, T t2) 与 Integer中的静态方法:int compare(int x, int y) --> Integer::compare; - 类::实例方法名;
例:BiPredicate 中的 boolean test(T t , U u ) 与 String 类中的 boolean s1.equals(s2); --> String::equals;
Comparator中的 int compare(int a,int b) 与 String 中的 s1.compareTo(s2) --> String::compareTo;
Function 中的 R apply(T) 与 Employee 中的 String empObj.getName(); --> Employee::getName;
来一起看几个例子:
@Testpublic void test03(){//Consumer 中的 void accept(T t)// PrintStream 中的 void println(T t)Consumer<String> con1 = str -> System.out.println(str);con1.accept("test");PrintStream ps = System.out;Consumer<String> con2 = ps::println;con2.accept("test");}@Testpublic void test04(){Employee emp = new Employee();emp.setName("hello");Supplier<String> sup1 = () -> emp.getName();System.out.println(sup1.get());Supplier<String> sup2 = emp::getName;System.out.println(sup2.get());}@Testpublic void test05(){Comparator<Integer> com1 = (i1,i2) -> Integer.compare(i1, i2);System.out.println(com1.compare(1, 2));System.out.println("=============>");// 类::静态方法Comparator<Integer> com2 = Integer::compare;System.out.println(com2.compare(2, 1));}@Testpublic void test06(){/** 类 :: 实例方法* Comparator 中的 int compare(T t1, T t2)* String 中的 int t1.compareTo(t2)* */Comparator<String> com1 = (s1,s2) -> s1.compareTo(s2);System.out.println(com1.compare("abc", "abf")); // -3System.out.println("=============>");Comparator<String> com2 = String::compareTo;System.out.println(com2.compare("abc", "abd")); //-1//匿名子类的形式Comparator<String> com3 = new Comparator<String>() {@Overridepublic int compare(String o1, String o2) {return o1.compareTo(o2);}};}@Testpublic void test07(){//类::实体方法// BiPredicate 中的 boolean test(t1,t2)// String 中的 boolean t1.equals(t2)BiPredicate<String,String> p1 = (s1,s2) -> s1.equals(s2);System.out.println(p1.test("ab", "ab"));BiPredicate<String,String> p2 = String :: equals;System.out.println(p2.test("ab", "ab"));}@Testpublic void test08(){/*类::实体方法* Function中的 R apply(T t)* Employee 中的 String empObj.getName()* */Employee emp = new Employee("gcx", 18,180000.00);Function<Employee,String> func1 = e -> e.getName();System.out.println(func1.apply(emp));Function<Employee,String> func2 = Employee::getName;System.out.println(func2.apply(emp));}
Stream
Stream 对集合数据进行操作,可以执行复杂的查找、过滤和映射;
特点:
Stream 本身无法存储元素;
不改变源对象;
创建 Stream 的四种方式
- Collection 接口中的默认方法 : stream()
List 、Set、Queue等,直接调用 stream() 方法就可以获得 Stream;
Stream stream2 = list.stream(); - Arrays 的静态方法: Arrays.stream(T[] array)
Stream stream1 = Arrays.stream(new String[]{“d”,“e”,“f”}); - Stream 的静态方法 :Stream.of(T…values);
Stream stream = Stream.of(“A”,“B”,“C”,“D”);
stream.forEach(System.out::println); - 基于 Supplier;
Stream s = Stream.generate(Supplier sp);
s.limit(20).forEach(System.out::println);
此种方式创建的 Stream 会不断调用 Supplier.get() 方法来产生下一个元素,打印的时候必须使用 limit() 使其先变成有限序列;
Stream 的优点:Stream几乎不占用空间,因为每个元素都是实时计算出来的,用的时候再算;
支持基本数据类型的流:
Java 的泛型不支持基本数据类型,我们无法使用 Stream 这样的类型,只能使用 Stream , 但是这样会频繁进行拆、装箱,影响效率;
java 标准库提供了 : IntStream LongStream 和 DoubleStream;
// IntStream
IntStream stream = Arrays.stream(new int[]{1,2,3});
//LongStream
List<String> list1 = Arrays.asList("1","2","3");
LongStream longStream = list1.stream().mapToLong(Long::parseLong);
/**
LongStream mapToLong(ToLongFunction<? super T> mapper);
@FunctionalInterface
public interface ToLongFunction<T> {long applyAsLong(T value);
}
*/OptionalLong max = list1.stream().mapToLong(Long::parseLong).max();
Long asLong = max.getAsLong();
实例:打印斐波那契数列
@FunctionalInterface
public interface LongSupplier{long getAsLong();
}
class FibSupplier implements LongSupplier{public static long num =1 ;public long getAsLong(){return fib(num++);}public long fib(long num){if(num ==1 || num == 2){return 1;}else{return fib(num-2) + fib(num-1);}}
}
public class Test1{public static void main(String[] args){LongStream fib = LongStream.generate(new FibSupplier());//打印fib.limit(10).forEach(System.out::println);}
}
常见的Stream 操作
map()
Stream.map() 是 Stream 最常用的一个转换方法,把一个 Stream 转换为另一个 Stream;
所谓 map 操作,就是把一种运算操作映射到序列的每一个元素上;
map(Function);
Arrays.asList("Apple","Pear","Orange","Banana").stream().map(String::trim).map(String::toLowerCase).forEach(System.out::println);
filter
filter(Predicate)
filter 可以对一个 Stream 的所有元素进行测试,不满足条件就扔掉,剩下的满足条件的元素就构成一个新的Stream;
reduce
reduce(T identity, BinaryOperator accumulator)
T apply(t1,t2) # 负责把上次累加的结果和本次的元素进行运算;
identity # 执行累加计算的初始值;
map 和 filter 都是 Stream 的转换方法,而 Stream.reduce() 是 Stream的一个聚合方法;把所有元素聚成一个结果;
// acc是上次计算的结果,初始为0;
int sum = Stream.of(1,2,3,4,5,6).reduce(0,(acc,n) -> acc + n );
如果去掉初始值,我们会得到一个 Optional:
Optional<Integer> opt = stream.reduce((acc,n) -> acc +n);
if(opt.isPresent()){ System.out.println(opt.get());
}
因为 Stream 的元素有可能是 0 个,这样就没法调用 reduce() 的聚合函数了;
注意:
Stream 的转换操作 map 和 filter 并不会触发任何计算(只保存了转换规则);
聚合操作是真正需要从 Stream 请求数据的,会立刻促使 Stream 输出它的每一个元素;
输出为List
如果我们希望把 Stream 的元素保存到集合(把Stream变成list是一个聚合操作);
// 获得的实体类是 ArrayList
List<String> collect = stream.filter(s -> s!=null && !s.isEmpty()).collect(Collectors.toList());
输出为数组
A[] toArray(IntFunction<A[]> generator);
@FunctionalInterface
public interface IntFunction{
R apply(int value);
}
String[] strings = list.stream().toArray(String[]::new);
输出为 Map
Map<String,String> map = stream.collect(Collectors**.toMap(**
s -> s.substring(0,s.indexOf(":")),
s -> s.substring(s.indexOf(":") +1)
));
toMap 里面是两个 Function 实现类,分别对应 key的映射,和 value 的映射;
分组输出
List<String> list1 = Arrays.asList("Apple","Banana","Blackberry","Coconut", "Avocado","Cherry","Apricots");
//以单词的首字母分组;
Map<String,List<String>> collect1 = list1.stream().collect(Collectors.groupingBy(s -> s.substring(0,1),Collectors.toList()));
排序
// 要求每个元素必须实现 Comparable 接口;
stream.sorted().collect(Collectors.toList());
//传入比较规则;
stream.sorted(String::compareToIgnoreCase).collect(Collectors.toList());
去重
List<String> list2 = Arrays.asList("a","A","b","b","A");
List<String> collect2 = list2.stream().distinct().collect(Collectors.toList());
截取
//skip(2): 跳过前两个;
// limit(3) : 输出 3个;
List<String> collect2 = list2.stream().skip(2).limit(3).collect(Collectors.toList());
并行
将对 Stream 元素的单线程处理,变为并行处理:
stream.parallel().sorted().toArray(String[] :: new );
合并
Stream.comcat(s1,s2);
遍历
forEach(Consumer)
它可以循环处理 Stream 的每个元素,我们经常传入 System.out::println 来打印 Stream的元素;
flatMap
所谓 flatMap() 是把 Stream 的每个元素 (list) 映射为 Stream, 然后合并成一个新的 Stream
Stream<List<Integer>> s = Stream.of(
Arrays.asList(1,2,3),
Arrays.asList(4,5,6),
Arrays.asList(7,8,9)
);
Stream<Integer> i = s.flatMap(list -> list.stream());
最大、最小
max(Comparator<? super T> cp ) : 找出最大元素;
min(Comparator<? super T> cp ) : 找出最小元素;
测试 Stream 的元素是否满足条件
boolean allMatch(Predicate<? super T>) : 测试是否所有元素均满足测试条件;
boolean anyMatch(Predicate<? super T>) : 测试是否至少有一个元素满足测试条件。
sum、average
针对IntStream 、 LongStream、 DoubleStream , 还额外提供了以下聚合方法:
sum() : 对所有元素求和;
average() : 对所有元素求平均数;
拼接流中的元素
//用 xxx 拼接流中的元素;
String s = list2.stream().collect(Collectors.joining("xxx"));
findFirst、orElse、orElseThrow
findFirst: 获取第一个元素,返回值是 Optional
orElse : 通常与 findFirst 配合使用,意思是,找不到就返回指定的默认值;
orElseThrow : 通常与 findFirst 配合使用,意思是,找不到就抛异常;
List<String> list2 = Arrays.asList("r","ba","c","sd","e","f");
String s1 = list2.stream().filter(s -> s.contains("a")).findFirst().orElse("haha");Optional<String> a1 = list2.stream().filter(s -> s.contains("a")).findFirst();String a1 = list2.stream().filter(s->s.contains("a")).findFirst().orElseThrow(RuntimeException::new);
Lambda Stream相关推荐
- lambda stream流处理异常的方法/Either不终止stream流处理异常
lambda stream流处理异常的方法/Either不终止stream流处理异常 1.直接用try/catch捕获 1.1 stream流中使用try/catch 案例如下,在list中存在可能引 ...
- java stream foreach_Java 8 Lambda Stream forEach具有多个语句
我仍在学习Lambda,请原谅我做错了什么 final Long tempId = 12345L; List updatedEntries = new LinkedList<>(); fo ...
- 零基础学习java------21---------动态代理,java8新特性(lambda, stream,DateApi)
1. 动态代理 在一个方法前后加内容,最简单直观的方法就是直接在代码上加内容(如数据库中的事务),但这样写不够灵活,并且代码可维护性差,所以就需要引入动态代理 1.1 静态代理实现 在讲动态代理之前, ...
- parallel循环java_Java 8 lambda stream forEach parallel 等循环与Java 7 for each 循环耗时测试...
Java 8 里面的stream 有串行流和并行流之分. 说高级的stream就是那个并行流.下面是那个并行流的简单实现.只要是继承Collection类的都可以这么用. list.stream(). ...
- java8 Lambda Stream collect Collectors 常用实例
将一个对象的集合转化成另一个对象的集合 List<OrderDetail> orderDetailList = orderDetailService.listOrderDetails(); ...
- lambda stream 循环_jdk8-lambda-stream的使用
1, 认识stream(声明式编程) Stream 不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像一个高级版本的 Iterator, 原始版本的Iterator,用户只能一个一 ...
- Java基础巩固(二)异常,多线程,线程池,IO流,Properties集合,IO工具类,字符流,对象流,Stream,Lambda表达式
一.异常,多线程 学习目标 : 异常的概述 异常的分类 异常的处理方式 自定义异常 多线程入门 1 异常的概述 1.1 什么是异常? 异常就是程序出现了不正常情况 , 程序在执行过程中 , 数据导致程 ...
- JDK1.8中的Stream详解
Stream简介 Stream 作为 Java 8 的一大亮点,它与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念.它也不同于 StAX 对 XML ...
- stream of java_java8新特性之强大的Stream API
Stream API Stream是Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找.过滤和映射数据等操作. 使用Stream API 对集合数据进行操作, ...
最新文章
- struts2+hibernate+Spring分层开发
- 【分块】#6278. 数列分块入门 2 (区间修改、查询权值c在区间中的排名)
- python十一:集合(set)
- (chap2 简单的Http协议) HTTP方法(2)其他方法
- 【机器学习】机器学习中缺失值处理方法大全(附代码)
- eclipse主题下载网站
- 【C++深度剖析教程6】C++之友元
- Mac计算器的计算过程怎么看?教你一键查看运算记录!
- grandMA2onPC控制UE4灯光
- 在HTML中什么表示水平线,HTML中加入水平线的标签是( )
- php 新浪微博登陆,PHP使用新浪微博登入第三方网站实例代码
- 瘦了红颜, 多了寂寞
- 几种常用的文件加密方法
- Linux 安装DockerMysql
- 第二个MFC实例:GPA计算器
- 不叹惜、不呼唤我也不哭泣
- 基于Montgomery算法的高速、可配置 RSA密码IP核硬件设计系列(五)——模幂模块(抵抗侧信道攻击)模块的设计实现方案
- 【计量经济学导论】02. 多元回归模型
- 中国联通再次下调国际漫游资费 最高降幅达90.42%
- 微信小程序通过css实现底部边大圆弧效果
热门文章
- 从头开始学习 Dojo,第 2 部分 使用 Dojo 掌握面向对象开发
- ps ax ps axu_ps4s梦想的力量
- ACM中涉及到的数学知识
- 使用python随机画几何图形(矩形、圆形、三角形...)
- 高炉顶压前馈控制(布料扰动)
- 企业微信小程序可用存储空间不足_企业微信小程序制作,小程序开发公司
- Python3.6.1 AES/ECB/padding PKCS5 方法的加密解密脚本实现
- Oracle 11g RAC安装--基于openfiler存储+多路径+udev方式
- 关于iOS 11 tableView自动布局懵逼的事
- 插画软件_插画家眼中的色彩互动