强大的Stream API
所在包为: java.util.stream.*
Stream 是 java 8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的 查找、过滤和映射数据 等操作。使用 Stream api 的操作,就类似使用SQL 执行的数据库查询,。也可以使用 Stream API 来并行执行操作。
简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。
1. 流(Stream) 到底是什么?
流是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。、
”集合讲的是数据,流讲的是计算“
note: ① Stream 不会存储元素
② Stream 不会改变源对象。相反,他们会返回一个持有结果的新的 Stream。
③ Stream 操作时延迟执行的。这意味着他们会等到需要结果的时候才执行。
2. Stream 操作三个步骤
- 创建 Stream
- 中间操作
- 终止操作(终端操作)
2.1 创建 Stream 的方式
// 1. 可以通过 Collection 系列集合提供的 stream() 或 parallelStream()
// stream() 获取串行流;parallelStream() 获取并行流;
List<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();
// 2. 通过 Arrays 中的静态方法 stream() 获取数据流
Employee [] emps = new Employee[10];
Stream<Employee> stream2 = Arrays.stream(emps);
// 3. 通过 Stream 类中的静态方法 of()
Stream<String> stream3 = Stream.of("a", "b", "c");
// 4. 创建无限流
// 迭代
// 函数式接口
// Stream<T> iterate(final T seed, final UnaryOperator<T> f)
//
// @FunctionalInterface
// public interface UnaryOperator<T> extends Function<T, T> {
//
// static <T> UnaryOperator<T> identity() {
// return t -> t;
// }
// }
Stream<Integer> stream4 = Stream.iterate(0, (x) -> x+2);
stream4.limit(10).forEach(System.out::println); // 中间操作+终止操作
// 生成
Stream.generate(() -> Math.random()).limit(5).forEach(System.out::println);
2.2 中间操作
-
/* 筛选和切片 filter ——接受 Lambda,从流中排除某些元素 limit —— 截断流,使其元素不超过给定数量 skip(n) —— 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit() 互补; 注意该方法所执行的位置, 会在其之前的其他筛选方法之后的结果上进行跳过元素 distinct —— 筛选,通过流所生成元素的 hashCode() 和 equals() 去重复元素 (故使用该方法筛选, 需要先重写hashCode, equals ) */ Stream<String> stream = list.stream() .filter((e) -> { return e.getId() > 1; }) .skip(2) .limit(10) .distinct(); /* 映射 map —— 接受 lambda 表达式,将元素转换成其他i形式或提取信息。接受一个函数作为参数,该参数会被应用到每一个元素上,并将其映射成一个新的元素。 flatMap —— 接受一个函数作为参数,将流中的每个值都换成另外一个流,然后把所有流连接成一个流 */ public class TestStream02 { @Test public void test(){ List<String> list = Arrays.asList("a", "b", "CC", "dd"); Stream<Stream<Character>> streamStream = list.stream() .map(TestStream02::filterCharacter); streamStream.forEach((x) -> { x.forEach(System.out::println); }); // 终止操作,打印输出 System.out.println("======================================="); System.out.println("以上代码效果与以下代码相同"); System.out.println("======================================="); list.stream() .flatMap(TestStream02::filterCharacter) .forEach(System.out::println); } public static Stream<Character> filterCharacter(String str){ // 省略具体实现 } } /* 排序 sorted() —— 自然排序 (Comparable) sorted(Comparator com) —— 定制排序(Comparator), 自己实现 Comparator 函数式接口 */ List<String> list = Arrays.asList("a", "b", "CC", "dd"); list.stream().sorted().forEach(System.out::println); System.out.println("===================================="); employees.stream().sorted((e1, e2) -> { if(e1.getId() == e2.getId()) { return e1.getName().compareTo(e2.getName()); } else { return e1.getId().compareTo(e2.getId()); } }).forEach(System.out::println);
注:
中间操作 不会执行任何操作;直到发生 终止操作 才一次性执行全部内容,即"惰性求值"
2.3 终止操作(终端操作)
/*
1. 查找与匹配
allMatch —— 检查是否匹配所有元素
anyMatch —— 检查是否至少匹配一个元素
noneMatch —— 检查是否没有匹配所有元素
findFirst —— 返回第一个元素
findAny —— 返回当前流中的任意元素
count —— 返回流中元素的总个数
max —— 返回流中最大值
min —— 返回流中最小值
*/
// allMatch、anyMatch、noneMatch 实现 Predicate 函数式接口做匹配检查
boolean b1 = employees.stream()
.allMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));
List<String> list = Arrays.asList("a", "b", "CC", "dd");
list.stream().findFirst();
list.stream().findAny();
list.stream().count();
Optional<String> op = list.stream().max(String::compareTo);
Optional<String> op = list.stream().min(String::compareTo);
/*
2. 规约
reduce(T identity, BinaryOperator) / reduce(BinaryOperator) —— 可以将流中元素反复结合起来,得到一个值
*/
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
// reduce(T identity, BinaryOperator)
// 0 代入 x, list的流一个一个元素代入y, 将计算结果重新代入 x, 将下一个元素代入 y
Integer sum = list.stream().reduce(0, (x, y) -> x+y);
System.out.println("==================================");
Optional<Integer> op = employees.stream().map(Employee::getId).reduce(Integer::sum);
System.out.println("op:" + op.get());
/*
3. 收集
collect —— 将流转换为其他形式。接受一个Collector 接口的实现,用于给 Stream 中元素做汇总的方法
*/
public class TestStream04 {
List<Employee> employees = Arrays.asList(
new Employee(1, "atom", Employee.Status.BUSY),
new Employee(2, "jashon", Employee.Status.FREE),
new Employee(3, "Linus", Employee.Status.VOCATION),
new Employee(4, "henry", Employee.Status.FREE),
new Employee(4, "cenry", Employee.Status.VOCATION),
new Employee(4, "zenry", Employee.Status.BUSY),
new Employee(3, "Jack", Employee.Status.BUSY)
);
@Test
public void test8() {
String str = employees.stream().map(Employee::getName)
.collect(Collectors.joining(",", "-> ", " <-"));
// .collect(Collectors.joining(","));
System.out.println(str);
}
@Test
public void test7() {
// 此方法可获得 test3 中所计算的值
IntSummaryStatistics iss = employees.stream().collect(Collectors.summarizingInt(Employee::getId));
System.out.println(iss.getAverage());
System.out.println(iss.getCount());
System.out.println(iss.getCount());
System.out.println(iss.getMax());
System.out.println(iss.getMin());
}
@Test
public void test6() {
Map<Boolean, List<Employee>> map = employees.stream()
.collect(Collectors.partitioningBy((e) -> e.getId() > 3));
System.out.println(map);
}
// 多级分组
@Test
public void test5() {
Map<Employee.Status, Map<String, List<Employee>>> map = employees.stream()
.collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> {
if(((Employee) e).getId() < 3) {
return "靠前";
} else {
return "靠后";
}
})));
System.out.println(map);
}
// 分组
@Test
public void test4() {
Map<Employee.Status, List<Employee>> map = employees.stream()
.collect(Collectors.groupingBy(Employee::getStatus));
System.out.println(map);
}
// 计算
@Test
public void test3() {
// 总数
long count = employees.stream()
.collect(Collectors.counting());
System.out.println("total:" + count);
System.out.println("=======================");
// 平均值
Double avg = employees.stream()
.collect(Collectors.averagingDouble(Employee::getId));
System.out.println("avg:" + avg);
System.out.println("=======================");
// 总和
Integer sum = employees.stream()
.collect(Collectors.summingInt(Employee::getId));
System.out.println("sum:" + sum);
System.out.println("=======================");
// 最大值的对象
Optional<Employee> max = employees.stream()
.collect(Collectors.maxBy((e1, e2) -> Integer.compare(e1.getId(), e2.getId())));
System.out.println("最大值: " + max.get());
System.out.println("=======================");
// 最小值
Optional<Integer> min = employees.stream()
.map(Employee::getId)
.collect(Collectors.minBy(Integer::compare));
System.out.println("最小值: " + min.get());
}
// 收集获得集合
@Test
public void test2() {
List<String> list = employees.stream().map(Employee::getName).collect(Collectors.toList());
list.forEach(System.out::println);
System.out.println("=======================");
Set<String> set = employees.stream().map(Employee::getName).collect(Collectors.toCollection(HashSet::new));
set.forEach(System.out::println);
}
}