Java8 中的 Stream

简介: Java8 中有两大最为重要的改变。第一个是 Lambda 表达式;另外一个则是 Stream API(java.util.stream.*),Stream主要用来操作java中的集合,可以执行复杂的查找、过滤等操作。有点类似使用SQL查询数据库一样,Stream API提供了一种高效且易于使用的处理数据的方式。

image.png

一、 Stream 操作的三个步骤

  • 创建 Stream

一个数据源(如: 集合、数组), 获取一个流。

  • 中间操作

一个中间操作链,对数据源的数据进行处理。

  • 终止操作

一个终止操作,执行中间操作链,并产生结果。

二、如何创建Stream

Java8 中的 Collection 接口被扩展,提供了两个获取流的方法

获取一个串行流

defaultStream<E>stream() {
returnStreamSupport.stream(spliterator(), false);
    }

获取一个并行流

defaultStream<E>parallelStream() {
returnStreamSupport.stream(spliterator(), true);
    }

Java8 中的 Arrays 的静态方法 stream() 可以获取数组流

publicstatic<T>Stream<T>stream(T[] array) {
returnstream(array, 0, array.length);
    }

通过 Stream 类的静态方法 of()获取数组流

publicstatic<T>Stream<T>of(Tt) {
returnStreamSupport.stream(newStreams.StreamBuilderImpl<>(t), false);
}

三、Stream中间操作

多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会 执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值",Stream 的中间操作是不 会有任何结果数据输出的。

Stream 的中间操作在整体上可以分为:筛选与切片、映射、排序。

(一)筛选与切片

1.筛选filter

filter(Predicate p) 接收 Lambda 表达式,从流中排除某些元素

protectedList<Employee>list=Arrays.asList(
newEmployee("Lisa", 18, 9999.99),
newEmployee("Ruby", 38, 5555.55),
newEmployee("Charles", 60, 6666.66),
newEmployee("Vincent", 28, 8888.77),
newEmployee("Quella", 58, 4444.33)
    );
@TestpublicvoidtestFilter() {
Stream<Employee>list2=list.stream().filter(x->x.getAge() >30 );
    }

2.limit()

主要作用为:截断流,使其元素不超过给定数量

list.stream().filter((e) ->e.getAge() >30 ).limit(2).forEach(System.out :: println);

3.skip()

跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素 不足 n 个,则返回一个空流。与 limit(n) 互补。

