Java 8中的新特性Stream API 优点:
1. 便于并行
2. 并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。 相比于串行的流,并行的流可以很大程度上提高程序的执行效率。
3. Java 8中将并行进行了优化,我们可以很容易的对数据进行并行操作。Stream API可以声明性地 通过parallel()与sequential()在并行流与顺序流之间进行切换。
1.强大的Stream API
-
Java8 中有两个最为重要的改变。第一个是Lambda表达式;另外一个则是Stream API
-
Stream API (java.util.stream) 把真正的函数式编程风格引入到Java中。这是目前
为止对Java类库最好的补充,因为Stream API可以极大提供Java程序员的生产力,让程序员写出高效、干净、简洁的代码 -
Stream 是Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、
过滤和映射数据等操作。使用Stream API来并行执行操作,就类似于使用API使用SQL执行的数据库查询。
也可以使用Stream API来并行执行操作。简言之,Stream API提供了一种高效且易于使用的处理数据的方式。
1.1. 为什么要使用Stream API ?
-
实际开发中,项目中多数数据源都来自Mysql、Qracle等。但现在数据源可以更多了,有MongDB, Radis等,而这些
NoSQL的数据就需要Java层面去处理。 -
Stream和Collection集合的区别:Collection是一种静态的内存数据结构,而Stream是有关计算的。
前者是主要面向内存,存储在内存中,后者主要是面向CPU,通过CPU实现计算。
1.2. 什么是Stream
-
Stream 就是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
-
“集合讲的是数据,Stream讲的是计算”
1.3. 注意:
- Stream自己不会存储元素。
- Stream不会改变源对象。相反,他们会返回一个持有结果的新的Stream
- Stream操作时延迟执行的。这意味着他们会等到需要结果的时候才执行。
2. 操作 Stream 的三个步骤
- 创建Stream:一个数据源(如:集合、数组),获取一个流
- 中间操作:一个中间操作链,对数据源的数据进行处理
- 终止操作(终端操作):一旦执行终止操作,就执行中间操作链,并产生结果。之后不会再被使用。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NVBpBnBG-1649750340510)(README.assert/img_1.png)]
2.1 创建Stream的四种方式
1. 创建Stream方式一:通过集合
Java8 中的 Collection 接口被扩展,提供了两个获取流的方法:
default Stream<E> stream()
: 返回一个顺序流defalut Stream<E> parallelStream()
: 返回一个并行流- 代码测试:
// 创建Stream方式一:通过集合 @Test public void test01(){ List<Employee> employees = EmployeeData.getEmployees(); // default Stream<E> stream() : 返回一个顺序流 Stream<Employee> stream = employees.stream(); Object[] employeeps = stream.toArray(); // 将stream流转换为Object数组 long t1 = System.currentTimeMillis(); for (Object o : employeeps) { System.out.println(o); } long t2 = System.currentTimeMillis(); System.out.println(t2 - t1); // 17 ms System.out.println("**************************\n"); // default Stream<E> parallelStream() : 返回一个并行流 Stream<Employee> employeeStream = employees.parallelStream(); Object[] objects = employeeStream.toArray(); t1 = System.currentTimeMillis(); for (Object o : objects) { System.out.println(o); } System.out.println(System.currentTimeMillis() - t1); // 0 ms }
2. 创建Stream方式二:通过数组
Java8中的Arrays的静态方法 stream() 可以获取数组流
static <T> Stream<T> stream(T[] array)
: 返回一个流
重载形式,能够处理对应基本类型的数组:
public static IntStream stream(int[] array)
public static LongStream stream(long[] array)
public static DoubleStream stream(double[] array)
- 代码测试:
// 创建Stream方式二:通过数组 @Test public void test02() { // 调用Arrays类的 static <T> stream<T> stream(int[] array):返回一个流 int[] arr = new int[] { 1,2,3,4,5,6}; IntStream stream = Arrays.stream(arr); System.out.println(stream.sum()); // 21 Employee e1 = new Employee(1, "jack"); Employee e2 = new Employee(2, "lisi"); Employee[] arr2 = new Employee[]{ e1, e2}; Stream<Employee> stream2 = Arrays.stream(arr2); System.out.println(stream2.toString()); }
3. 创建Stream方式三:通过Stream的of()
- 可以调用Stream类静态方法of(), 通过显式值创建一个流。它可以接收任意数量的参数。
public static<T> Stream<T> of(T... values)
: 返回一个流- 代码测试:
// 创建Stream方式三:通过Stream的of() @Test public void test03() { Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5, 6); }
4. 创建Stream方式四:创建无限流
可以使用静态方法 Stream.iterate() 和 Stream.generate()创建无限流
- 迭代:
public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
- 生成:
public static<T> Stream<T> generate(Supplier<T> s)
- 代码测试:
// 创建Stream方式四:创建无限流 public void test04() { // 1. 迭代Stream.iterate(),遍历前10个偶数 Stream.iterate(0, t -> t + 2).limit(10).forEach(System.out::println); // 2. 使用生产函数来产生10个随机数 Stream.generate(Math::random).limit(10).forEach(System.out::println); }
2.2 Stream的中间操作
多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!
而在终止操作时一次性全部处理,称为“惰性求值”。
1. 筛选与切片
方法 | 描述 |
---|---|
filter(Predicate p) | 接口Lambda,从流中排出某些元素 |
distinct() | 筛选,通过流所生成元素的hashCode()和equals()去除重复元素 |
limit(long maxSize) | 截断流,使其元素不超过给定数量 |
skip(long n) | 跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与limit(n)互补 |
- 代码测试:
package StreamAPITest;
import MethodReferenceTest.Employee;
import MethodReferenceTest.EmployeeData;
import org.junit.Test;
import java.util.List;
import java.util.stream.Stream;
/**
* @ClassName: StreamAPITest2
* @Description: Java - Stream API的中间操作
* @author: zhilx
* @version: v1.0
* @data: 2022/4/12 9:15
* @node: 测试Stream的中间操作:
*
*/
public class StreamAPITest2 {
// 1. 筛选与切片
@Test
public void test01() {
List<Employee> list = EmployeeData.getEmployees();
System.out.println("list中元素的数量:" + list.size());
/**
* note:对流进行终止操作后,该流就被关闭,相等于Iterator的调用,关闭后必须创新创建或打开才可以继续使用。
*/
// filter(Predicate p) : 接口Lambda,从流中排出某些元素
// 练习:查询员工表中年龄小于45的员工信息
System.out.println("-----打印表中年龄大于45的CEO的数量-----");
Stream<Employee> stream = list.stream();
stream.filter(e -> e.getAge() > 45).forEach(System.out::println);
// note: forEach()表示Stream的终止操作,当调用该条件时已经将Stream关闭,因此后面的流无法指向相应的操作
// 如果想要执行,则必须重新创建Stream流
System.out.println("\n-----截断表中的前5个元素-----");
// limit(long maxSize) : 截断流,使其元素不超过给定数量
list.stream().limit(5).forEach(System.out::println);
System.