CSDN(https://blog.csdn.net/wisfy_21/article/details/80356822)要审核,现在看不了,先暂存一下。
[TOC]
流简介
流提供了对数据集合操作的简便方式,而且它更加灵活,性能也更好。与集合关注数据不同,流更加关注对数据的处理。
流的使用使得代码语义更加明确,易于阅读,比如:
//找到符合条件的数据并打印
Stream.of(23, 34, 124, 5, 19, 2, 4, 100)
.filter(i -> i > 20 && i < 100)
.forEach(System.out::println);
流的使用一般包含以下几个部分:
- 数据源,比如,集合、数组或者输入/输出资源。
- 中间操作。中间操作一般都会返回另一个流,而且中间操作不会立即执行。除非流水线上触发一个终端操作,否则中间操作不会执行任何处理。
- 终端操作。终端操作从流中得到处理结果,一般结果不是流。
需要注意的是,流只能消费一次。
流操作
流的重点在于对数据的处理。简单认识流之后,实际使用还需要明白流可以做哪些事情。下面列举几个常用的操作:
筛选、切片
1.filter,根据函数式接口Predicate的实例,操作的结果(boolean),返回包含所有符合要求的数据的流。
2.distinct,返回去重后的新的数据流。元素是否重复根据hashCode和equals方法判断。
Stream.of(23, 34, 124, 23, 19, 2, 4, 100)
.filter(i -> i > 20 && i < 100)
.distinct()
.forEach(System.out::println);
3.limit,限制返回流中元素的个数。
4.skip,跳过指定个数的元素。
IntStream.range(0,100)
.skip(50)
.limit(5)
.forEach(i -> System.out.print(i + " "));
//50 51 52 53 54
查找、匹配
查找操作有两个:
- findFirst,返回当前流中的第一个元素
- findAny,返回当前流中的一个元素,不关心位置。这里并不会随机返回一个数据,单线程环境下还是一直返回第一个元素。但是在并行环境下,如果不关心返回数据的位置,findAny的性能更优。
注意:两者返回的数据都是Optional
- isPresent(),是否包含值
- ifPresent(Consumer super T> consumer),当值存在时,执行函数式接口Consumer,其接口签名为:void accept(T t);
- T get(),返回值,不存在是将抛出错误。
- T orElse(T other),如果值存在返回值,不存在返回指定的值作为默认值。
Stream.of("A", "B","D","P","M","S","Q")
.filter(str -> str.compareTo("H") > 0)
.findAny()
.ifPresent(System.out::println);
//输出:P
匹配操作有allMatch、anyMatch、noneMatch。匹配操作返判断流中的数据是否满足指定条件,它们的返回值是boolean类型。
boolean result = Stream.of("A", "B","D","P","M","S","Q")
.allMatch(str -> str.compareTo("a") < 0);
规约
规约指reduce操作,将数据流中的数据进行规约操作,得到一个值。通过reduce操作可以很方便的实现求和、最大与最小值得计算等等。
求和:
int sum = IntStream.range(0,101).reduce((a,b) -> a+ b).getAsInt();
System.out.println(sum);
最大值:
int max = new Random()
.ints(0,1000)
.limit(100)
.reduce(Integer::max).getAsInt();
注:reduce操作有三个版本,使用时可以根据需要选择。
映射
- map操作,将每一个元素映射为另一个元素。
Stream.iterate(0, i -> i+2).limit(10).map(i -> i*2).forEach(System.out::println);
map应该是个很强大的操作,比如可以从对象中提取指定的属性,或者对对象执行某些操作得到新的对象等等。
- flatMap操作,合并流的内容,扁平化为一个流
List result = Stream.of("Hello","night")
.map(w -> w.split("")) //返回的是Stream
.flatMap(Arrays::stream) //将每个String[]转成Stream,合并
.distinct()
.collect(toList());
System.out.println(result);
//[H, e, l, o, n, i, g, h, t]
收集
collect操作是一个终端操作,可以将根据指定操作转成集合或者Map。
流的构建
- 使用Stream.of通过值来构建
- 通过数组来构建
int[] numbers = {2,354,56,6,76,31,12};
int max = Arrays.stream(numbers).max().getAsInt();
System.out.println(max);
- 集合构建,Collection接口的stream方法可以直接放回流
List numbers = Arrays.asList(2,354,56,6,76,31,12);
int min = numbers.stream().min(Integer::compareTo).get();
System.out.println(min);
- 文件生成流
Files.lines(Paths.get("F:\\data.txt")).forEach(System.out::println);
- 无限流
使用Stream.iterate和Stream.generate方法,可以按需产生无线流。
Stream.iterate(0, i -> i+2).limit(100).forEach(System.out::println);
Stream.generate(Math::random).limit(10).forEach(System.out::println);
数值流
Stream流中的数据都是对象类型,如果希望操作数据的话,使用时暗含装箱操作。为避免这个问题,Java 8提供了IntStream、DoubleStream、LongStream。这些流类型不仅仅是在内部使用基本类型,还提供了数值操作的快捷API,像sum、max、min等等。而且,它们与Stream之间可以相互转化。
注:内容主要来自《Java 8实战》,目前只介绍了简单的用法,更多的像分组分区、自定义收集器等,后面找机会再补补。