在 Java 8 中,得益于 Lambda 所带来的函数式编程, 引入了一个全新的 Stream 流概念。
目的:用于简化集合和数组操作的 API。
Stream流体验
需求:
- 创建一个集合,存储多个字符串元素
- 把集合中所有以”张”开头的元素存储到一个新的集合
- 把”张”开头的集合中的长度为3的元素存储到一个新的集合
- 遍历上一步得到的集合中的元素输出。
```java
List
names = new ArrayList<>();
@BeforeEach public void array() { Collections.addAll(names, “张三丰”, “张无忌”, “周芷若”, “赵敏”, “张强”); }
@Test public void old() { System.out.println(names);
// 1、从集合中找出姓张的放到新集合List<String> zhangList = new ArrayList<>();for (String name : names) {if (name.startsWith("张")) {zhangList.add(name);}}System.out.println(zhangList);// 2、找名称长度是3的姓名List<String> zhangThreeList = new ArrayList<>();for (String name : zhangList) {if (name.length() == 3) {zhangThreeList.add(name);}}System.out.println(zhangThreeList);
}
// stream 流方式 @Test public void stream() { names.stream().filter(s -> s.startsWith(“张”)).filter(s -> s.length() == 3).forEach(System.out::println); }
<a name="Y4zOe"></a>
## Stream流的获取
Stream 流的三类方法
- 获取 Stream 流:创建一条流水线,并把数据放到流水线上准备进行操作
- 中间方法:流水线上的操作。一次操作完毕之后,还可以继续进行其他操作
- 终结方法:一个 Stream 流只能有一个终结方法,是流水线上的最后一个操作
集合获取 Stream 流的方式:可以使用 Collection 接口中的默认方法 `stream()` 生成流
- `default Stream<E> stream()`:获取当前集合对象的 Stream 流
```java
/** --------------------Collection集合获取流------------------------------- */
Collection<String> list = new ArrayList<>();
Stream<String> s = list.stream();
/** --------------------Map集合获取流------------------------------- */
Map<String, Integer> maps = new HashMap<>();
// 键流
Stream<String> keyStream = maps.keySet().stream();
// 值流
Stream<Integer> valueStream = maps.values().stream();
// 键值对流(拿整体)
Stream<Map.Entry<String,Integer>> keyAndValueStream = maps.entrySet().stream();
数组获取 Stream 流的方式:
public static <T> Stream<T> stream(T[] array):获取当前数组的 Stream 流public static<T> Stream<T> of(T... values):获取当前数组/可变数据的 Stream 流/** ---------------------数组获取流------------------------------ */ String[] names = {"赵敏","小昭","灭绝","周芷若"}; Stream<String> nameStream = Arrays.stream(names); Stream<String> nameStream2 = Stream.of(names);Stream 流的常用 API(中间操作方法)
Stream<T> filter(Predicate<? super T> predicate):用于对流中的数据进行过滤。Stream<T> limit(long maxSize):获取前几个元素Stream<T> skip(long n):跳过前几个元素Stream<T> distinct():去除流中重复的元素。依赖(hashCode和equals方法)static <T> Stream<T> concat(Stream a, Stream b):合并 a 和 b 两个流为一个流 ```java names.stream().filter(s -> s.startsWith(“张”)).filter(s -> s.length() == 3).forEach(System.out::println); long size = names.stream().filter(s -> s.length() == 3).count(); System.out.println(size);
names.stream().filter(s -> s.startsWith(“张”)).limit(2).forEach(System.out::println);
names.stream().filter(s -> s.startsWith(“张”)).skip(2).forEach(System.out::println);
// map 加工方法: 第一个参数原材料 -> 第二个参数是加工后的结果。 // 给集合元素的前面都加上一个:Halo : names.stream().map(s -> “Halo :” + s).forEach(System.out::println);
// 需求:把所有的名称 都加工成一个学生对象。 names.stream().map(Student::new).forEach(System.out::println); // 构造器引用 方法引用
// 合并流。
Stream
注意:
- 中间方法也称为非终结方法,调用完成后返回新的 Stream 流可以继续使用,支持链式编程。
- 在 Stream 流中无法直接修改集合、数组中的数据。
```java
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
class Employee {
private String name;
private char sex;
private double salary;
private double bonus;
private String punish; // 处罚信息
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
class Topperformer {
private String name;
private double money; // 月薪
}
private static double allMoney;
private static double allMoney2;
@Test
public void test() {
List<Employee> one = new ArrayList<>();
one.add(new Employee("猪八戒", '男', 30000, 25000, null));
one.add(new Employee("孙悟空", '男', 25000, 1000, "顶撞上司"));
one.add(new Employee("沙僧", '男', 20000, 20000, null));
one.add(new Employee("小白龙", '男', 20000, 25000, null));
List<Employee> two = new ArrayList<>();
two.add(new Employee("武松", '男', 15000, 9000, null));
two.add(new Employee("李逵", '男', 20000, 10000, null));
two.add(new Employee("西门庆", '男', 50000, 100000, "被打"));
two.add(new Employee("潘金莲", '女', 3500, 1000, "被打"));
two.add(new Employee("武大郎", '女', 20000, 0, "下毒"));
// 获取工资最高的员工
Employee employee = one.stream().max(Comparator.comparingDouble(e -> e.getSalary() + e.getBonus())).get();
System.out.println(employee);
// 获取工资最高的员工并封装成 Topperformer 对象
Topperformer topperformer = one.stream().max(Comparator.comparingDouble(e -> e.getSalary() + e.getBonus()))
.map(e -> new Topperformer(e.getName(), e.getSalary() + e.getBonus())).get();
System.out.println(topperformer);
// 统计 one 部门的平均月收入,去掉最高和最低
one.stream().sorted(Comparator.comparingDouble(e -> e.getSalary() + e.getBonus())).skip(1).limit(one.size() - 2).forEach(e -> {
allMoney += (e.getSalary() + e.getBonus());
});
System.out.println("one 部平均工资是" + allMoney / (one.size() - 2));
// 统计两个部门整体的平均工资,去掉最高和最低
Stream<Employee> s1 = one.stream();
Stream<Employee> s2 = two.stream();
Stream<Employee> s3 = Stream.concat(s1, s2);
s3.sorted(Comparator.comparingDouble(e -> e.getSalary() + e.getBonus())).skip(1).limit(one.size() + two.size() - 2).forEach(e -> {
allMoney2 += (e.getSalary() + e.getBonus());
});
BigDecimal a = BigDecimal.valueOf(allMoney2);
BigDecimal b = BigDecimal.valueOf(one.size() + two.size() - 2);
System.out.println("两个部门平均工资是" + a.divide(b, 2, RoundingMode.HALF_UP));
}
Stream流的常见终结操作方法
void forEach(Consumer action):对此流的每个元素执行遍历操作long count():返回此流中的元素数
注意:终结操作方法,调用完成后流就无法继续使用了,原因是不会返回 Stream 了。
Stream 流的收集操作
收集 Stream 流的含义:就是把 Stream 流操作后的结果数据转回到集合或者数组中去。
Stream 流的收集方法:
R collect(Collector collector):开始收集Stream流,指定收集器
Collectors 工具类提供了具体的收集方式
public static <T> Collector toList():把元素收集到 List 集合中public static <T> Collector toSet():把元素收集到 Set 集合中public static Collector toMap(Function keyMapper , Function valueMapper):把元素收集到 Map 集合中 ```java Listlist = new ArrayList<>(); list.add(“张无忌”); list.add(“周芷若”); list.add(“赵敏”); list.add(“张强”); list.add(“张三丰”); list.add(“张三丰”);
Stream
// JDK 16 得到不可变集合
// List
// 注意: “流只能使用一次”
Stream
Stream