list.stream().skip(2).forEach(System.out :: println

4.distinct()

去重操作,通过流所生成元素的 hashCode() 和 equals() 去 除重复元素,distinct 需要实体中重写 hashCode()和 equals()方法才 可以使用

list.stream().distinct().forEach(System.out :: println);

(二)映射

1.map

接收一个函数作为参数,该函数会被应用到每个元 素上,并将其映射成一个新的元素。

方法声明

<R>Stream<R>map(Function<?superT, ?extendsR>mapper)

比如把以下集合元素全部转化为大写,然后再输出

List<String>list=Arrays.asList("a", "b", "c", "d");
list.stream().map((e) ->e.toUpperCase()).forEach(System.out::printf)


2.flatMap

接收一个函数作为参数,将流中的每个值都换成另 一个流,然后把所有流连接成一个流。

@TestpublicvoidtestFlatMap(){
List<Data2>listOfData2=Arrays.asList(
newData2(10501, "JOE"  , "Type1"),
newData2(10603, "SAL"  , "Type5"),
newData2(40514, "PETER", "Type4"),
newData2(59562, "JIM"  , "Type2"),
newData2(29415, "BOB"  , "Type1"),
newData2(61812, "JOE"  , "Type9"),
newData2(98432, "JOE"  , "Type7"),
newData2(62556, "JEFF" , "Type1"),
newData2(10599, "TOM"  , "Type4")
        );
List<Data1>listOfData1=Arrays.asList(
newData1(10501, "JOE"    ,3000000),
newData1(10603, "SAL"    ,6225000),
newData1(40514, "PETER"  ,2005000),
newData1(59562, "JIM"    ,3000000),
newData1(29415, "BOB"    ,3000000)
        );
List<OutputData>result=listOfData1.stream()
                .flatMap(x->listOfData2.stream()
                        .filter(y->x.getId() ==y.getId())
                        .map(y->newOutputData(y.getId(), x.getName(), y.getType(), x.getAmount())))
                .collect(Collectors.toList());
System.out.println(result);
    }

(三)排序

1.sorted()

产生一个新流,其中按自然顺序排序

List<Employee>persons=list.stream().sorted().collect(Collectors.toList());

2.sorted(Comparator comp)

产生一个新流,其中按自定义的比较器顺序排序

List<Employee>persons1=list.stream().sorted((e1, e2) -> {
if (e1.getAge() ==e2.getAge()) {
return0;
} elseif (e1.getAge() >e2.getAge()) {
return1;
} else {
return-1;
}
}).collect(Collectors.toList());

四、终止操作

终端操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如: List、 Integer、 Double、String 、甚至是void

1.allMatch(Predicate p)

检查是否匹配所有元素,只有所有的元素都匹配条件时,allMatch()方法才会返回 true

booleanmatch=employees.stream().allMatch((e) ->Employee.Stauts.SLEEPING.equals(e.getStauts()));

2.anyMatch()

使用 anyMatch()方法时,只要有任意一个元素符合条件,anyMatch()方法就会返回 true

booleanmatch=employees.stream().anyMatch((e) ->Employee.Stauts.SLEEPING.equals(e.getStauts()))

3.findFirst()

findFirst()方法表示返回流中的第一个元素。

Optional<Employee>op=employees.stream().sorted((e1, e2) ->Double.compare(e1.getSalary(), e2.getSalary())).findFirst();

4.count()

count()方法表示返回流中元素总数。

longcount=employees.stream().count();

5.forEach()

forEach()方法表示内部迭代(使用 Collection 接口需要用户去做迭代,称为外部迭代。相反, Stream API 使用内部迭代)。其在 Stream 接口内部的定义如下所示。

voidforEach(Consumer<?superT>action);
employees.stream().forEach(System.out::println);

五、Reduce

reduce()是把流中所有元素结合起来,生成一个新的值。reduce()方法在 Stream 接口中的定义如下所示

Treduce(Tidentity, BinaryOperator<T>accumulator);
Optional<T>reduce(BinaryOperator<T>accumulator); <U>Ureduce(Uidentity, BiFunction<U, ?superT, U>accumulator, BinaryOperator<U>combiner);
List<Integer>list=Arrays.asList(1,2,3,4,5,6,7,8,9,10);
Integersum=list.stream().reduce(0, (x, y) ->x+y);
System.out.println(sum);

六、收集

collect(Collector c) 将流转换为其他形式。接收一个 Collector 接口的实现,用于给 Stream 中元 素做汇总的方法

Collector 接口中方法的实现决定了如何对流执行收集操作(如收集到 List、Set、Map)。 Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例, 具体方法与实例如下表:

方法

返回值

方法作用

使用示例

toList

List

List 把流中元素收集到 List

List employees= list.stream().collect(Collectors.toList());

toSet

Set

把流中元素收集到 Set

Set employees= list.stream().collect(Collectors.toSet());

toCollection

Collection

把流中元素收集到创建的集合

Collection employees=list.stream().collect(Collectors.toCollection(Arra yList::new));

counting

Long

计算流中元素的个数

long count = list.stream().collect(Collectors.counting());

joining

String

连接流中每个字符串

String str= list.stream().map(Employee::getName).collect(Collectors.jo ining());

maxBy

Optional

根据比较器选择最大值

Optionalmax= list.stream().collect(Collectors.maxBy(comparingInt(Em ployee::getSalary)));

minBy

Optional

根据比较器选择最小值

Optional min = list.stream().collect(Collectors.minBy(comparingInt(E mployee::getSalary)));

reducing

归约产生的类型

从一个作为累加器的初始值 开始,利用 BinaryO perator 与 流中元素逐个结合,从而归 约成单个 值

int total=list.stream().collect(Collectors.reducing(0, Employee::getSala r, Integer::sum));

groupingBy

Map<K,List>

根据某属性值对流分组,属 性为 K,结果为

Map map= list.stream() .collect(Collectors.groupin gBy(Employee::getStatus));

相关文章
|
4月前
|
安全 Java API
告别繁琐编码,拥抱Java 8新特性:Stream API与Optional类助你高效编程,成就卓越开发者!
【8月更文挑战第29天】Java 8为开发者引入了多项新特性,其中Stream API和Optional类尤其值得关注。Stream API对集合操作进行了高级抽象,支持声明式的数据处理,避免了显式循环代码的编写;而Optional类则作为非空值的容器,有效减少了空指针异常的风险。通过几个实战示例,我们展示了如何利用Stream API进行过滤与转换操作,以及如何借助Optional类安全地处理可能为null的数据,从而使代码更加简洁和健壮。
123 0
|
1月前
|
Java API 数据处理
探索Java中的Lambda表达式与Stream API
【10月更文挑战第22天】 在Java编程中,Lambda表达式和Stream API是两个强大的功能,它们极大地简化了代码的编写和提高了开发效率。本文将深入探讨这两个概念的基本用法、优势以及在实际项目中的应用案例,帮助读者更好地理解和运用这些现代Java特性。
|
2月前
|
Java 流计算
Flink-03 Flink Java 3分钟上手 Stream 给 Flink-02 DataStreamSource Socket写一个测试的工具!
Flink-03 Flink Java 3分钟上手 Stream 给 Flink-02 DataStreamSource Socket写一个测试的工具!
44 1
Flink-03 Flink Java 3分钟上手 Stream 给 Flink-02 DataStreamSource Socket写一个测试的工具!
|
2月前
|
Java Shell 流计算
Flink-02 Flink Java 3分钟上手 Stream SingleOutputStreamOpe ExecutionEnvironment DataSet FlatMapFunction
Flink-02 Flink Java 3分钟上手 Stream SingleOutputStreamOpe ExecutionEnvironment DataSet FlatMapFunction
25 1
Flink-02 Flink Java 3分钟上手 Stream SingleOutputStreamOpe ExecutionEnvironment DataSet FlatMapFunction
|
3月前
|
存储 Java API
Java——Stream流详解
Stream流是JDK 8引入的概念,用于高效处理集合或数组数据。其API支持声明式编程,操作分为中间操作和终端操作。中间操作包括过滤、映射、排序等,可链式调用;终端操作则完成数据处理,如遍历、收集等。Stream流简化了集合与数组的操作,提升了代码的简洁性
142 11
Java——Stream流详解
|
2月前
|
存储 Java 数据处理
Flink-01 介绍Flink Java 3分钟上手 HelloWorld 和 Stream ExecutionEnvironment DataSet FlatMapFunction
Flink-01 介绍Flink Java 3分钟上手 HelloWorld 和 Stream ExecutionEnvironment DataSet FlatMapFunction
37 1
|
3月前
|
Java API C++
Java 8 Stream Api 中的 peek 操作
本文介绍了Java中`Stream`的`peek`操作,该操作通过`Consumer&lt;T&gt;`函数消费流中的每个元素,但不改变元素类型。文章详细解释了`Consumer&lt;T&gt;`接口及其使用场景,并通过示例代码展示了`peek`操作的应用。此外,还对比了`peek`与`map`的区别,帮助读者更好地理解这两种操作的不同用途。作者为码农小胖哥,原文发布于稀土掘金。
128 9
Java 8 Stream Api 中的 peek 操作
|
3月前
|
Java C# Swift
Java Stream中peek和map不为人知的秘密
本文通过一个Java Stream中的示例,探讨了`peek`方法在流式处理中的应用及其潜在问题。首先介绍了`peek`的基本定义与使用,并通过代码展示了其如何在流中对每个元素进行操作而不返回结果。接着讨论了`peek`作为中间操作的懒执行特性,强调了如果没有终端操作则不会执行的问题。文章指出,在某些情况下使用`peek`可能比`map`更简洁,但也需注意其懒执行带来的影响。
163 2
Java Stream中peek和map不为人知的秘密
|
3月前
|
Java 大数据 API
Java 流(Stream)、文件(File)和IO的区别
Java中的流(Stream)、文件(File)和输入/输出(I/O)是处理数据的关键概念。`File`类用于基本文件操作,如创建、删除和检查文件;流则提供了数据读写的抽象机制,适用于文件、内存和网络等多种数据源;I/O涵盖更广泛的输入输出操作,包括文件I/O、网络通信等,并支持异常处理和缓冲等功能。实际开发中,这三者常结合使用,以实现高效的数据处理。例如,`File`用于管理文件路径,`Stream`用于读写数据,I/O则处理复杂的输入输出需求。
220 12
|
3月前
|
Java 程序员 API
Java 8新特性之Lambda表达式与Stream API的探索
【9月更文挑战第24天】本文将深入浅出地介绍Java 8中的重要新特性——Lambda表达式和Stream API,通过实例解析其语法、用法及背后的设计哲学。我们将一探究竟,看看这些新特性如何让Java代码变得更加简洁、易读且富有表现力,同时提升程序的性能和开发效率。