Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。
对于流的处理,主要有三种关键性操作:分别是流的创建、中间操作(intermediate operation)以及最终操作(terminal operation)。
在Java 8中,除了增加了很多Stream相关的类以外,还对集合类自身做了增强,在其中增加了stream方法,可以将一个集合类转换成流。
/**
* 通过集合生成,应用中最常用的一种
*/
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> stream1 = integerList.stream();
/**
* 通过数组生成
* 通过Arrays.stream方法生成流,并且该方法生成的流是数值流【即IntStream】而不是Stream<Integer>。补充一点使用数值流可以避免计算过程中拆箱装箱,提高性能。
*/
int[] intArr = new int[]{1, 2, 3, 4, 5};
IntStream stream2 = Arrays.stream(intArr);
以上,通过一个已有的List创建一个流。除此以外,还有一个parallelStream方法,可以为集合创建一个并行流。(多线程方式,需要考虑线程安全问题)
这种通过集合创建出一个Stream的方式也是比较常用的一种方式。
可以使用Stream类提供的of方法,直接返回一个由指定元素组成的流。
/**
* 通过值生成
* 通过Stream的of方法生成流,通过Stream的empty方法可以生成一个空流
*/
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
Stream有很多中间操作,多个中间操作可以连接起来形成一个流水线,每一个中间操作就像流水线上的一个工人,每人工人都可以对流进行加工,加工后得到的结果还是一个流。
通过使用filter方法进行条件筛选,filter的方法参数为一个条件
/**
* filter筛选
* 通过使用filter方法进行条件筛选,filter的方法参数为一个条件
*/
List<Integer> integerList = Arrays.asList(1, 1, 2, 3, 4, 5);
Stream<Integer> stream = integerList.stream().filter(i -> i > 3);
//stream.forEach(System.out::println);
通过limit方法指定返回流的个数,limit的参数值必须>=0,否则将会抛出异常
/**
* limit返回指定流个数
* 通过limit方法指定返回流的个数,limit的参数值必须>=0,否则将会抛出异常
*/
List<Integer> integerList1 = Arrays.asList(1, 1, 2, 3, 4, 5);
Stream<Integer> stream1 = integerList1.stream().limit(3);
//stream1.forEach(System.out::println);
通过skip方法跳过流中的元素,上述例子跳过前两个元素,所以打印结果为2,3,4,5,skip的参数值必须>=0,否则将会抛出异常
/**
* skip跳过流中的元素
* 通过skip方法跳过流中的元素,上述例子跳过前两个元素,所以打印结果为2,3,4,5,skip的参数值必须>=0,否则将会抛出异常
*/
List<Integer> integerList2 = Arrays.asList(1, 1, 2, 3, 4, 5);
Stream<Integer> stream2 = integerList2.stream().skip(2);
//stream2.forEach(System.out::println);
sorted 方法用于对流进行排序。以下代码片段使用 sorted 方法进行排序
/**
* sorted对流进行排序
* sorted 方法用于对流进行排序。以下代码片段使用 sorted 方法进行排序
*/
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
numbers.stream().sorted().forEach(System.out::println);
distinct主要用来去重,以下代码片段使用 distinct 对元素进行去重
/**
* distinct去重
* distinct主要用来去重,以下代码片段使用 distinct 对元素进行去重
*/
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
numbers.stream().distinct().forEach(System.out::println);
所谓流映射就是将接受的元素映射成另外一个元素
/**
* map流映射(所谓流映射就是将接受的元素映射成另外一个元素)
*/
List<String> stringList = Arrays.asList("Java 8", "Lambdas", "In", "Action");
Stream<Integer> stream3 = stringList.stream().map(String::length);
//stream3.forEach(System.out::println);
将一个流中的每个值都转换为另一个流
/**
* flatMap流转换(将一个流中的每个值都转换为另一个流)
*/
List<String> wordList = Arrays.asList("Hello", "World");
List<String> strList = wordList.stream()
.map(w -> w.split(" "))
.flatMap(Arrays::stream)
.distinct()
.collect(Collectors.toList());
//strList.forEach(System.out::println);
/**
* 元素匹配 - allMatch匹配所有
*/
List<Integer> integerList3 = Arrays.asList(1, 2, 3, 4, 5);
if (integerList3.stream().allMatch(i -> i > 3)) {
System.out.println("值大于3");
}
/**
* 元素匹配 - anyMatch匹配其中一个
*/
List<Integer> integerList4 = Arrays.asList(1, 2, 3, 4, 5);
if (integerList4.stream().anyMatch(i -> i > 3)) {
System.out.println("存在大于3的值");
}
/**
* 元素匹配 - noneMatch全部不匹配
*/
List<Integer> integerList5 = Arrays.asList(1, 2, 3, 4, 5);
if (integerList5.stream().noneMatch(i -> i > 3)) {
System.out.println("值都小于3");
}
}
Stream的中间操作得到的结果还是一个Stream,那么如何把一个Stream转换成我们需要的类型呢?比如计算出流中元素的个数、将流装换成集合等。这就需要最终操作(terminal operation)
最终操作会消耗流,产生一个最终结果。也就是说,在最终操作之后,不能再次使用流,也不能在使用任何中间操作,否则将抛出异常:
java.lang.IllegalStateException: stream has already been operated upon or closed
count用来统计流中的元素个数。
/**
* 统计流中元素个数
* 通过使用count方法统计出流中元素个数
*/
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
Long result = integerList.stream().count();
//System.out.println("result = " + result);
通过findFirst方法查找到第一个大于三的元素并打印
/**
* 查找 - findFirst查找第一个
* 通过findFirst方法查找到第一个大于三的元素并打印
*/
List<Integer> integerList2 = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> result2 = integerList2.stream().filter(i -> i > 3).findFirst();
//System.out.println("result2 = " + result2);
通过findAny方法查找到其中一个大于三的元素并打印,因为内部进行优化的原因,当找到第一个满足大于三的元素时就结束,该方法结果和findFirst方法结果一样。提供findAny方法是为了更好的利用并行流,findFirst方法在并行上限制更多
/**
* 查找 - findAny随机查找一个
* 通过findAny方法查找到其中一个大于三的元素并打印,因为内部进行优化的原因,当找到第一个满足大于三的元素时就结束,该方法结果和findFirst方法结果一样。提供findAny方法是为了更好的利用并行流,findFirst方法在并行上限制更多
*/
List<Integer> integerList3 = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> result3 = integerList3.stream().filter(i -> i > 3).findAny();
//System.out.println("result3 = " + result3);
获取流中最小最大值
/**
* 获取流中最小最大值
* 通过min/max获取最小最大值
*/
//Optional<Integer> min = menu.stream().map(Dish::getCalories).min(Integer::compareTo);
//Optional<Integer> max = menu.stream().map(Dish::getCalories).max(Integer::compareTo);
// 也可以写成:
//OptionalInt min = menu.stream().mapToInt(Dish::getCalories).min();
//OptionalInt max = menu.stream().mapToInt(Dish::getCalories).max();
Stream 提供了方法 ‘forEach’ 来迭代流中的每个数据。以下代码片段使用 forEach 输出了10个随机数
/**
* forEach 输出了10个随机数
*/
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);
collect就是一个归约操作,可以接受各种做法作为参数,将流中的元素累积成一个汇总结果
/**
* collect
* collect就是一个归约操作,可以接受各种做法作为参数,将流中的元素累积成一个汇总结果
*/
List<String> strings = Arrays.asList("AAAAA", "BBBB", "CCC", "DD", "E");
List<Integer> collect = strings.stream()
.filter(str -> str.length() <= 3)
.map(String::length)
.sorted()
.limit(2)
.distinct()
.collect(Collectors.toList());
collect.forEach(System.out::println);
最终得到一个List 数组,也就是流最终的归宿。