Stream流 - Java 8 新特性
Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。
Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。
Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。
这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。
元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。
流是从支持数据处理操作的源生成的元素序列,源可以是数组、文件、集合、函数。流不是集合元素,它不是数据结构并不保存数据,它的主要目的在于计算。
①Stream 自己不会存储元素。
②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
生成流
- stream() − 为集合创建串行流。
- parallelStream() − 为集合创建并行流。
生成流的方式主要有五种:
1.通过集合生成
List<Integer> lists = Arrays.asList(1, 2, 3, 4, 5, 6);
//返回一个顺序流
Stream<Integer> stream = lists.stream();
//返回一个并行流
Stream<Integer> stream2 = lists.parallelStream();
2.通过数组生成
int[] intArr = {1, 2, 3, 4, 5, 6};
IntStream stream = Arrays.stream(intArr);
通过Arrays.stream方法生成的流是数值流【即IntStream】而不是 Stream。补充一点使用数值流可以避免计算过程中拆箱装箱,提高性能。
Stream API提供了mapToInt、mapToDouble、mapToLong三种方式将对象流【即Stream 】转换成对应的数值流,同时提供了boxed方法将数值流转换为对象流.
3.通过值生成
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);
4.通过文件生成
Stream<String> lines = Files.lines(Paths.get("data.txt"), Charset.defaultCharset());
5.通过函数生成
iterator
Stream<Integer> stream = Stream.iterate(0, n -> n + 2).limit(5);
iterate方法接受两个参数,第一个为初始化值,第二个为进行的函数操作,因为iterator生成的流为无限流,通过limit方法对流进行了截断,只生成5个偶数。
generator
Stream<Double> stream = Stream.generate(Math::random).limit(5);
generate方法接受一个参数,方法参数类型为Supplier ,由它为流提供值。generate生成的流也是无限流,因此通过limit对流进行了截断。
流的操作、使用
中间操作
filter
筛选,保留结果为true的元素
List<Integer> lists = Arrays.asList(1, 2, 3, 4, 5, 6);
Stream<Integer> stream = lists.stream().filter(i -> i > 3);//输出 4 5 6
distinct
去重
List<Integer> lists = Arrays.asList(1, 1, 3, 5, 5, 6);
Stream<Integer> stream = lists.stream().filter(i -> i > 3);//输出 1 3 5 6
limit
指定返回流的个数,必须>=0,否则抛出异常
List<Integer> lists = Arrays.asList(1, 1, 3, 5, 5, 6);
Stream<Integer> stream = lists.stream().filter(i -> i > 3).limit(2);//输出 1 3
skip
跳过流元素
List<Integer> lists = Arrays.asList(1, 1, 3, 5, 5, 6);
Stream<Integer> stream = lists.stream().filter(i -> i > 3).skip(2);//输出 5 6
map
流映射:将接受的元素映射成另外一个元素
List<String> stringList = Arrays.asList("Java 8", "qingchen", "pay", "Action");
List<Integer> collect = stringList.stream()
.map(String::length)
.collect(Collectors.toList());//输出 6 8 3 6
flatMap
流转换:将一个流中的每个值都转换为另一个流.
List<String> stringList = Arrays.asList("杰哥,不要啊", "忽略", "沈阳大街", "老八,秘制小汉堡");
List<String> collect = stringList.stream()
.map(s->s.split(","))
.flatMap(Arrays::stream)
.collect(Collectors.toList());
collect.forEach(System.out::println);
//输出:杰哥 不要啊 忽略 沈阳大街 老八 秘制小汉堡
allMatch
匹配所有元素
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");
}
anyMatch
匹配其中一个
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的元素");
}
noneMatch
全部不匹配
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的元素");
}
终端操作
count
统计元素个数
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
Long result = integerList.stream().count(); // 5
findFirst
查找第一个
Stream<Integer> valueStream = Stream.of(1,2,3,4,5,6,7);
Optional<Integer> result = valueStream.filter(i -> i > 3).findFirst();// 4
findAny
随机查找一个
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));
通过findAny方法查找到其中一个大于三的元素并打印,因为内部进行优化的原因,当找到第一个满足大于三的元素时就结束,该方法结果和findFirst方法结果一样。提供findAny方法是为了更好的利用并行流,findFirst方法在并行上限制更多
reduce
组合元素
求和
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
int sum = integerList.stream().reduce(0, Integer::sum);
获取最大、小值
List<String> stringList = Arrays.asList("Java 8", "QINGCEHN", "In", "Action");
Optional<Integer> min = stringList.stream()
.map(String::length)
.reduce(Integer::min);//2
Optional<Integer> max = stringList.stream()
.map(String::length)
.reduce(Integer::max);//8
min/max
获取最大、小值
List<String> stringList = Arrays.asList("Java 8", "QINGCEHN", "In", "Action");
Optional<Integer> min = stringList.stream()
.map(String::length)
.min();//2
Optional<Integer> max = stringList.stream()
.map(String::length)
.max(Interger::compareTo);//8
sum
int sum = stringList.stream().mapToInt(String::length).sum();
如果数据类型为double、long,则通过summingDouble、summingLong方法进行求和。
int sum = stringList.stream()
.collect(summingInt(String::length));
foreach
遍历
stream().forEach(System.out::println);
collect
返回集合
List<Integer> intList = stringList.stream()
.map(String::length)
.collect(toList());
Set<Integer> intSet = stringList.stream()
.map(String::length)
.collect(toSet());
joining
拼接流中的元素
List<String> stringList = Arrays.asList("杰哥", "不要啊", "你干嘛", "我舅是太阳");
String result = stringList.stream()
.map(String::toLowerCase)
.collect(Collectors.joining("-"));//输出:杰哥-不要啊-你干嘛-我舅是太阳