Stream流是JDK8新增的成员,允许以声明性方式处理数据集合,可以把Stream流看作是遍历数据集合的一个高级迭代器。Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找/筛选/过滤、排序、聚合和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。
对于简单操作,比如最简单的遍历,Stream串行API性能明显差于显示迭代,但并行的Stream API能够发挥多核特性。
对于复杂操作,Stream串行API性能可以和手动实现的效果匹敌,在并行执行时Stream API效果远超手动实现。
使用Stream API能够写出更短的代码。
尽可能的使用Stream API也另外一个优势,那就是只要Java Stream类库做了升级优化,代码不用做任何修改就能享受到升级带来的好处。
for本来就是比较底层的操作,性能自然很高。stream的优势是并行处理。数据量越大,stream的优势越明显,数据量小,肯定是for循环性能最好。
从支持数据处理操作的源生成元素序列.数据源可以是集合,数组或IO资源。
从操作角度来看,流与集合是不同的. 流不存储数据值; 流的目的是处理数据,它是关于算法与计算的。
如果把集合作为流的数据源,创建流时不会导致数据流动; 如果流的终止操作需要值时,流会从集合中获取值; 流只使用一次。
流中心思想是延迟计算,流直到需要时才计算值。
List<String> list = Arrays.asList("a", "b", "c");
// 创建一个顺序流
Stream<String> stream = list.stream();
// 创建一个并行流
Stream<String> parallelStream = list.parallelStream();
int[] array={1,3,5,6,8};
IntStream stream = Arrays.stream(array);
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);
Stream<Integer> stream = Stream.iterate(0, n -> n + 2).limit(5);
stream2.forEach(System.out::println);
Stream<Double> stream = Stream.generate(Math::random).limit(5);
stream3.forEach(System.out::println);
通过Stream的of方法生成流,通过Stream的empty方法可以生成一个空流.
iterate方法接受两个参数,第一个为初始化值,第二个为进行的函数操作,因为iterator生成的流为无限流,通过limit方法对流进行了截断,只生成5个偶数。
generate方法接受一个参数,方法参数类型为Supplier ,由它为流提供值。generate生成的流也是无限流,因此通过limit对流进行了截断,生成5个随机数。
Stream<String> lines = Files.lines(Paths.get("data.txt"), Charset.defaultCharset());
通过Files.line方法得到一个流,并且得到的每个流是给定文件中的一行.
stream和 parallelStream的简单区分:stream是顺序流,由主线程按顺序对流执行操作,而 parallelStream是并行流,内部以多线程并行执行的方式对流进行操作,但前提是流中的数据处理没有顺序要求。例如筛选集合中的奇数,两者的处理不同之处:
一个流可以后面跟随零个或多个中间操作。其目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用。这类操作都是惰性化的,仅仅调用到这类方法,并没有真正开始流的遍历,真正的遍历需等到终端操作时,常见的中间操作有下面即将介绍的 filter、map 等。
一个流有且只能有一个终端操作,当这个操作执行后,流就被关闭了,无法再被操作,因此一个流只能被遍历一次,若想在遍历需要通过源数据在生成流。终端操作的执行,才会真正开始流的遍历。如下面即将介绍的 count、collect 等。
通过使用filter方法进行条件筛选,filter的方法参数为一个条件(过滤保留函数返回值为 true 的元素)。
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5, 6);
Stream<Integer> stream = integerList.stream().filter(i -> i > 3);
结果为:4,5,6
通过distinct方法快速去除重复的元素。
List<Integer> integerList = Arrays.asList(1, 1, 2, 3, 4, 5);
Stream<Integer> stream = integerList.stream().distinct();
结果为:1,2,3,4,5
通过limit方法指定返回流的个数,limit的参数值必须 >=0,否则将会抛出异常。
List<Integer> integerList = Arrays.asList(1, 1, 2, 3, 4, 5);
Stream<Integer> stream = integerList.stream().limit(3);
结果为: 1,1,2
List<Integer> integerList = Arrays.asList(1, 1, 2, 3, 4, 5);
Stream<Integer> stream = integerList.stream().skip(2);
结果为: 2,3,4,5
skip的参数值必须>=0,否则将会抛出异常。
流映射就是将接受的元素映射成另外一个元素。
List<String> stringList = Arrays.asList("Java 8", "Lambdas", "In", "Action");
List<Integer> collect = stringList.stream()
.map(String::length)
.collect(Collectors.toList());
结果为:[6, 7, 2, 6]
通过map方法可以完成映射,该例子完成中 String -> Integer 的映射。
将一个流中的每个值都转换为另一个流,然后把所有流连接成一个流.
List<String> wordList = Arrays.asList("Java 8", "Lambdas", "In", "Action");
List<String> strList = wordList.stream()
.map(w -> w.split(" "))
.flatMap(Arrays::stream)
.distinct()
.collect(Collectors.toList());
结果为:[Java, 8, Lambdas, In, Action]
map(w -> w.split(" ")) 的返回值为 Stream
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
if (integerList.stream().allMatch(i -> i > 3)) {
System.out.println("所有元素值都大于3");
} else {
System.out.println("并非所有元素值都大于3");
}
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
if (integerList.stream().anyMatch(i -> i > 3)) {
System.out.println("存在值大于3的元素");
} else {
System.out.println("不存在值大于3的元素");
}
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
if (integerList.stream().noneMatch(i -> i > 3)) {
System.out.println("值都小于3的元素");
} else {
System.out.println("值不都小于3的元素");
}
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
Long result = integerList.stream().count();
结果为:5
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> result = integerList.stream().filter(i -> i > 3).findFirst();
System.out.println(result.orElse(-1));
结果为:4
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> result = integerList.stream().filter(i -> i > 3).findAny();
System.out.println(result.orElse(-1));
结果为:4
提供findAny方法是为了更好的利用并行流,findFirst方法在并行上限制更多
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
int sum = integerList.stream()
.reduce(0, Integer::sum);
结果为:15
reduce接受两个参数,一个初始值这里是0,一个 BinaryOperatoraccumulator
来将两个元素结合起来产生一个新值,另外reduce方法还有一个没有初始化值的重载方法。
List<String> stringList = Arrays.asList("Java 8", "Lambdas", "In", "Action");
Optional<Integer> min = stringList.stream()
.map(String::length)
.reduce(Integer::min);
Optional<Integer> max = stringList.stream()
.map(String::length)
.reduce(Integer::max);
结果为:Optional[2] 和 Optional[7]
写法一:
List<String> stringList = Arrays.asList("Java 8", "Lambdas", "In", "Action");
Optional<Integer> min = stringList.stream()
.map(String::length)
.min(Integer::compareTo);
Optional<Integer> max = stringList.stream()
.map(String::length)
.max(Integer::compareTo);
写法二:
List<String> stringList = Arrays.asList("Java 8", "Lambdas", "In", "Action");
OptionalInt
min = stringList.stream()
.mapToInt(String::length)
.min();
OptionalInt
max = stringList.stream()
.mapToInt(String::length)
.max();
写法三:
List<String> stringList = Arrays.asList("Java 8", "Lambdas", "In", "Action");
Optional<Integer> min = stringList.stream()
.map(String::length)
.reduce(Integer::min);
Optional<Integer> max = stringList.stream()
.map(String::length)
.reduce(Integer::max);
结果为:Optional[2] 和 Optional[7]
sum(推荐)
List<String> stringList = Arrays.asList("Java 8", "Lambdas", "In", "Action");
int sum = stringList.stream()
.mapToInt(String::length)
.sum();
summingInt
如果数据类型为double、long,则通过summingDouble、summingLong方法进行求和。
List<String> stringList = Arrays.asList("Java 8", "Lambdas", "In", "Action");
int sum = stringList.stream()
.collect(summingInt(String::length));
reduce
List<String> stringList = Arrays.asList("Java 8", "Lambdas", "In", "Action");
int sum = stringList.stream()
.map(String::length)
.reduce(0, Integer::sum);
/**
* 求Integer集合的元素之和、乘积和最大值
*
*/
List<Integer> list = Arrays.asList(1, 2, 3, 4);
//求和
Optional<Integer> reduce = list.stream().reduce((x,y) -> x+ y);
System.out.println("求和:"+reduce);
//求积
Optional<Integer> reduce2 = list.stream().reduce((x,y) -> x * y);
System.out.println("求积:"+reduce2);
//求最大值
Optional<Integer> reduce3 = list.stream().reduce((x,y) -> x>y?x:y);
System.out.println("求最大值:"+reduce3);
/*
* 求所有员工的工资之和和最高工资
*/
Optional<Integer> reduce = personList.stream().map(Person :: getSalary).reduce(Integer::sum);
Optional<Integer> reduce2 = personList.stream().map(Person :: getSalary).reduce(Integer::max);
System.out.println("工资之和:"+reduce);
System.out.println("最高工资:"+reduce2);
求和、求最大值、最小值的时候,对于相同操作有不同的方法可以选择执行。可以选择collect、reduce、min/max/sum方法,推荐使用min、max、sum方法。因为它最简洁易读,同时通过mapToInt将对象流转换为数值流,避免了装箱和拆箱操作
averagingInt、 averagingLong、 averagingDouble
List<String> stringList = Arrays.asList("Java 8", "Lambdas", "In", "Action");
double average = stringList.stream()
.collect(averagingInt(String::length));
List<String> stringList = Arrays.asList("Java 8", "Lambdas", "In", "Action");
IntSummaryStatistics intSummaryStatistics = stringList.stream()
.collect(summarizingInt(String::length));
double average = intSummaryStatistics.getAverage(); // 获取平均值
int min = intSummaryStatistics.getMin(); // 获取最小值
int max = intSummaryStatistics.getMax(); // 获取最大值
long sum = intSummaryStatistics.getSum(); // 获取总和
如果数据类型为double、long,则通过summarizingDouble、summarizingLong方法
List<String> stringList = Arrays.asList("Java 8", "Lambdas", "In", "Action");
stringList.stream().forEach(System.out::println);
List<String> stringList = Arrays.asList("Java 8", "Lambdas", "In", "Action");
List<Integer> intList = stringList.stream()
.map(String::length)
.collect(toList());
Set<Integer> intSet = stringList.stream()
.map(String::length)
.collect(toSet());
等价于
List<Integer> intList = new ArrayList<>();
Set<Integer> intSet = new HashSet<>();
for (String item : stringList) {
intList.add(item.length());
intSet.add(item.length());
}
通过遍历和返回集合的使用发现流只是把原来的外部迭代放到了内部进行,这也是流的主要特点之一。内部迭代可以减少好多代码量。
List<String> stringList = Arrays.asList("Java 8", "Lambdas", "In", "Action");
String result = stringList.stream()
.map(String::toLowerCase)
.collect(Collectors.joining("-"));
结果为:java 8-lambdas-in-action
List<String> stringList = Arrays.asList("Java 8", "Lambdas", "In", "Action");
Map<Integer, List<String>> collect = stringList.stream().collect(groupingBy(String::length));
通过嵌套使用groupingBy进行多级分类
List<String> stringList = Arrays.asList("Java 12", "Lambdas", "In", "Action");
Map<Integer, Map<Integer, List<String>>> collect = stringList.stream()
.collect(groupingBy(
String::length,
groupingBy(String::hashCode)
));
结果为:
{2={2373=[In]}, 6={1955883606=[Action]}, 7={1611513196=[Lambdas], -155279169=[Java 12]}}
List<String> stringList = Arrays.asList("Java 12", "Lambdas", "In", "Action");
Map<Integer, Map<String, List<String>>> collect = stringList.stream()
.collect(groupingBy(
String::length,
groupingBy(item -> {
if (item.length() <= 2) {
return "level1";
} else if (item.length() <= 6) {
return "level2";
} else {
return "level3";
}
})
));
结果为:{2={level1=[In]}, 6={level2=[Action]}, 7={level3=[Java 12, Lambdas]}}
分区是特殊的分组,它分类依据是true和false,所以返回的结果最多可以分为两组。
List<String> stringList = Arrays.asList("Java 12", "Lambdas", "In", "Action");
Map<Boolean, List<String>> collect = stringList.stream().collect(partitioningBy(String::isEmpty));
结果为:{false=[Java 12, Lambdas, In, Action], true=[]}
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
Map<Boolean, List<Integer>> result = integerList.stream().collect(partitioningBy(i -> i < 3));
结果为:{false=[3, 4, 5], true=[1, 2]}