如果前方的路是黑暗的,那应该先找到指路的灯
java8中的 StreamAPI 非常丰富,本文介绍几种比较重要的API。
- collect(toList()) 这个方法是用于生成一个列表, 是一个
及早求值操作
.
下面看一段示例代码
List<String> collected = Stream.of("a", "b", "c").
collect(Collectors.toList());
assertEquals(Arrays.asList("a", "b", "c"), collected);
上一篇文章中说过,Stream中的很多操作都是惰性求值,因此在Stream中的一系列方法之后,需要调用一个collect的及早求值方法,从而得到一个List<String>,下面这句是用断言测试工具测试结果是否为预期的。
- map操作可以将一个流中的值转换成一个新的流
下面看一段示例代码
//使用map操作
List<String> collected = Stream.of("a", "b", "hello")
.map(str -> str.toUpperCase()).collect(Collectors.toList());
assertEquals(Arrays.asList("A", "B", "HELLO"), collected);
传给map的lambda表达式只接受一个String类型的参数,返回一个新的String。参数和返回值不必属于同一种类型,但是lambda表达式必须是Function接口的一个实例,Function接口是只包含一个参数的普通函数接口。
map操作一开始理解起来有点抽象。 在看看下面这个例子
//使用map操作
List<Integer> collected2 = Stream.of(1, 2, 3).map(i32 -> i32 + 1)
.collect(Collectors.toList());
collected2.stream().forEach(i32 -> {
System.out.println(i32);
});
assertEquals(Arrays.asList(2, 3, 4), collected2);
这里通过实现map中的 Function接口,来对数据进行 +1 的操作。
3.filter 遍历数据并检查其中的元素。
//使用filter操作
List<String> beginningWithNumbers = Stream.of("a", "abc", "1abc").
filter(value -> isDigit(value.charAt(0))).collect(Collectors.toList());
assertEquals(Arrays.asList("1abc"), beginningWithNumbers);
和map很像, filter接收一个函数作为参数,该函数用lambda表达式表示。该函数和前面实例中if条件判断语句的功能一样,如果字符串首字母为数字,则返回true,因此若要重构遗留的代码,for循环中的if条件语句就可以用filter方法替代。
- flatMap
前面的map操作,它可用一个新的值代替Stream中的值,但有时,用户希望让map操作有点变化,生成一个新的Stream对象代替它,但是又不希望结果是一连串的流,此时flatMap最能派上用场。 看下面的例子。
//使用flatMap
List<Integer> together = Stream.of(Arrays.asList(1, 2), Arrays.asList(3, 4))
.flatMap(numbers -> numbers.stream()).
collect(Collectors.toList());
assertEquals(Arrays.asList(1, 2, 3, 4), together);
用flatMap实际上是将每个列表转换成 Stream对象,其余部分由flatMap方法处理。flatMap方法相关函数接口和map方法一样, 都是 Function接口,只是方法的返回值限定为Stream类型了。通俗一点的讲,就是将参数都转换成stream,形成了一个stream在通过及早求执方法 collect()得到一个 together的 List<Integer>
- max 和 min操作。
max和min是Stream上比较常用的操作。例如下代码中,找到track中字段num值最小的一条
List<Track> tracks = Arrays.asList(
new Track("第二天堂", 15),
new Track("大将军", 8),
new Track("荒野猎人", 20));
Track shortestTrack = tracks.stream()
.min(Comparator.comparing(track -> track.getNum())).get();
assertEquals(tracks.get(1), shortestTrack);
max或min方法需要指定一个排序指标作为甄选依据,示例代码中我们指定了num字段作为排序依据,同理,需要获取最大值时,只需要改用max方法即可。为了让Stream对象按照track的长度进行排序,需要传一个Comparator对象,java8 中提供了一个新的静态方法, comparing,使用它可以方便地实现一个比较器。
6.reduce操作
reduce操作可以实现从一组值中生成一个值,实际上 count ,max,min等因为比较常用,所以被纳入了标准库中,其实这些方法都是reduce操作,先看一段代码
//点定义一个 BinaryOperator并指定它的结果是由 第一个参数+第二个参数组成的
BinaryOperator<Integer> accumulator = (acc, element) -> acc + element;
//紧接着,模拟每一次的操作
int count2 = accumulator.
apply(accumulator.
apply(accumulator.
apply(0, 1)
, 2)
, 3);
这里先从最内部开始,第一个值 0,1相加得到1,第二层 1,2 相加得到3 ,最外面一层,3加3等于6,实际上,他的操作方式就是我们在上面代码第一行定义的。 然后改成使用reduce方式在看看代码是怎么实现的呢?
int count = Stream.of(1, 2, 3).reduce(0, (acc, element) -> acc + element);
在使用Stream的reduce操作时,实际上就是将集合中的参数,以0为起点,按照两个参数传入Stream中的当前元素和 acc。将两个参数相加,acc在这里实际上就是累加器,保存着当前的累加结果。
此类的计算方式,在引入java8之前,我们还需要使用for循环,另外定义一个累加器,每次循环取出数据进行累加,并更新打累加器。 如果使用了reduce方式,是不是方便了很多呢。
其实我们也可以通过reduce来实现诸如 max, min的方法
int max = Stream.of(1,2,3).reduce(0, (acc, element) -> acc>element?acc:element);
System.out.println(max);
int min = Stream.of(1, 2, 3).reduce(0, (acc, element) -> acc<element?acc:element);
System.out.println(min);
你值得拥有最好的自己