流通常是有三个部分组成
-
数据源:流的获取,比如
list.stream()
方法; -
中间处理:中间处理是对流元素的一系列处理。比如过滤
filter
,排序sorted
,映射map
; -
终端处理:终端处理会生成结果,结果可以是任何不是流值。生成List,可用
collect(Collectors.toList())
,生成Map可用collect(Collectors.toMap())
也可以不返回结果,如stream.forEach(System.out::println)
就是将结果打印到控制台中,并没有返回。
中间操作符
流方法 | 描述 |
---|---|
filter | filter函数接收一个Lambda表达式作为参数,该表达式返回 boolean,在执行过程中,流将元素逐一输送给filter,并筛选出执行结果为 true 的元素; |
distinct | 对流元素去重 |
limit | 截取流的前N个元素 |
skip | 跳过流的前n个元素,截取流后面的元素 |
map | 对流中的每个元素执行一个函数,使得元素转换成另一种类型输出。流会将每一个元素输送给map函数,并执行map中的Lambda表达式,最后将执行结果存入一个新的流中。 如:将 list 中每一个 Integer类型元素自增后转化为 String类型/对流元素加前缀/后缀等 |
flatMap | 对流进行偏平化 |
sorted | 排序, 默认按照ascii, 也可以传入自定义排序规则 |
终止操作符
流方法 | 描述 |
---|---|
anyMatch | 是否匹配任一元素anyMatch用于判断流中是否存在至少一个元素满足指定的条件,这个判断条件通过Lambda表达式传递给anyMatch,执行结果为boolean类型。 |
allMatch | 是否匹配所有元素 |
noneMatch | 是否未匹配所有元素 |
findAny | 获取任一元素(Stream()得到的是第一个元素/parallelStream()是随机获取) |
findFirst | 获取第一个元素findAny从流中随机选出 一个元素出来,它返回一个Optional类型的元素。 |
forEach | 遍历流 |
collect | 流转换 |
reduce | 将流中的元素进行合并,形成一个新的值,常见的归约操作包括求和等运算, 求最大值或最小值。 |
count | 将流中的元素个数返回 |
Optional 对象介绍
Optional是Java8新加入的一个容器,这个容器只存1个或0个元素,它用于防止出现NullpointException,它提供如下方法:
isPresent() 判断容器中是否有值。 ifPresent(Consume lambda) 容器若不为空则执行括号中的Lambda表达式。 T get() 获取容器中的元素,若容器为空则抛出NoSuchElement异常。 T orElse(T other) 获取容器中的元素,若容器为空则返回括号中的默认值。
流转换
数值流的使用
采用Stream 的 redure 方法 进行数值归约操作会涉及到基本数值类型和引用数值类型之间的装箱、拆箱操作,因此效率较低; 此时最好是将当流操作为纯数值操作时,这样使用数值流能获得较高的效率;
-
StreamAPI提供了三种数值流:IntStream、DoubleStream、LongStream;
1) 将 Stream 转换成数值流 StreamAPI 提供了将普通流转换成数值流的三种方法:mapToInt、mapToDouble、mapToLong(参数:相应的转化Lambda表达式);
将数值流转化为Stream 的方法:boxed;
List<Double> list = Arrays.asList(2.3,2.4,2.5,2.7,2.8); //普通Stream转为数值Stream DoubleStream doubles = list.stream().mapToDouble(x->x); //转化为DoubleStream IntStream ints = list.stream().mapToInt(x->Integer.parseInt(String.format("%.0f",x))); //转化为IntStream,同时进行取舍操作 //数值Stream转为普通Stream Stream stream = list.boxed();
2)数值流的数值计算
每种数值流都提供了数值计算函数,如max、min、sum、avg等。
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7); OptionalInt max = list.stream().max(); int max_value = max.orElse(0); OptionalInt sum = list.steam().sum(); iny sum_value = sum.orElse(0);
Stream 可以通过 Collector 收集器,将其转化为 Array,Collection,Map,String;
//普通转换 Stream<String> stream = Stream.of("are","you","ok"); String[] array = stream().toArray(); //涉及拆箱、装箱操作的转换 Stream<Integer> stream = Stream.of(1,2,3,4,5,6); int[] array = stream.mapToInt(x->x).toArray(); Integer[] array = stream.toArray(Integer[]::new); //将 List<Inetegr> 转化为 String[] List<Integer> list = Arrays.asList(1,2,3,4,5); String[] array = list.stream().map(String::valueOf).toArray(String[]::new); // 转换为list集合 List<Integer> list1 = stream.collect(Collectors.toList()); List<Integer> list2 = stream.collect(Collectors.toCollection(ArrayList::new)); // 转换为Set集合 Set<Integer> set = stream.collect(Collectors.toCollection(Set::new)); // 转换为栈 Stack<Integer> stack = stream.collect(Collectors.toCollection(Stack::new)); // 转换为map //使用val的hashcode为key,val本身为value Map<Integer, String> map = Stream.of("are","you","ok").collect(Collectors.toMap( s -> s.hashCode(), s -> s)); // 使用val的hashcode为key,val本身为value,如果key的value重复,则使用新的value Map<Integer, String> map = Stream.of("are","you","ok").collect(Collectors.toMap( s -> s.hashCode(), s -> s,(oldval,newval)->newval)); //将 List 转化为使用 “,” 分隔的字符串 List<Integer> list = Arrays.asList(1,2,3,4,5,6,7); String str = list.stream().map(x->x.toString()).collect(Collectors.joining(",")); System.out.println(str); //输出: 1,2,3,4,5,6,7
过滤和排序
Stream.of(1, 8, 5, 2, 1, 0, 9, 2, 0, 4, 8) .filter(n -> n > 2) // 对元素过滤,保留大于2的元素 .distinct() // 去重,类似于SQL语句中的DISTINCT .skip(1) // 跳过前面1个元素 .limit(2) // 返回开头2个元素,类似于SQL语句中的SELECT TOP .sorted() // 对结果排序 .forEach(System.out::println); //filter后剩下:8,5,9,4,8 //去重后排序剩下:5,9
of()方法的底层是 Array.Stream()
查找和匹配
Stream中提供的查找方法有anyMatch()、allMatch()、noneMatch()、findFirst()、findAny()
, 这些方法被用来查找或匹配某些元素是否符合给定的条件:
boolean hasMatch = Stream.of("Java", "C#", "PHP", "C++", "Python") .anyMatch(s -> s.equals("Java")); // hasMatch:true boolean hasAllMatch = Stream.of("Java", "C#", "PHP", "C++", "Python") .allMatch(s -> s.contains("#")); //hasAllMatch:false Optional<String> element = Stream.of("Java", "C#", "PHP", "C++", "Python") .filter(s -> s.contains("C")) // .findFirst() // 查找第一个元素 .findAny(); // 查找任意元素 //element:Optional[C#]
实际上测试结果发现,
findFirst()
和findAny()
返回的都是第一个元素,两者之间到底有没什么区别呢因为Stream()是串行,调用findAny()都会获取第一个
而parallelStream()是并行,调用findAny()会随机获得
归约
归约操作就是将流中的元素进行合并,形成一个新的值,常见的归约操作包括求和等运算, 求最大值或最小值。归约操作一般使用reduce()
方法, 与map()
方法搭配使用,可以处理一些很复杂的归约操作。
List<Book> books =Arrays.asList( new Book("Java编程思想", "Bruce Eckel", "机械工业出版社", 108.00D), new Book("Java 8实战", "Mario Fusco", "人民邮电出版社", 79.00D), new Book("MongoDB权威指南(第2版)", "Kristina Chodorow", "人民邮电出版社", 69.00D) ); // 计算所有图书的总价 Optional<Double> totalPrice = books.stream() .map(Book::getPrice) .reduce((n, m) -> n + m); // 价格最高的图书 Optional<Book> expensive = books.stream().max(Comparator.comparing(Book::getPrice)); // 价格最低的图书 Optional<Book> cheapest = books.stream().min(Comparator.comparing(Book::getPrice)); // 计算总数 long count = books.stream().count();