1、Lambda 表达式
1.1、介绍
1、什么是 Lambda 表达式
- 匿名内部类:可以作为接口对象的引用(重写了接口的抽象方法)。
- Lambda 表达式:可以作为接口对象的引用(匿名内部类的简写方式)。
public class T01_Lambda {
@Test
public void test01() {
// 匿名内部类
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("开启新的线程 ...");
}
};
Thread thread = new Thread(runnable);
thread.start();
}
public void test02() {
// Lambda 表达式
Runnable runnable = () -> System.out.println("开启新的线程 ...");
Thread thread = new Thread(runnable);
thread.start();
}
}
2、Lambda 表达式语法
- Lambda 表达式分为两个部分
- 左边:参数列表,对应接口抽象方法的参数列表。
- 右边:具体功能,对应接口抽象方法的内部代码。
(参数列表) -> { 代码/表达式 }
- Lambda 表达式的特点(能省则省)
- 参数类型可以省略(类型推断)。
- 单个参数可以省略小括号。
- 单个语句可以省略大括号。
- 单个语句而且有返回值,可以省略 return 与大括号,简化为表达式。
1.2、示例
public class T03_LambdaSyntax {
public static void main(String[] args) {
// 1、无参无返回值
Print01 p1 = () -> System.out.println("你好");
p1.print();
// 2、单个参数无返回值
Print02 p2 = s -> System.out.println(s);
p2.print("你好");
// 3、多个参数无返回值
Math01 m1 = (x, y) -> System.out.println(x * y);
m1.operation(10, 15);
// 4、多个参数有返回值
Math02 m2 = (x, y) -> x * y;
System.out.println(m2.operation(10, 15));
}
public interface Print01 {
// 1、无参无返回值
void print();
}
public interface Print02 {
//2、单个参数无返回值
void print(String s);
}
public interface Math01 {
// 3、多个参数无返回值
void operation(int x, int y);
}
public interface Math02 {
// 4、多个参数有返回值
int operation(int x, int y);
}
}
1.3、存在问题:foreach() 方法中使用 Lambda 如何提前终止
- 存在问题:使用 foreach() 方法遍历集合,其内部为 Lambda 表达式。需要提前终止遍历,但是 continue、break 直接报错。
- 原因分析:因为 foreach() 是方法而不是循环语句,因此无法使用 continue、break。终止方法可以 return 或者抛出异常。
- 如何解决
- 方式一:使用 foreach() 方法遍历集合,使用 return 终止遍历。后续代码继续执行,相当于 continue。
- 方式二:使用 foreach() 方法遍历集合,使用 throw 抛出异常但不处理。后续代码没有执行,相当于 break。
- 方式三:使用增强 for 循环遍历集合,使用 break、continue 终止遍历。
public class T03_LambdaForeach {
// 方式一:使用 foreach() 方法遍历集合,使用 return 终止遍历。后续代码继续执行,**相当于 continue**。
@Test
public void test01() {
List<String> list = Arrays.asList("A", "B", "C");
list.forEach(s -> {
if ("B".equals(s)) {
System.out.print(" 终止或跳出循环 ");
// continue;
// break;
return;
}
System.out.print(s);
});
// 结果:A 终止或跳出循环 C
}
// 方式二:使用 foreach() 方法遍历集合,使用 throw 抛出异常但不处理。后续代码没有执行,**相当于 break**。
@Test
public void test02() {
List<String> list = Arrays.asList("A", "B", "C");
try {
list.forEach(s -> {
if ("B".equals(s)) {
System.out.print(" 终止或跳出循环 ");
throw new RuntimeException(" 终止或跳出循环 ");
}
System.out.print(s);
});
} catch (RuntimeException e) {
}
// 结果:A 终止或跳出循环
}
// 方式三:使用增强 for 循环遍历集合,**使用 continue、break 终止遍历**。
@Test
public void test03() {
List<String> list = Arrays.asList("A", "B", "C");
for (String s : list) {
if ("B".equals(s)) {
System.out.print(" 终止或跳出循环 ");
// continue;
break;
}
System.out.print(s);
}
// continue 结果:A 终止或跳出循环 C
// break 结果:A 终止或跳出循环
}
}
2、方法引用
2.1、介绍
- 方法引用:可以作为接口对象的引用(Lambda 表达式的简写方式,前提是该 Lambda 表达式存在已有实现)。
- 方法引用分类
- 调用实例方法:对象::实例方法名
- 调用实例方法:类名::实例方法名(注意:Java 代码中不允许类名调用实例方法,方法引用可以)
- 调用静态方法:类名::静态方法名
- 调用构造方法:类名::new(只能调用无参构造)
- 调用数组构造方法:类名[]::new(只能调用无参构造)
2.2、示例
// 方法引用
public class T01_MethodReference {
// 调用实例方法:实例::实例方法名
@Test
public void test01() {
Consumer<String> consumer1 = s -> System.out.println(s);
consumer1.accept("张三");
// 以上 Lambda 表达式,存在已有实现(out 实例的方法),因此可替换为方法引用
Consumer<String> consumer2 = System.out::println;
consumer2.accept("张三");
}
// 调用实例方法:类名::实例方法名
@Test
public void test02() {
Function<String, Integer> function1 = s -> s.length();
System.out.println(function1.apply("张三"));
// 以上 Lambda 表达式,存在已有实现(String 类的实例方法),因此可替换为方法引用
Function<String, Integer> function2 = String::length;
System.out.println(function2.apply("张三"));
}
// 调用静态方法:类名::静态方法名
@Test
public void test03() {
Function<Integer, String> function1 = integer -> String.valueOf(integer);
System.out.println(function1.apply(30));
// 以上 Lambda 表达式,存在已有实现(String 类的静态方法),因此可替换为方法引用
Function<Integer, String> function2 = String::valueOf;
System.out.println(function2.apply(30));
}
// 调用构造方法:类名::new
@Test
public void test04() {
Supplier<Object> supplier1 = () -> new Object();
System.out.println(supplier1.get());
// 以上 Lambda 表达式,存在已有实现(Object 类的构造方法),因此可替换为方法引用
Supplier<Object> supplier2 = Object::new;
System.out.println(supplier2.get());
}
// 调用数组构造方法:类名[]::new
@Test
public void test05() {
Function<Integer, String[]> function1 = integer -> new String[integer];
System.out.println(Arrays.toString(function1.apply(10)));
// 以上 Lambda 表达式,存在已有实现(String 数组的构造方法),因此可替换为方法引用
Function<Integer, String[]> function2 = String[]::new;
System.out.println(Arrays.toString(function2.apply(10)));
}
}
2.3、匿名内部类、Lambda 表达式、方法引用的关系
- 匿名内部类:可以作为接口对象的引用(重写了接口的抽象方法)。
- Lambda 表达式:可以作为接口对象的引用(匿名内部类的简写方式)。
- 方法引用:可以作为接口对象的引用(Lambda 表达式的简写方式,前提是该 Lambda 表达式存在已有实现)。
3、函数式接口
3.1、介绍
1、什么是函数式接口
- 如果某个接口“只有一个抽象方法”(只有一个方法需要实现),则该接口为函数式接口。
- 函数式接口的实现类对象可以使用 Lambda 表达式来表示。
2、@FunctionalInterface 注解
- @FunctionalInterface 注解表示该接口为函数式接口,若不符合要求则会报错(作用类似 @Override 注解,若该方法不符合重写要求则会报错)。
- 函数式接口具有以下特点:
- “只有一个抽象方法”(只有一个方法需要实现)。
- 该抽象方法包括继承自其他接口的抽象方法。
- 该抽象方法不包括默认方法、静态方法、私有方法(因为这些方法本身提供实现)。
- 该抽象方法不包括重写 Object 类的方法(因为所有的类默认继承 Object 类,这些方法 Object 类已经实现)。
// 自定义函数式接口
@FunctionalInterface
public interface T01_FunctionalInterface {
void print();
default void print(Integer i) {
System.out.println(i);
}
static void print(String s) {
System.out.println(s);
}
String toString();
}
3、四大核心函数式接口
- Consumer 接口:消费型接口。接收参数无返回值。
- Supplier 接口:供给型接口。不接收参数有返回值。
- Function 接口:函数型接口。接收参数有返回值。
- Predicate 接口:断定型接口。接收参数返回布尔值。
public class T02_FunctionalInterface {
public static void main(String[] args) {
Consumer<Integer> consumer = x -> x = x + 10;
Supplier<Integer> supplier = () -> 5 * 5;
Function<Integer, Integer> function = x -> x * x;
Predicate<Integer> predicate = x -> x > 10;
}
}
3.2、Consumer 消费型接口
1、Consumer 接口
- 抽象方法:accept():执行指定函数
- 默认方法:andThen():返回组合函数。然后执行
package java.util.function;
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
2、示例
- 指定字符串,先输出其长度,再输出其大写,再输出其小写。
// 指定字符串,先输出其长度,再输出其大写,再输出其小写
public class T01_Consumer {
@Test
public void test01() {
print("Java", s -> System.out.println(s.length()), s -> System.out.println(s.toUpperCase()), s -> System.out.println(s.toLowerCase()));
}
public void print(String s, Consumer<String> c1, Consumer<String> c2, Consumer<String> c3) {
// 组合多个函数
Consumer<String> consumer = c1.andThen(c2).andThen(c3);
// 执行函数
consumer.accept(s);
}
}
3.3、Supplier 供给型接口
1、Supplier 接口
- 抽象方法:get():执行指定函数
package java.util.function;
@FunctionalInterface
public interface Supplier<T> {
T get();
}
2、示例
- 产生 10 个 0~100 之间的整数,添加到集合中。
// 产生 10 个 0~100 之间的整数,添加到集合中
public class T01_Supplier {
@Test
public void test01() {
List<Integer> list = getList(10, () -> (new Random().nextInt(100)));
list.forEach(System.out::println);
}
public List<Integer> getList(int length, Supplier<Integer> supplier) {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < length; i++) {
// 执行函数
Integer integer = supplier.get();// 每次执行获得一个结果
list.add(integer);
}
return list;
}
}
3.4、Function 函数型接口
1、Function 接口
- 抽象方法:apply():执行指定函数
- 默认方法
- compose():返回组合函数。将前一个函数的结果,作为后一个函数的参数
- andThen():返回组合函数。然后执行
- 静态方法:identity():返回一个函数。该函数为输入参数
package java.util.function;
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
static <T> Function<T, T> identity() {
return t -> t;
}
}
2、示例
- 输入“张三,30”,先截取年龄,再转为数字,再给年龄加 1。
// 输入“张三,30”,先截取年龄,再转为数字,再给年龄加 1
public class T01_Function {
@Test
public void test01() {
Integer calc = calc("张三,30", s -> s.trim().split(",")[1], s -> Integer.parseInt(s), s -> s + 1);
System.out.println(calc);
}
public Integer calc(String s, Function<String, String> f1, Function<String, Integer> f2, Function<Integer, Integer> f3) {
// 返回组合函数。将前一个函数的结果,作为后一个函数的参数
Function<String, Integer> function = f3.compose(f2.compose(f1));// 先将 f1 的结果作为 f2 的参数,再将 f2 的结果作为 f3 的参数
return function.apply(s);
}
}
3.5、Predicate 断言型接口
1、Predicate 接口
- 抽象方法:test():执行指定函数
- 默认方法
- and():返回组合函数。逻辑且
- negate():返回组合函数。逻辑非
- or():返回组合函数。逻辑或
- 静态方法:isEqual():返回一个函数。判断输入参数是否等于目标对象
package java.util.function;
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
default Predicate<T> negate() {
return (t) -> !test(t);
}
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
2、Predicate 接口示例
@Test
public void test01() {
isTrue("ABC", s -> s.startsWith("A"), s -> s.length() == 2);
}
public void isTrue(String s, Predicate<String> p1, Predicate<String> p2) {
System.out.println("是否以 A 开始:" + p1.test(s));
System.out.println("是否非 A 开始:" + p1.negate().test(s));
System.out.println("是否以 A 开始,而且长度为 3:" + p1.and(p2).test(s));
System.out.println("是否以 A 开始,或者长度为 3:" + p1.or(p2).test(s));
System.out.println("输入参数是否等于 ABC:" + Predicate.isEqual("ABC").test(s));
}
}
4、Stream 流
4.1、介绍
1、什么是 Stream 流
- Stream 流可以将集合(数组、Collection 单列集合、Map 双列集合)看做是一个流,并对集合中的元素进行各种操作。例如:筛选、遍历、排序、映射、收集、聚合等等。
- Stream 流相比直接操作集合,代码简洁,功能强大。
- 根据 Stream 对象方法的返回值类型,Stream 流分为两种操作
- 中间操作:返回值类型为 Stream 流,可以继续进行其他流式操作。
- 终结操作:返回值类型为其他对象,不能继续进行其他流式操作。
- 注意事项
- 每次调用中间操作,就会生成新的 Stream 对象。
- 只有调用终结操作,中间操作才会执行。
- 调用终结操作之后,Stream 对象不能再次使用,否则会发生非法状态异常 IllegalStateException。
- 不用手动关闭(指向内存的流不用关闭,指向硬盘/网络等等外部资源的流需要关闭)。
2、如何获取 Stream 流
- Array 数组:一是使用 Arrays 类的静态方法 stream(T[] array),二是使用 Stream 的静态方法 of()、iterate()、generate()。
- Collection 单列集合:直接使用 Collection 接口的默认方法 stream()。
- Map 双列集合:需要先将 Map 转换为 Collection,然后间接使用 Collection 接口的默认方法 stream()。
public class T01_GetStream {
@Test
public void test01() {
String[] s = new String[]{"张三", "李四", "王五"};
Arrays.stream(s).forEach(System.out::println);// 张三 李四 王五
Stream.of(s).forEach(System.out::println);// 张三 李四 王五
}
@Test
public void test02() {
Collection<String> collection = Arrays.asList("张三", "李四", "王五");
collection.stream().forEach(System.out::println);// 张三 李四 王五
}
@Test
public void test03() {
Map<String, String> map = new HashMap<>();
map.put("张三", "zhangsan");
map.put("李四", "lisi");
map.put("王五", "wangwu");
map.keySet().stream().forEach(System.out::print);// 李四 张三 王五
map.values().stream().forEach(System.out::println);// lisi zhangsan wangwu
map.entrySet().stream().forEach(System.out::println);// 李四=lisi 张三=zhangsan 王五=wangwu
}
}
4.2、相关接口
package java.util.stream;
public interface BaseStream<T, S extends BaseStream<T, S>> extends AutoCloseable {
Iterator<T> iterator();
Spliterator<T> spliterator();
boolean isParallel();
S sequential();
S parallel();
S unordered();
S onClose(Runnable closeHandler);
@Override
void close();
}
4.3、Optional 类
- 容器,用来存储对象。经常作为 Stream 流部分方法的返回值。
- 特点:final 类,私有构造方法。
package java.util;
public final class Optional<T> {
private static final Optional<?> EMPTY = new Optional<>();
private final T value;
private Optional() {
this.value = null;
}
public static<T> Optional<T> empty() {}
public static <T> Optional<T> of(T value) {}
public static <T> Optional<T> ofNullable(T value) {}
public T get() {}// 获取
public boolean isPresent() {}// 判断是否存在
public void ifPresent(Consumer<? super T> consumer) {}// 如果存在,执行消费函数
public Optional<T> filter(Predicate<? super T> predicate) {}// 过滤,根据断定函数
public <U> Optional<U> map(Function<? super T, ? extends U> mapper) {}// 映射,根据函数
public <U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {}// 映射,根据函数
public T orElse(T other) {}// 如果存在,返回该值,否则返回 T other
public T orElseGet(Supplier<? extends T> other) {}// 如果存在,返回该值,否则返回供给型函数生成的结果
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {}// 如果存在,返回该值,否则抛出供给函数生成的异常
}
4.4、常用方法介绍
- 常用方法
- 遍历 forEach、排序 sort、过滤 filter、映射 map、归纳 reduce、窥视 peek
- 其他方法
- 最小 min、最大 max、计数 count、匹配 match、查找 find
- 去重 distinct、限量 limit、跳过 skip
- 静态方法
- 返回流构建器、返回空流、转换为流、生成无限流、合并流
- 收集
- 转换为数组、收集为集合
package java.util.stream;
public interface Stream<T> extends BaseStream<T, Stream<T>> {
// 1、遍历
void forEach(Consumer<? super T> action);// 遍历
void forEachOrdered(Consumer<? super T> action);// 顺序遍历
// 2、排序
Stream<T> sorted();// 自然排序
Stream<T> sorted(Comparator<? super T> comparator);// 比较器排序
// 3、过滤
Stream<T> filter(Predicate<? super T> predicate);
// 4、映射
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
IntStream mapToInt(ToIntFunction<? super T> mapper);
LongStream mapToLong(ToLongFunction<? super T> mapper);
DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper);
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper);
LongStream flatMapToLong(Function<? super T, ? extends LongStream> mapper);
DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper);
// 5、归纳
Optional<T> reduce(BinaryOperator<T> accumulator);// 不能改变归纳类型,无初始值
T reduce(T identity, BinaryOperator<T> accumulator);// 不能改变归纳类型,有初始值
<U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner);// 可以改变归纳类型,有初始值
// 6、窥视
Stream<T> peek(Consumer<? super T> action);
// 7.1、最小、最大、计数、匹配、查找
Optional<T> min(Comparator<? super T> comparator);// 最小
Optional<T> max(Comparator<? super T> comparator);// 最大
long count();// 计数
boolean anyMatch(Predicate<? super T> predicate);// 匹配(任意一个符合条件则返回 true)
boolean allMatch(Predicate<? super T> predicate);// 匹配(全部元素符合条件则返回 true)
boolean noneMatch(Predicate<? super T> predicate);// 匹配(没有一个符合条件则返回 true)
Optional<T> findFirst();// 查找
Optional<T> findAny();// 查找
// 7.2、去重、限量、跳过
Stream<T> distinct();
Stream<T> limit(long maxSize);// 限量
Stream<T> skip(long n);// 跳过
// 8、静态方法
public static<T> Builder<T> builder() {}// 返回流构建器,用于构建流
public static<T> Stream<T> empty() {}// 返回空流,然后使用 concat() 合并流
public static<T> Stream<T> of(T t) {}// 转换为流
public static<T> Stream<T> of(T... values) {}// 转换为流
public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) {}// 生成无限流,根据指定种子
public static<T> Stream<T> generate(Supplier<T> s) {}// 生成无限流
public static<T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) {}// 合并流
public interface Builder<T> extends Consumer<T> {
@Override
void accept(T t);
default Builder<T> add(T t) {}
Stream<T> build();
}
// 9.1、转换为数组
Object[] toArray();// 收集为 Object 类型的数组
<A> A[] toArray(IntFunction<A[]> generator);// 收集为指定类型的数组
// 9.2、收集为集合
<R> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner);// 自定义收集
<R, A> R collect(Collector<? super T, A, R> collector);// 指定收集器收集
}
- Employee 类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Employee {
private String name;
private String gender;
private Integer age;
private String address;
private Double salary;
public static List<Employee> getList() {
List<Employee> list = new ArrayList<>();
list.add(new Employee("张三", "男", 17, "西安", 6500.0D));
list.add(new Employee("李四", "女", 19, "郑州", 4000.0D));
list.add(new Employee("王五", "男", 18, "上海", 4800.0D));
list.add(new Employee("赵六", "女", 20, "北京", 4000.0D));
list.add(new Employee("钱七", "男", 22, "武汉", 4500.0D));
list.add(new Employee("孙八", "女", 21, "南京", 8000.0D));
return list;
}
}
4.5、常用方法 - 遍历
/*
// 1、遍历
void forEach(Consumer<? super T> action);// 遍历
void forEachOrdered(Consumer<? super T> action);// 顺序遍历
*/
public class T01_Foreach {
@Test
public void test01() {
List<String> list = Arrays.asList("B", "C", "A");
list.stream().forEach(System.out::println);
list.stream().forEachOrdered(System.out::println);
}
}
4.6、串行流与并行流
1、如何获取并行流
- 方式一:将串行流转换为并行流
- 方式二:直接生成并行流
// 如何获取并行流
public class T01_GetParallelStream {
@Test
public void test01() {
List<String> list = new ArrayList<>();
// 方式一:将串行流转换为并行流
Stream<String> s1 = list.stream().parallel();
// 方式二:直接生成并行流
Stream<String> s2 = list.parallelStream();
}
}
2、串行流与并行流的区别
- 遍历区别:foreach() 与 foreachOrdered() 方法,串行流下两者结果一致,并行流下前者不能保证遍历顺序,后者可以。
- 查找区别:findAny() 与 findFirst() 方法,串行流下两者都是返回第一个元素,并行流下前者不能保证每次都返回第一个元素,后者可以。
- 速度区别:并行流比串行流速度更快。
// 串行流与并行流的区别
public class T02_ParallelStream {
// 遍历区别
@Test
public void test01() {
List<String> list = Arrays.asList("B", "C", "A");
System.out.println("并行流 forEach() 方法");
list.parallelStream().forEach(System.out::println);
System.out.println("并行流 forEachOrdered() 方法");
list.parallelStream().forEachOrdered(System.out::println);// 结果始终为:B C A
}
// 查找区别
@Test
public void test02() {
List<String> list = Arrays.asList("B", "C", "A");
Optional<String> any = list.parallelStream().findAny();
System.out.println(any.get());
Optional<String> first = list.parallelStream().findFirst();
System.out.println(first.get());// 结果始终为:B
}
}
4.7、常用方法 - 排序
/*
// 2、排序
Stream<T> sorted();// 自然排序
Stream<T> sorted(Comparator<? super T> comparator);// 比较器排序
*/
public class T01_Sorted {
// 自然排序
@Test
public void test01() {
List<String> list = Arrays.asList("B", "C", "A");
list.stream().sorted().forEach(System.out::println);
}
// 比较器排序
@Test
public void test02() {
List<Employee> employees = Employee.getList();
employees.stream().sorted((e1, e2) -> {
double d = e2.getSalary() - e1.getSalary();
int i = e1.getAge() - e2.getAge();
return d > 0 ? 1 : (d < 0 ? -1 : i > 0 ? 1 : (i < 0 ? -1 : 0));
}).forEach(System.out::println);
}
}
4.8、常用方法 - 过滤
/*
// 3、过滤
Stream<T> filter(Predicate<? super T> predicate);
*/
public class T01_Filter {
@Test
public void test01() {
List<String> list = Arrays.asList("乔峰", "段誉", "虚竹", "鸠摩智", "段正淳", "段延庆", "庄聚贤", "慕容复");
// 以下写法结果相同
list.stream().filter(s -> s.startsWith("段")).filter(s -> s.length() == 2).forEach(System.out::println);
list.stream().filter(s -> s.startsWith("段") && s.length() == 2).forEach(System.out::println);
}
@Test
public void test02() {
List<Employee> list = Employee.getList();
// 以下写法结果相同
list.stream().filter(e -> "男".equals(e.getGender())).filter(e -> e.getSalary() >= 5000.0D).forEach(System.out::println);
list.stream().filter(e -> "男".equals(e.getGender()) && e.getSalary() >= 5000.0D).forEach(System.out::println);
}
}
4.9、常用方法 - 映射
1、映射分类
- 根据方法返回流中元素的数量分为:mapXXX() 一对一映射、faltMapXXX() 一对多映射
- 根据方法返回流的数据类型分为:Stream、IntStream、LongStream、DoubleStream。Stream 流泛型为引用数据类型,后三个为底层流,专门用于操作基本数据类型。
2、示例一
/*
// 4、映射
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
IntStream mapToInt(ToIntFunction<? super T> mapper);
LongStream mapToLong(ToLongFunction<? super T> mapper);
DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper);
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper);
LongStream flatMapToLong(Function<? super T, ? extends LongStream> mapper);
DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper);
*/
public class T01_Map01 {
// map()
@Test
public void test01() {
List<Employee> list = Employee.getList();
Stream<String> stream1 = list.stream().map(Employee::getName);
stream1.forEach(System.out::println);
// 结果:张三 李四 王五 赵六 钱七 孙八
}
// flatMap()
@Test
public void test02() {
List<Employee> list = Employee.getList();
Stream<String> stream2 = list.stream().flatMap(e -> Stream.of(e.getName().split("")));
stream2.forEach(System.out::println);
// 结果:张 三 李 四 王 五 赵 六 钱 七 孙 八
}
// map() 与 mapToInt() 的区别
@Test
public void test03() {
List<Employee> list = Employee.getList();
Stream<Integer> stream = list.stream().map(Employee::getAge);
IntStream intStream = list.stream().mapToInt(Employee::getAge);
}
// flatMap() 与 flatMapToInt() 的区别
@Test
public void test04() {
List<Employee> list = Employee.getList();
Stream<Integer> stream = list.stream().flatMap(e -> Stream.of(e.getAge(), e.getSalary().intValue()));
IntStream intStream = list.stream().flatMapToInt(e -> IntStream.of(e.getAge(), e.getSalary().intValue()));
}
}
3、示例二
/*
// 4、映射
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
IntStream mapToInt(ToIntFunction<? super T> mapper);
LongStream mapToLong(ToLongFunction<? super T> mapper);
DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper);
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper);
LongStream flatMapToLong(Function<? super T, ? extends LongStream> mapper);
DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper);
*/
public class T01_Map02 {
// 1、所有员工工资加 1000
@Test
public void test01() {
List<Employee> list = Employee.getList();
Stream<Employee> stream = list.stream().map(e -> {
Employee employee = new Employee();
employee.setName(e.getName());
employee.setSalary(e.getSalary() + 1000.0D);
return employee;
});
stream.forEach(System.out::println);
}
// 2、所有员工工资加 1000
@Test
public void test02() {
List<Employee> list = Employee.getList();
Stream<Employee> stream = list.stream().map(e -> {
e.setSalary(e.getSalary() + 1000.0D);
return e;
});
stream.forEach(System.out::println);
}
}
4.10、常用方法 - 归纳
- 归纳总结三种方式的区别
- 方式一:不能改变归纳类型,无初始值
- 方式二:不能改变归纳类型,有初始值
- 方式三:可以改变归纳类型,有初始值
/*
// 5、归纳
Optional<T> reduce(BinaryOperator<T> accumulator);// 不能改变归纳类型,无初始值
T reduce(T identity, BinaryOperator<T> accumulator);// 不能改变归纳类型,有初始值
<U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner);// 可以改变归纳类型,有初始值
*/
public class T01_Reduce {
// 员工年龄求和
@Test
public void test01() {
List<Employee> list = Employee.getList();
Optional<Integer> reduce = list.stream().map(Employee::getAge).reduce(Integer::sum);
System.out.println(reduce.get());
}
// 员工年龄求和
@Test
public void test02() {
List<Employee> list = Employee.getList();
Integer reduce = list.stream().map(Employee::getAge).reduce(0, Integer::sum);
System.out.println(reduce);
}
// 员工年龄求和
@Test
public void test03() {
List<Employee> list = Employee.getList();
Integer reduce = list.stream().reduce(0, (age, e) -> Integer.sum(age, e.getAge()), Integer::sum);
System.out.println(reduce);
}
}
4.11、常用方法 - 窥视
- peek()、map()、forEach() 的区别
- peek():进行消费型操作,返回操作之前的流。额外操作,不会改变流中的数据,但是可以改变流中数据的引用。
- map():进行函数型操作,返回操作之后的流。
- forEach():进行消费型操作,无返回值。
/*
// 6、窥视
Stream<T> peek(Consumer<? super T> action);
peek()、map()、forEach() 的区别
peek():进行消费型操作,返回操作之前的流。额外操作,不会改变流中的数据,但是可以改变流中数据的引用。
map():进行函数型操作,返回操作之后的流。
forEach():进行消费型操作,无返回值。
peek()、map()、forEach() 方法
Stream<T> peek(Consumer<? super T> action);
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
void forEach(Consumer<? super T> action);
*/
public class T01_Peek {
// peek() 不会改变流中的数据
@Test
public void test01() {
List<String> list = Arrays.asList("B", "C", "A");
list.stream().peek(s -> System.out.println("额外操作:" + s.toLowerCase())).forEach(s -> System.out.println("遍历输出:" + s));
}
// peek() 但是可以改变流中数据的引用
@Test
public void test02() {
List<Employee> list = Employee.getList();
list.stream().peek(e -> e.setAge(100)).forEach(System.out::println);
}
}
4.12、常用方法 - 其他方法
/*
// 7.1、最小、最大、计数、匹配、查找
Optional<T> min(Comparator<? super T> comparator);// 最小
Optional<T> max(Comparator<? super T> comparator);// 最大
long count();// 计数
boolean anyMatch(Predicate<? super T> predicate);// 匹配(任意一个符合条件则返回 true)
boolean allMatch(Predicate<? super T> predicate);// 匹配(全部元素符合条件则返回 true)
boolean noneMatch(Predicate<? super T> predicate);// 匹配(没有一个符合条件则返回 true)
Optional<T> findFirst();// 查找
Optional<T> findAny();// 查找
// 7.2、去重、限量、跳过
Stream<T> distinct();
Stream<T> limit(long maxSize);// 限量
Stream<T> skip(long n);// 跳过
*/
public class T01_OtherMethods {
@Test
public void test01() {
List<Employee> list = Employee.getList();
// 最小
Optional<Employee> min = list.stream().min((o1, o2) -> o1.getAge() - o2.getAge());
min.ifPresent(System.out::println);
// 最大
Optional<Employee> max = list.stream().max((o1, o2) -> o1.getAge() - o2.getAge());
max.ifPresent(System.out::println);
// 计数
System.out.println(list.stream().count());
// 匹配
boolean b1 = list.stream().anyMatch(employee -> employee.getAge() > 20);
boolean b2 = list.stream().allMatch(employee -> employee.getAge() > 20);
boolean b3 = list.stream().noneMatch(employee -> employee.getAge() > 20);
System.out.println(b1);
System.out.println(b2);
System.out.println(b3);
// 查找
Optional<Employee> first = list.stream().findFirst();
Optional<Employee> any = list.stream().findAny();
first.ifPresent(System.out::println);
any.ifPresent(System.out::println);
}
@Test
public void test02() {
List<String> list = Arrays.asList("A", "B", "C", "A", "B", "C");
// 去重
System.out.println("去重:");
list.stream().distinct().forEach(System.out::println);// A B C
System.out.println("跳过、限量:");
// 跳过、限量
list.stream().skip(2).limit(2).forEach(System.out::println);// C A
}
}
4.13、常用方法 - 静态方法
- of():转换为流
- iterate()、generate():生成无限流
- builder():返回流构建器,用于构建流
- empty():返回空流,然后使用 concat() 合并流
- concat():合并流
/*
// 8、静态方法
public static<T> Builder<T> builder() {}// 返回流构建器,用于构建流
public static<T> Stream<T> empty() {}// 返回空流,然后使用 concat() 合并流
public static<T> Stream<T> of(T t) {}// 转换为流
public static<T> Stream<T> of(T... values) {}// 转换为流
public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) {}// 生成无限流,根据指定种子
public static<T> Stream<T> generate(Supplier<T> s) {}// 生成无限流
public static<T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) {}// 合并流
*/
public class T01_StaticMethods {
// 1、转换为流
@Test
public void test01() {
Stream<String> s1 = Stream.of("张三");
Stream<String> s2 = Stream.of("张三", "李四", "王五");
String[] array = new String[]{"张三", "李四", "王五"};
Stream<String> s3 = Stream.of(array);
}
/*
2、iterate() 生成无限流:
1、生成字符串:张三-1 张三-2 张三-3 张三-4 张三-5
2、计算 5 的阶乘
*/
@Test
public void test02() {
Stream<String> stream = Stream.iterate("张三-1", s -> {
String[] split = s.split("-");
return split[0] + "-" + (Integer.parseInt(split[1]) + 1);
}).limit(5);
stream.forEach(System.out::println);
Optional<Integer> optional = Stream.iterate(1, integer -> integer + 1).limit(5).reduce((i1, i2) -> i1 * i2);
System.out.println(optional.get());
}
// 3、generate() 生成无限流:生成 10 个 100 以内的随机数
@Test
public void test03() {
Stream<Integer> stream = Stream.generate(() -> new Random().nextInt(100)).limit(10);
stream.forEach(System.out::println);
}
// 4、流构件器
@Test
public void test04() {
Stream.Builder<String> builder = Stream.builder();
Stream<String> stream = builder.add("张三").add("李四").add("王五").build();
stream.forEach(System.out::println);
}
// 5、合并流
@Test
public void test05() {
Stream<String> empty = Stream.empty();
Stream<String> stream1 = Stream.of("张三", "李四", "王五");
Stream<String> stream2 = Stream.concat(empty, stream1);
stream2.forEach(System.out::println);
}
}
4.14、常用方法 - 收集
1、介绍
- 转换为数组、收集为集合
// 9.1、转换为数组
Object[] toArray();// 收集为 Object 类型的数组
<A> A[] toArray(IntFunction<A[]> generator);// 收集为指定类型的数组
// 9.2、收集为集合
<R> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner);// 自定义收集
<R, A> R collect(Collector<? super T, A, R> collector);// 指定收集器收集
- Collectors 类 - 收集器工具类
package java.util.stream;
public final class Collectors {
// 1.1、收集为指定 Collection、List、Set
public static <T, C extends Collection<T>> Collector<T, ?, C> toCollection(Supplier<C> collectionFactory) {}// 收集为指定 Collection
public static <T> Collector<T, ?, List<T>> toList() {}// 收集为 List
public static <T> Collector<T, ?, Set<T>> toSet() {}// 收集为 Set
// 1.2、收集为 Map
public static <T, K, U> Collector<T, ?, Map<K,U>> toMap(
Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper) {}
public static <T, K, U> Collector<T, ?, Map<K,U>> toMap(
Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper,
BinaryOperator<U> mergeFunction) {}
public static <T, K, U, M extends Map<K, U>> Collector<T, ?, M> toMap(
Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper,
BinaryOperator<U> mergeFunction,
Supplier<M> mapSupplier) {}
// 1.3、收集为 ConcurrentMap
public static <T, K, U> Collector<T, ?, ConcurrentMap<K,U>> toConcurrentMap(
Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper) {}
public static <T, K, U> Collector<T, ?, ConcurrentMap<K,U>> toConcurrentMap(
Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper,
BinaryOperator<U> mergeFunction) {}
public static <T, K, U, M extends ConcurrentMap<K, U>> Collector<T, ?, M> toConcurrentMap(
Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper,
BinaryOperator<U> mergeFunction,
Supplier<M> mapSupplier) {}
// 2、字符串连接
public static Collector<CharSequence, ?, String> joining() {}
public static Collector<CharSequence, ?, String> joining(CharSequence delimiter) {}
public static Collector<CharSequence, ?, String> joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix) {}
// 7、映射
public static <T, U, A, R> Collector<T, ?, R> mapping(Function<? super T, ? extends U> mapper, Collector<? super U, A, R> downstream) {}
// 8、收集,然后执行 Function
public static <T,A,R,RR> Collector<T,A,RR> collectingAndThen(Collector<T,A,R> downstream, Function<R,RR> finisher) {}
// 3、统计:计数、最小、最大、求和、平均、统计所有
public static <T> Collector<T, ?, Long> counting() {}// 计数
public static <T> Collector<T, ?, Optional<T>> minBy(Comparator<? super T> comparator) {}// 最小
public static <T> Collector<T, ?, Optional<T>> maxBy(Comparator<? super T> comparator) {}// 最大
public static <T> Collector<T, ?, Integer> summingInt(ToIntFunction<? super T> mapper) {}// 求和
public static <T> Collector<T, ?, Long> summingLong(ToLongFunction<? super T> mapper) {}// 求和
public static <T> Collector<T, ?, Double> summingDouble(ToDoubleFunction<? super T> mapper) {}// 求和
public static <T> Collector<T, ?, Double> averagingInt(ToIntFunction<? super T> mapper) {}// 平均
public static <T> Collector<T, ?, Double> averagingLong(ToLongFunction<? super T> mapper) {}// 平均
public static <T> Collector<T, ?, Double> averagingDouble(ToDoubleFunction<? super T> mapper) {}// 平均
public static <T> Collector<T, ?, IntSummaryStatistics> summarizingInt(ToIntFunction<? super T> mapper) {}// 统计所有
public static <T> Collector<T, ?, LongSummaryStatistics> summarizingLong(ToLongFunction<? super T> mapper) {}// 统计所有
public static <T> Collector<T, ?, DoubleSummaryStatistics> summarizingDouble(ToDoubleFunction<? super T> mapper) {}// 统计所有
// 4、归纳
public static <T> Collector<T, ?, T> reducing(T identity, BinaryOperator<T> op) {}
public static <T> Collector<T, ?, Optional<T>> reducing(BinaryOperator<T> op) {}
public static <T, U> Collector<T, ?, U> reducing(U identity, Function<? super T, ? extends U> mapper, BinaryOperator<U> op) {}
// 5.1、分组:返回 Map
public static <T, K> Collector<T, ?, Map<K, List<T>>> groupingBy(
Function<? super T,
? extends K> classifier) {}
public static <T, K, A, D> Collector<T, ?, Map<K, D>> groupingBy(
Function<? super T, ? extends K> classifier,
Collector<? super T, A, D> downstream) {}
public static <T, K, D, A, M extends Map<K, D>> Collector<T, ?, M> groupingBy(
Function<? super T, ? extends K> classifier,
Supplier<M> mapFactory,
Collector<? super T, A, D> downstream) {}
// 5.2、分组:返回 ConcurrentMap
public static <T, K> Collector<T, ?, ConcurrentMap<K, List<T>>> groupingByConcurrent(
Function<? super T, ? extends K> classifier) {}
public static <T, K, A, D>Collector<T, ?, ConcurrentMap<K, D>> groupingByConcurrent(
Function<? super T, ? extends K> classifier,
Collector<? super T, A, D> downstream) {}
public static <T, K, A, D, M extends ConcurrentMap<K, D>> Collector<T, ?, M> groupingByConcurrent(
Function<? super T, ? extends K> classifier,
Supplier<M> mapFactory,
Collector<? super T, A, D> downstream) {}
// 6、分区
public static <T> Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(
Predicate<? super T> predicate) {}
public static <T, D, A> Collector<T, ?, Map<Boolean, D>> partitioningBy(
Predicate<? super T> predicate,
Collector<? super T, A, D> downstream) {}
}
2、收集为数组
/*
// 9.1、转换为数组
Object[] toArray();// 收集为 Object 类型的数组
<A> A[] toArray(IntFunction<A[]> generator);// 收集为指定类型的数组
*/
public class T01_ToArray {
@Test
public void test01() {
List<Employee> list = Employee.getList();
Object[] objects = list.stream().toArray();
for (Object object : objects) {
System.out.println(object);
}
}
@Test
public void test02() {
List<Employee> list = Employee.getList();
// Employee[] employees = list.stream().toArray(i -> new Employee[i]);
Employee[] employees = list.stream().toArray(Employee[]::new);
for (Employee employee : employees) {
System.out.println(employee.getName());
}
}
}
3、收集为集合 - 自定义收集
/*
// 9.2、收集为集合
<R> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner);// 自定义收集
Supplier<R> supplier:提供一个收集数据的容器,容器的泛型为 R。例如 ArrayList<String>、HashMap<String, Employee>。
BiConsumer<R, ? super T> accumulator:如何给容器添加数据,添加什么数据,容器的泛型为 R,流的泛型为 T。
BiConsumer<R, R> combiner:如何将多个容器合并,容器的泛型为 R。
*/
public class T02_Collect01 {
@Test
public void test01() {
List<Employee> list = Employee.getList();
ArrayList<String> arrayList = list.stream().collect(
ArrayList::new,
(nameArrayList, e) -> nameArrayList.add(e.getName()),
ArrayList::addAll);
arrayList.forEach(System.out::println);
}
@Test
public void test02() {
List<Employee> list = Employee.getList();
HashMap<String, Employee> hashMap = list.stream().collect(
HashMap::new,
(nameHashMap, e) -> nameHashMap.put(e.getName(), e),
HashMap::putAll
);
hashMap.forEach((k, v) -> System.out.println(k + "::" + v));
}
}
4、收集为集合 - 指定收集器收集
package T19_Stream.T14_Collect;
import T19_Stream.Employee;
import org.junit.Test;
import java.util.*;
import java.util.stream.Collectors;
/*
Stream 接口
<R, A> R collect(Collector<? super T, A, R> collector);// 指定收集器收集
Collectors 类 - 收集器工具类
*/
public class T03_Collect02 {
// 1.1、收集为指定 Collection、List、Set
@Test
public void test01() {
List<Employee> employees = Employee.getList();
ArrayList<Employee> arrayList = employees.stream().collect(Collectors.toCollection(ArrayList::new));
List<Employee> list = employees.stream().collect(Collectors.toList());
Set<Employee> set = employees.stream().collect(Collectors.toSet());
}
// 1.2、收集为 Map
@Test
public void test02() {
List<Employee> employees = Employee.getList();
Map<String, Integer> map1 = employees.stream().collect(Collectors.toMap(Employee::getName, Employee::getAge));
System.out.println(map1);
Map<Integer, String> map2 = employees.stream().collect(Collectors.toMap(Employee::getAge, Employee::getName, (o1, o2) -> o1));
System.out.println(map2);
HashMap<Integer, String> map3 = employees.stream().collect(Collectors.toMap(Employee::getAge, Employee::getName, (o1, o2) -> o1, HashMap::new));
System.out.println(map3);
}
// 2、字符串连接
@Test
public void test03() {
List<Employee> employees = Employee.getList();
String s1 = employees.stream().map(Employee::getName).collect(Collectors.joining());
System.out.println(s1);
String s2 = employees.stream().map(Employee::getName).collect(Collectors.joining("-"));
System.out.println(s2);
String s3 = employees.stream().map(Employee::getName).collect(Collectors.joining("-", "开始<", ">结束"));
System.out.println(s3);
}
// 3、统计:计数、最小、最大、求和、平均、统计所有
@Test
public void test04() {
List<Employee> list = Employee.getList();
// 计数
Long count = list.stream().collect(Collectors.counting());
System.out.println(count);
// 最小
Optional<Employee> min = list.stream().collect(Collectors.minBy((o1, o2) -> o1.getAge() - o2.getAge()));
System.out.println(min.get());
// 最大
Optional<Employee> max = list.stream().collect(Collectors.maxBy((o1, o2) -> o1.getAge() - o2.getAge()));
System.out.println(max.get());
// 求和
int sum = list.stream().collect(Collectors.summingInt(Employee::getAge));
System.out.println(sum);
// 平均
double avg = list.stream().collect(Collectors.averagingInt(Employee::getAge));
System.out.println(avg);
// 统计所有
IntSummaryStatistics summary = list.stream().collect(Collectors.summarizingInt(Employee::getAge));
System.out.println(summary);
}
/*
// 归纳
public static <T> Collector<T, ?, T> reducing(T identity, BinaryOperator<T> op) {}
public static <T> Collector<T, ?, Optional<T>> reducing(BinaryOperator<T> op) {}
public static <T, U> Collector<T, ?, U> reducing(U identity, Function<? super T, ? extends U> mapper, BinaryOperator<U> op) {}
*/
// 4、归纳
@Test
public void test05() {
List<Employee> employees = Employee.getList();
Integer sum1 = employees.stream().map(Employee::getAge).collect(Collectors.reducing(100, Integer::sum));
System.out.println(sum1);
Optional<Integer> sum2 = employees.stream().map(Employee::getAge).collect(Collectors.reducing(Integer::sum));
System.out.println(sum2.get());
Integer sum3 = employees.stream().map(Employee::getSalary).collect(Collectors.reducing(0, Double::intValue, Integer::sum));
System.out.println(sum3);
}
/*
// 5.1、分组:返回 Map
public static <T, K> Collector<T, ?, Map<K, List<T>>> groupingBy(
Function<? super T,
? extends K> classifier) {}
public static <T, K, A, D> Collector<T, ?, Map<K, D>> groupingBy(
Function<? super T, ? extends K> classifier,
Collector<? super T, A, D> downstream) {}
public static <T, K, D, A, M extends Map<K, D>> Collector<T, ?, M> groupingBy(
Function<? super T, ? extends K> classifier,
Supplier<M> mapFactory,
Collector<? super T, A, D> downstream) {}
*/
@Test
public void test06() {
List<Employee> employees = Employee.getList();
// Map<String, List<Employee>> map = employees.stream().collect(Collectors.groupingBy(Employee::getGender));
// map.forEach((k, v) -> System.out.println(k + "::" + v));
// Map<String, Map<Integer, List<Employee>>> map2 = employees.stream().collect(Collectors.groupingBy(Employee::getGender, Collectors.groupingBy(Employee::getAge)));
// map2.forEach((k, v) -> {
// System.out.println(k);
// v.forEach((k1, v1) -> System.out.println("\t" + k1 + "::" + v1));
// });
HashMap<String, Map<Integer, List<Employee>>> map3 = employees.stream().collect(Collectors.groupingBy(Employee::getGender, HashMap::new, Collectors.groupingBy(Employee::getAge)));
map3.forEach((k, v) -> {
System.out.println(k);
v.forEach((k1, v1) -> System.out.println("\t" + k1 + "::" + v1));
});
}
/*
// 6、分区
public static <T> Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(
Predicate<? super T> predicate) {}
public static <T, D, A> Collector<T, ?, Map<Boolean, D>> partitioningBy(
Predicate<? super T> predicate,
Collector<? super T, A, D> downstream) {}
*/
@Test
public void test07() {
List<Employee> employees = Employee.getList();
// Map<Boolean, List<Employee>> map1 = employees.stream().collect(Collectors.partitioningBy(e -> e.getSalary() > 4500.0D));
// System.out.println("薪资是否超过 4500:");
// map1.forEach((k, v) -> {
// System.out.println(k + "::" + v);
// });
Map<Boolean, Map<Boolean, List<Employee>>> map2 = employees.stream().collect(Collectors.partitioningBy(e -> e.getSalary() >= 4500.0D, Collectors.partitioningBy(e -> e.getAge() >= 20)));
System.out.println("薪资是否超过 4500");
map2.forEach((k, v) -> {
System.out.println(k);
System.out.println("\t年龄是否超过 20");
v.forEach((k1, v1) -> {
System.out.println("\t" + k1 + "::" + v1);
});
});
}
/*
// 7、映射
public static <T, U, A, R> Collector<T, ?, R> mapping(Function<? super T, ? extends U> mapper, Collector<? super U, A, R> downstream) {}
*/
@Test
public void test08() {
List<Employee> list = Employee.getList();
Map<Boolean, List<Integer>> map = list.stream().collect(Collectors.mapping(Employee::getAge, Collectors.partitioningBy(integer -> integer >= 20)));
map.forEach((k, v) -> System.out.println(k + "::" + v));
}
/*
// 8、收集,然后执行 Function
public static <T,A,R,RR> Collector<T,A,RR> collectingAndThen(Collector<T,A,R> downstream, Function<R,RR> finisher) {}
*/
@Test
public void test09() {
List<Employee> list = Employee.getList();
Object[] collect = list.stream().collect(Collectors.collectingAndThen(Collectors.mapping(Employee::getGender, Collectors.toList()), ls -> ls.toArray()));
System.out.println(collect.length);
}
}