@SpringBootTest(classes =
Application.class,
webEnvironment =
SpringBootTest.WebEnvironment.RANDOM_PORT)
public class StreamIntroduction {
/*一.Java Stream操作=======*/
//1. 外部迭代-----------------------
/**
* Java 8 之前,在操作Java集合时,
* 我们使用外部迭代。在外部迭代中,
* 我们为每个循环使用for或,或者
* 为集合获取一个迭代器,并按顺
* 序处理集合的元素。下面的代码
* 计算列表中所有奇数的平方和。
* 它使用每个循环访问列表中的每
* 个元素,然后使用if语句过滤奇数。
* 然后计算平方,最后用sum变量
* 存储平方的和。
*/
@Test
public void test00() {
List<Integer> numbers =
Arrays.asList(1, 2, 3, 4, 5);
int sum = 0;
for (int n : numbers) {
if (n % 2 == 1) {
int square = n * n;
sum = sum + square;
}
}
System.out.println(sum);
}
//2. 内部迭代----------------------
/**
* 在上面的代码中,我们没有使用
* loop语句来遍历列表。我们通过
* 流在内部执行循环。对于奇整数
* 的计算,我们使用lambda表达式。
* 我们首先做过滤器, 然后映射,
* 然后减少。
*/
@Test
public void test01() {
List<Integer> numbers =
Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream()
)//过滤(后面会讲到)
.filter(n -> n % 2 == 1
.map(n -> n * n)//映射
//累加
.reduce(0, Integer::sum);
System.out.println(sum);
}
//3.序列-------------------------
/**
* 外部迭代通常意味着顺序代码。
* 顺序代码只能由一个线程执行。
* 流被设计成并行处理元素。
* 下面的代码并行计算列表中奇
* 数的平方和。我们所做的只是
* 将stream()替换为parallelStream()。
*/
@Test
public void test02() {
List<Integer> numbers =
Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.parallelStream()
.filter(n -> n % 2 == 1)
.map(n -> n * n)
.reduce(0, Integer::sum);
System.out.println(sum);
}
//4. 命令式和函数式-----------
/**
* 在命令式编程中,我们不仅控制做
* 什么,而且控制如何做。例如,
* 在使用命令式编程对列表中的整数
* 进行求和时。
* 我们必须决定如何迭代列表中的每
* 个元素。我们可以使用for循环,
* for-each循环,或者我们可以从
* list中获得一个迭代器对象并
* 使用while循环。
* 然后我们还要计算和。在声明式
* 编程中,我们只需要告诉要做什么,
* 系统本身如何处理这部分。
* 集合支持命令式编程,
* 而流支持声明式编程。
* StreamIntroduction API通过
* 使用lambda表达式支持函数式编程。
* 我们想对流元素执行的操作通常是
* 通过传递一个lambda表达式来完成的。
* 流上的操作生成不修改数据源的
* 结果(peek除外)。
*/
//5. 中间操作终端操作-------------
/**
* 流支持两种类型的操作:
* 中间操作(惰性操作):延迟操作
* 在流上调用急于操作之前不会处理
* 元素。指的是操作最终不会产生新的集合。
* 终端操作(即时操作):一个流上的
* 中间操作会产生另一个流。指的是操作
* 会产生新的集合。
* Streams链接操作以创建流管道。
* 在下面的代码中,filter()和map()都是
* 惰性操作。而reduce()是即时操作。
*/
@Test
public void test03() {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.parallelStream()
.filter(n -> n % 2 == 1)
.map(n -> n * n)
.reduce(0, Integer::sum);
System.out.println(sum);
}
/*二.Java Stream API ========*/
/**
* Stream相关的接口和类在java.util包
* 中。AutoCloseable接口来自
* java.lang包。所有Stream接口都
* 继承自BaseStream接口,
* 而BaseStream接口继承自
* AutoCloseable接口。
* AutoCloseable
* |
* +--BaseStream
* |
* +--IntStream
* |
* +--LongStream
* |
* +--DoubleStream
* |
* +--Stream<T>
* 如果Stream使用集合作为其数据源,
* 并且集合不需要关闭。
* 如果Stream基于可关闭的数据源
* (如文件I/O通道),我们可以使用
* try-with-resources语句创建Stream,
* 使其自动关闭。
* 1. BaseStream
* BaseStream接口定义了所有
* Stream通用的所有方法。
* -- Iterator<T> Iterator() 终端操作,
* 返回流的迭代器。
* -- sequential() 中间操作,
* 返回一个串行流。如果流已经
* 是串行,它就返回自己。
* 它将并行流转换为顺序流。
* -- parallel() 中间操作,
* 返回并行流。如果流已经是
* 并行的,它就返回自己。
* 它将并行流转换为顺序流。
* -- boolean isParallel() 如果流
* 是并行的,返回true,否则返回
* false。在调用终端流操作方法
* 之后调用此方法可能会产生不
* 可预测的结果。
* -- unordered() 中间操作,
* 返回流的无序版本。如果流已经
* 是无序的,它将返回自己。
* 2.Stream
* Stream<T>接口表示元素类
* 型为T的流。Stream<Student>
* 表示学生对象流。Stream<T>接口
* 包含filter()、map()、reduce()、
* collect()、max()、min()等方法。
* 在使用基本类型时,我们可以使用
* 三个专门的流接口,即IntStream、
* LongStream和DoubleStream。
* 这些接口提供了处理基本值的方法。
对于其他基本类型,如float、short、
* byte,我们仍然可以使用这三种专用
* 流接口。
* 在下面的代码中,我们将使用stream
* 计算列表中所有奇数的平方和。
* 我们将使用以下步骤进行计算。
* 2.1 创建Stream
* 集合接口中的stream()方法返回
* 一个顺序流。在这种情况下,
* 集合充当数据源。下面的代码创建了
* 一个列表<Integer>,
* 并从列表中获得一个流<Integer>:
* List<Integer> numbersList = Arrays.asList(1, 2, 3, 4, 5);
* Stream<Integer> numbersStream = numbersList.stream();
* 2.2 过滤Stream
* Stream<T> filter()使用指定谓词返回
* true时来保留流中的元素。下面的语句得到了一个奇数流:
* Stream<Integer> oddNumbersStream=
* numbersStream.filter(n -> n % 2 == 1);
* 2.3 映射Stream
* Stream<T> map()使用一个函数映射流
* 中的每个元素并创建一个新的流。
* Stream<Integer> aStream =
* stream.map(n -> n * n);// n = n * n
* 2.4 规约Stream
* reduce(T identity, BinaryOperator<T> accumulator)
* 将流减少为单个值。接受一个初始值和一个二进制运算符<T>的
* 累加器作为参数。使用提供的初始值
* 和关联累积函数对该流的元素执行减少,并返回减少的值。
* int sum = aStream.reduce(0, (n1, n2) -> n1 + n2);
*/
@Test
public void test04() {
List<Integer> numbers =
Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream()
.filter(n -> n % 2 == 1)
.map(n -> n * n)
.reduce(0, Integer::sum);
System.out.println(sum);
}
/**
* 2.5 有序流与无序流
* 流可以是有序的,也可以是
* 无序的。StreamIntroduction API
* 可以将表示有序数据源(如列表或排序集)的
* 有序流转换为无序流。
* 我们还可以通过应用排序中间操
* 作将无序流转换为有序流。
*/
@Test
public void test05() {
List<Integer> numbers = Arrays.asList(3,7,9,3,1,2,1, 2, 3, 4, 5);
numbers.stream()
.filter(n -> n % 2 == 1)
.sorted()
.forEach(System.out::println);
}
}