1. 创建Stream: 一个数据源(如:集合、 数组),获取一个流
2. 中及操作: 一个中间操作链,对数据源的数据进行处理
3. 终止操作(终端操作):一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用。
filter --- 接收Lambda,从流中排除某些元素
limit --- 截断流,使其元素不超过给定数量。
skip(n)--- 跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与limit互补
distinct --- 筛选,通过流所生成元素的hashCode()和equals去除重复元素。
map --- 接收Lambda,将元素转换成其他形式或提取信息.接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素.
flatMap --- 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
sorted(): 自然排序(Comparable)
sorted(Comparator com): 定制排序
import lombok.Data;
import java.util.Objects;
// 员工信息
@Data
public class Employee {
private String name; // 姓名
private Integer age; // 年龄
private Double salary; // 工资
private Status status; // 状态
public enum Status {
FREE,
BUSY,
VOCATION;
}
public Employee() {}
public Employee(String name, Integer age, Double salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
public Employee(String name, Integer age, Double salary, Status status) {
this.name = name;
this.age = age;
this.salary = salary;
this.status = status;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", age=" + age +
", salary=" + salary +
", status=" + status +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
return Objects.equals(name, employee.name) &&
Objects.equals(age, employee.age) &&
Objects.equals(salary, employee.salary);
}
@Override
public int hashCode() {
return Objects.hash(name, age, salary);
}
}
import com.sarj.streetlamp.optional.Employee;
import org.junit.Test;
import java.util.*;
import java.util.stream.Stream;
/**
Stream的三个操作步骤:
1. 创建Stream: 一个数据源(如:集合、 数组),获取一个流
2. 中及操作: 一个中间操作链,对数据源的数据进行处理
3. 终止操作(终端操作):一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用。
创建Stream的常见方式: 详情查看 demo1
中间操作的常用方法:
filter --- 接收Lambda,从流中排除某些元素
limit --- 截断流,使其元素不超过给定数量。
skip(n)--- 跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与limit互补
distinct --- 筛选,通过流所生成元素的hashCode()和equals去除重复元素。
map --- 接收Lambda,将元素转换成其他形式或提取信息.接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素.
flatMap --- 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
sorted(): 自然排序(Comparable)
sorted(Comparator com): 定制排序
*/
public class StreamTest1 {
// 创建Stream的常见方式
@Test
public void demo1() {
// 方式一: 通过Collection系列集合提供的stream() 或 parallelStream()
// stream():获取的是串行流, 串行(可以理解为: 一个一个执行操作动作)
// parallelStream(): 获取的是并行流, 并行(可以理解为:可以同时执行多个操作动作)
List list = new ArrayList<>();
Stream stream1 = list.stream();
Stream stream2 = list.parallelStream();
// 方式二: 通过Arrays中的静态方法stream()获取数组流
String[] strs = new String[2];
Stream stream3 = Arrays.stream(strs);
// 3. 通过Stream类中的静态方法of(String... values): 它可以接收任意数量的参数
Stream stream4 = Stream.of(1, 2, 3);
Stream stream5 = Stream.of(strs);
Stream> stream6 = Stream.of(list);
// 4. 创建无限流
// 迭代
Stream stream7 = Stream.iterate(0, (x) -> x + 2); // seed是起始位置, 从 seed开始, 然后一直执行 x + 2操作
stream7.limit(10).forEach(System.out::println); // limit:相当于中间操作; forEach相当于终止操作(中间操作讲解, 别急,静下心)
// 生成
Stream stream8 = Stream.generate(Math::random);
stream8.limit(5).forEach(System.out::println); // limit:相当于中间操作; forEach相当于终止操作(中间操作讲解, 别急,静下心)
}
// 公用数据
List emps = Arrays.asList(
new Employee("张三", 18, 9999.99, Employee.Status.FREE),
new Employee("李四", 58, 5555.55, Employee.Status.BUSY),
new Employee("王五", 26, 3333.33, Employee.Status.VOCATION),
new Employee("赵六", 36, 6666.66, Employee.Status.FREE),
new Employee("赵六", 36, 6666.66, Employee.Status.FREE),
new Employee("田七", 12, 8888.88, Employee.Status.BUSY)
);
// 中间操作: 不会执行任何操作 - start
/**
* filter测试用例
* filter --- 接收Lambda,从流中排除某些元素
*/
@Test
public void demo2() {
// 外部迭代:list.iterator
// 内部迭代: 迭代操作由StreamAPI完成
System.out.println(" ------ 中间操作之过滤 ----------");
// 1. 创建流
Stream stream1 = emps.stream();
// 2. 中间操作之过滤, 过滤出年龄大于35的员工
Stream stream2 = stream1.filter((e) -> {
System.out.println("过滤...");
return e.getAge() > 35;
}); // 要是没有终止操作,不会打印“中间操作”log。。。
// 3. 当执行终止操作时,会讲一系列中间操作一次性执行, 即"惰性求值"
stream2.forEach(System.out::println);
System.out.println("---- 另一种实现: 建议采用这种方式,看的爽... ------");
// 另一种实现
emps.stream().filter((e) -> {
System.out.println("过滤2....");
return e.getAge() > 35;
}).forEach(System.out::println);
}
/**
* limit、skip、distinct测试用例
* limit --- 截断流,使其元素不超过给定数量。
* skip(n)--- 跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与limit互补
* distinct --- 筛选,通过流所生成元素的hashCode()和equals去除重复元素。
*/
@Test
public void demo3() {
System.out.println("--------- 中间操作之截断流(limit),实现1");
// 1. 创建流
Stream stream1 = emps.stream();
// 2. 中间操作之截断流, 截取一个员工
Stream stream2 = stream1.limit(1);
// 3. 终止操作
stream2.forEach(System.out::println);
System.out.println("--------- 中间操作之截断流(limit),实现2");
emps.stream().limit(1).forEach(System.out::println);
System.out.println("--------- 中间操作之跳过元素(skip),实现1");
// 1. 创建流
Stream stream3 = emps.stream();
// 2. 中间操作之跳过元素, 跳过前两个员工
Stream stream4 = stream3.skip(2);
// 3. 终止操作
stream4.forEach(System.out::println);
System.out.println("--------- 中间操作之跳过元素(skip),实现2");
emps.stream().skip(2).forEach(System.out::println);
System.out.println("--------- 筛选,通过流所生成元素的hashCode()和equals去除重复元素, 实现1");
// 1. 创建流
Stream stream5 = emps.stream();
// 2. 中间操作之筛选,通过流所生成元素的hashCode()和equals去除重复元素
Stream stream6 = stream5.distinct();
// 3. 终止操作
stream6.forEach(System.out::println);
System.out.println("--------- 筛选,通过流所生成元素的hashCode()和equals去除重复元素, 实现2");
emps.stream().distinct().forEach(System.out::println);
}
// filter, limit, skip, distinct联合使用
@Test
public void demo4() {
// 过滤出大于15的员工,然后跳过第一个,再去重复的,最后截取四个员工的信息并输出
System.out.println(" ----- filter, limit, skip, distinct联合使用");
emps.stream().filter((e) -> e.getAge() > 15).skip(1).distinct().limit(4).forEach(System.out::println);
}
/**
* map测试用例:
* map --- 接收Lambda,将元素转换成其他形式或提取信息.接收一个函数作为参数,该函数会被应用到每个元素上,
* 并将其映射成一个新的元素.
*/
@Test
public void demo5() {
List strList = Arrays.asList("aaa", "bbb", "ccc", "ddd");
// 1. 创建流
Stream stream = strList.stream();
// 2. 中间操作, 将列表中的元素都转为大写
Stream stream1 = stream.map((str) -> str.toUpperCase());
// 3. 终止操作
stream1.forEach(System.out::println);
// 等同于上面三步操作
System.out.println(" -------------- 简化代码方式 ------------");
strList.stream().map((str) -> str.toUpperCase()).forEach(System.out::println);
System.out.println("----------------------");
// 1. 创建流
Stream stream2 = emps.stream();
// 2. 中间操作, 只获取员工中的名字这个信息
Stream stream3 = stream2.map(Employee::getName);
stream3.forEach(System.out::println);
// 等同于上面三步操作
System.out.println(" -------------- 简化代码方式 ------------");
emps.stream().map(Employee::getName).forEach(System.out::println);
}
/**
* flatMap测试用例
* flatMap --- 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
*/
@Test
public void demo6() {
List strList = Arrays.asList("aaa", "bbb", "ccc", "ddd");
// 使用map方式
Stream> stream1 = strList.stream().map(StreamTest1::filterCharacter); // {
{a,a,a}, {b,b,b}}
stream1.forEach(sm -> {
sm.forEach(System.out::println);
});
// 使用flatMap方式
Stream stream2 = strList.stream();
Stream stream3 = stream2.flatMap(StreamTest1::filterCharacter); // {a,a,a, b,b,b}
stream3.forEach(System.out::println);
}
public static Stream filterCharacter(String str) {
List list = new ArrayList<>();
for (Character ch : str.toCharArray()) {
list.add(ch);
}
return list.stream();
}
/**
排序之sorted测试用例:
sorted(): 自然排序(Comparable)
sorted(Comparator com): 定制排序
*/
@Test
public void demo7() {
// 以下都写简化代码哈,根据上面的多次分解操作Stream应该都会了哈。
System.out.println("--------- 自然排序 ------------");
List strList = Arrays.asList("ccc", "aaa", "bbb", "ddd");
strList.stream().sorted().forEach(System.out::println); // 自然排序
System.out.println("--------- 自定义排序 ------------");
emps.stream().sorted((e1, e2) -> {
if (e1.getAge().equals(e2.getAge())) { // 当年龄相同时,比较姓名
return e1.getName().compareTo(e2.getName());
}
return e1.getAge().compareTo(e2.getAge());
}).forEach(System.out::println);
}
// 中间操作: 不会执行任何操作 - end
}