祸兮,福所依;福兮,祸所伏。
什么是流?
简单说,流是从集合中计算得来的一组元素序列。
集合与流之间的差异就在于什么时候进行计算:
集合是一个内存中的数据结构,它包含数据结构中目前所有的值——集合中的每个元素都得先算出来才能添加到集合中。
相比之下,流则是在概念上固定的数据结构(你不能添加或删除元素),其元素是按需计算的。
筛选元素,例:筛选字符长度>3的元素
// 返回"three","four"
Stream.of("one", "two", "three", "four")
.filter((e) -> e.length() > 3);
元素去重
// 返回元素"one","three","four"
Stream.of("one", "one", "three", "four")
.distinct();
返回前n条数据
// 返回元素"one","two"
Stream.of("one", "two", "three", "four")
.limit(2);
跳过前 n 条数据
// 返回元素"three","four"
Stream.of("one", "two", "three", "four")
.skip(2);
通常用于将一个类型转换成另外一个类型,也可以是同类型
// 将每个元素映射成大写
Stream.of("one", "two", "three", "four")
.map(String::toUpperCase);
// User -> UserDTO
User user = new User();
Stream<UserDTO> userDTOStream = Stream.of(user)
.map((u) -> {
UserDTO dto = new UserDTO();
BeanUtils.copyProperties(u, dto);
return dto;
});
补充:
mapToInt,将元素转换成int类型, 返回IntStream
mapToLong,将元素转换成long类型,返回LongStream
mapToDouble,将元素转换成double类型,返回DoubleStream
在操作原始数值类型时,最好使用原始类型特化流,因为这些流将元素特化为int、long、double等基本类型,从而避免了进行数值计算时,暗含的装箱、拆箱成本。
流的扁平化。flatmap方法让你把一个流中的每个值都换成另一个流,然后把所有的流连接起来成为一个流。
它比较适用于Stream中元素是一个集合或数组的情况,比如:
Stream
举个例子:words 数组元素为 {“one”,“two”,“three”},目标时将words以字符格式输出,即:‘o’ ‘n’ ‘e’ …
String[] words = {"one","two","three"};
Stream<String> stream = Stream.of(words);
// 分割字符串
Stream<String[]> stream1 = stream.map(e -> e.split(""));
// 将Stream 转换成 Stream
Stream<String> stringStream = stream1.flatMap(e -> Arrays.stream(e));
stringStream.collect(Collectors.toList())
.forEach(s -> System.out.print(s + " "));
说起来,flatMap有点像双层for循环,它可以对stream流中单个元素再进行拆分。
补充:
flatMapToInt,将元素扁平成int类型
flatMapToLong,将元素扁平成long类型
flatMapToDouble,将元素扁平成double类型
流中是否有一个元素能匹配
是否匹配所有元素
流中没有任何元素匹配
查找元素,返回当前流中的任意元素
查找第一个元素
reduce方法可以用在数字求和、乘积等场景。
它的作用是每次计算的时候都用到上一次的计算结果,比如求和操作:前两个数的和加上第三个数的和,一直加到最后一个数位置,最后返回结果。
int sum = IntStream.of(3, 4, 8)
.reduce(0, (a, b) -> a + b);
当然,这里用IntStream的sum方法更好
int sum = IntStream.of(3, 4, 8)
.sum();
可接受一个泛型对象或可变泛型对象集合,返回一个Stream对象
Stream<String> stream = Stream.of("a", "b", "c");
创建一个空的Stream对象
Stream<Object> empty = Stream.empty();
连接两个Stream,返回一个新的Stream
Stream<String> a = Stream.of("a","b","c");
Stream<String> b = Stream.of("d","e");
Stream<String> c = Stream.concat(a,b);
// 输出:abcde
c.collect(Collectors.toList()).forEach(System.out::print);
peek:窥视,窥探;
java源码中对这个方法进行了详细描述
简单说:这个方法的存在主要是为了支持调试
java源码提供的案例如下:
Stream.of("one", "two", "three", "four")
.filter(e -> e.length() > 3)
.peek(e -> System.out.println("Filtered value: " + e))
.map(String::toUpperCase)
.peek(e -> System.out.println("Mapped value: " + e))
.collect(Collectors.toList());
输出结果:
Filtered value: three
Mapped value: THREE
Filtered value: four
Mapped value: FOUR
这个方法的好处在于,我们可以在执行Stream的filter、map或者其他操作之后可以查看到数据执行的结果。