概述
- Java8(又称JDK1.8)是Java语言开发的一个重要版本,Oracle公司于2014年3月发布,可以看成是自Java5以来最具革命性的版本
- Java8有两大最重要的改变,第一个是
Lambda表达式
,另外一个就是Stream API
1、Lambda表达式&函数式接口
1.1概述
函数式接口概述
- 一个接口中只声明一个
抽象
方法(Since JDK1.8) 一般都有FunctionalInterface注解 - 重写了超类Object类中任意一个public方法的方法并不算接口中的抽象方法,因为任何接口的实现都会从其父类Object或其它地方获得这些方法的实现,比如我们在Comparator接口中可以发现里面有两个抽象方法,所以说Comparator的抽象方法就是compare(T o1, T o2)
@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
boolean equals(Object obj);
}
- 比如Runnable接口 Callable接口 。。。
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
@FunctionalInterface
public interface Callable<V> {
V call() throws Exception;
}
@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
}
Lambda表达式概述
- Lambda表达式的本质:
函数式接口的一个匿名实现类对象(重写接口中的抽象方法)
即Lambda必须依赖于函数式接口
1.2基本格式与使用要求
基本格式
(var field1,var field2...)-> {xxxxxx....}
左边:Lambda形参列表(就是接口抽象方法的形参列表)
中间: -> Lambda操作符
右边:Lambda体,就是重写抽象方法的方法体
要求:
- 接口必须是
函数式接口
,即接口中只能
有一个抽象
方法,如果接口有泛型的话,泛型必须使用在抽象方法的返回值或者参数类型上(便于Lambda的类型推断)
1.3使用的四种情况
1. 无参无返回值
格式:参数列表只写一个括号,右边写方法体
- 如果有多条语句大括号不能省,
- 如果只有一条语句大括号可以省略。
//方法体有多条语句
()->{语句1;语句2;....};
//方法体只有一条语句 省略大括号
()->语句;
举例:
@Test
public void test1() {
-----------原始写法----------------------
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("ssd");
System.out.println("sdsd");
}
};
-------------Lambda改造后 (这里有两条语句) 所以大括号不能省------
Runnable lambdaRunnable = () -> {
System.out.println("sd");
System.out.println("sdsd");
};
---------方法体只有一条语句 可以省略大括号------------
Runnable lambdaRunnable2 =()->System.out.println("sd");
}
2.有一个参数,无返回值
格式:参数列表写一个参数,右边写方法体
(var field) ->{语句一,语句二... };
简化:
//如果指定了泛型,参数的数据类型可以省略,小括号也可以省略,类型推断
Ca<T> c = field -> {语句一,语句二...};
//同样的,如果方法体只有一条语句,大括号可以省略
Ca<T> c = field -> 语句一;
举例
@Test
public void test2(){
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println("sxxx");
}
};
--------------------------------Lambda表达式改造后---------------------------
//指定了泛型是String 则后面的str的类型可以省略,因为参数的类型就是类上的泛型,类型推断
Consumer<String> consumer1 = str ->System.out.println(str);
}
3.有一个参数,有返回值
格式:参数列表写一个参数,右边写方法体
(var field) ->{语句一,语句二... return xx;};
简化
//省略参数类型和小括号,
field ->{语句一,语句二... return xx; };
//只有一条return语句时,可以省略大括号和return关键字
field ->return xx;
举例
自定义一个函数式 有一个参数和返回值
@FunctionalInterface
public interface InterfaceTest<T> {
T has(T t);
}
@Test
public void test3() {
---原始写法--------
InterfaceTest<String> interfaceTest = new InterfaceTest<String>() {
@Override
public String has(String str) {
return str;
}
};
---改造后-------
--------多条语句---------
InterfaceTest<String> interfaceTest1 = str -> {
System.out.println("xxxx");
...
return str;
};
-----------只有一条return语句 省略大括号和return关键字-----------------
InterfaceTest<String> interfaceTest2 = str -> str;
}
4.有两个及以上的参数,有(没有)返回值
格式:参数列表必须使用括号,参数类型可以省略
(field1,field2 ...)->{语句一,语句二,....return xx;};
//如果方法体只有一条语句可以省略大括号和return关键字(有返回值)
举例
@Test
public void test4(){
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return 0;
}
};
----------Lambda改造后--------------------------------
Comparator<Integer> tComparator = (o1, o2) -> 1;
}
5.总结:
关于参数列表
1、参数类型都
可以省略(类型推断)
2、如果参数列表中只有一个参数,小括号可以省略
3、如果没有参数
或者有两个以上的参数
小括号不能省略
关于方法体的总结
1、Lambda一般使用大括号{}进行包裹
- —如果只有一条语句
可以省略大括号和return关键字(有返回值的话)
-----------------------强制要求:(如果省略了return关键字,那么必须省略大括号) - 如果有多条语句那么任何符号都不能省略(大括号,return关键字)
1.4四大函数式接口及方法引用
1.4.1接口基本概述
函数式接口 | 抽象方法 | 用途 |
---|---|---|
消费型接口Consumer | void accept(T t) | 为类型为T的对象进行操作,没有返回值 |
供给型接口Supplier | T get() | 返回类型为T的对象 |
函数型接口Function<T,R> | R apply(T t) | 为类型为T的对象进行操作,操作完成返回类型是R的对象 |
断定型接口Predicate | boolean test (T t) | 判断类型为T的对象是否满足某个条件 返回一个boolean值 |
1.4.2方法应用与构造器引用概述
-
当要传递给Lambda体(即实现函数式接口后的方法体)的操作已经有实现的方法了,就可以使用方法引用
-
方法引用可以看做是Lambda表达式深层次的表达,换句话说,方法引用就是Lambda表达式,也就是函数式接口的一个实例,通过方法的名字来执行一个方法,可以认为是Lambda表达式的的一个语法糖
-
要求:==函数式接口的抽象方法的参数列表和返回值类型必须和方法引用的方法的参数列表和返回值保持一致!==针对情况1和2
-
格式:使用操作符
::
将类或对象与方法名分隔开来 -
如下三种主要的使用情况
1、对象::实例方法名
2、类::静态方法名
3、类::实例方法名
1.4.3详讲四大接口与方法应用
1、使用对象::非静态方法名
Consumer接口
源码:
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
基本的使用
/**
* Consumer<T>接口的测试及应用
* void accept(T t)
* void println(T t) //跟accept方法一样 都是一个参数无返回值就可以使用方法引用
* 对象::方法名
* */
@Test
public void test(){
Consumer<String> consumer = str->System.out.println(str);
Consumer<String> consumerM = System.out::println;
consumer.accept("I believe i can fly");
consumerM.accept("I have a great dream");
------实际应用 集合的一个foreach(Consumer<T> con)方法---------
List<Integer> list = new ArrayList();
for (int i = 0; i < 5; i++) {
list.add(i);
}
list.forEach(i->System.out.print(i));
list.forEach(System.out::print);
}
Supplier接口
/**
* Supplier<T>接口的测试及使用
* T get()
* 与自定义类的属性的get方法(T get())形参方法名都一样 就可以使用方法引用
* 使用 对象::方法名
* */
@Test
public void test2(){
Person person = new Person();
Supplier<String> supplierLam = ()->person.getName();
Supplier<String> supplier = person::getName;
}
2、使用类::静态方法
Comparator接口
/*
* Comparator<T>中的 int compare(T t1,T t2)
* 和Integer类中的 int compare(T t1,T t2)
* 参数和返回值一样 所以就可以使用 类::静态方法 使用方法引用
*
* */
@Test
public void test3(){
Comparator<Integer> comparator = (t1,t2)->Integer.compare(t1,t2);
Comparator<Integer> comparator1 = Integer::compare;
}
3、类::非静态方法(难点)
当函数式接口中抽象方法的第一个参数作为某一个方法的调用者出现,然后假设去掉第一个参数后就和我们的一个方法的参数列表及返回值相同,就可以使用 类::非静态方法 来进行方法引用
通俗的说就是
R get(T t); //抽象方法 R 和 T 都是泛型 在调用方法是类型才能确定
class Person {
//String test() (Person类)
String test(){
xxx..
}
}
//某个类的一个方法 这个方的返回值在声明的时候就是确定的 比如我们这里使用String作为test方法的返回值
判断A类的test方法是否可以使用 Person::test 进行 类::非静态方法
1、先判断 抽象方法的参数列表去掉一个参数(一般是参数列表的第一个参数)后是否和Person类的test方法的参数列表是一致的(只看参数个数)
1/1、如果说抽象方法和我们的真实方法的参数列表都不止一个,那么在进行第一步之后,还必须判断抽象方法剩余的参数和我们的真实方法的参数列表是否一直(包括个数和类型)
2、再次判断在调用抽象方法的过程中 R的真实类型是否是String(即返回值是否和方法一致)
3、再次判断 调用抽象方法时 参数T的真实类型是否是Person(即一个参数变成了真实方法调用者)
满足上面的三个条件 才能使用 Person::test 进行方法引用 否则不构成方法引用
举例
/**
* Comparator接口中的 int compareTo(T t1,T t2)
* (String类) int t2.compare(t2)
* 这种情况也可以使用方法引用 参数列表的一个参数作为调用者出现
即抽象方法去掉第一个参数后,就和我们的String类的方法参数和返回值相同了,即就可以使用发哪 方法引用了
满足上面的三个条件
* */
@Test
public void test4(){
Comparator<String> comparator = (t1,t2) -> t1.compareTo(t2);
Comparator<String> comparator1 = String :: compareTo;
}
/**
* Bipredicate中的 boolean(T t1,T t2)
* 和String中的boolean t1.equals(t2)
* 去掉抽象方法中的第一个参数后就和我们的equals的参数列表和返回值相同
* 就可以使用方法引用了
* */
@Test
public void test5(){
//原始写法
BiPredicate<String,String> b1 = new BiPredicate<String, String>() {
@Override
public boolean test(String s, String s2) {
return s.equals(s2);
}
};
//Lambda表达式写法
BiPredicate<String,String> biPredicate = (t1,t2)->t1.equals(t2);
//方法引用写法
BiPredicate<String,String> b = String::equals;
}
1.4.4构造器引用
和方法引用类似,函数式接口的抽象方法的形参列表和构造器的形参列表一致,抽象方法的返回值类型即为构造器所属的类的类型
//构造器引用
//Supplier中的T get()
@Test
public void test2(){
Supplier<Employee> supplier = ()-> new Employee();
Supplier<Employee> supplier1 = Employee::new;
}
//Function中的R apply(T t)
//与Employee中的有一个参数的构造器相同
@Test
public void test3(){
//普通写法
Function<String,Employee> function1 = new Function<String, Employee>() {
@Override
public Employee apply(String s) {
return new Employee(s);
}
};
//Lambda表达式写法
Function<String,Employee> function2 = str -> new Employee();
//构造器引用写法
Function<String,Employee> function3 = Employee::new;
}
//BiFunction中的R apply(T t,U u)
//Emploeyee中有 T(R r1,F f1) 两个参数的构造器,返回值
//所以可以使用构造器引用
@Test
public void test4(){
BiFunction<String,Integer,Employee> function1 = (name,age) -> new Employee(name,age);
BiFunction<String,Integer,Employee> function2 = Employee::new;
}
1.4.5数组引用
可以将数组看作是一个特殊的类,就当做是构造器引用,则写法就与构造器引用相同
@Test
public void test5(){
//普通写法
Function<Integer,Integer[]> function2 = new Function<Integer, Integer[]>() {
@Override
public Integer[] apply(Integer len) {
return new Integer[len];
}
};
//Lambda表达式写法
Function<Integer,Integer[]> function = len -> new Integer[len];
//构造器引用写法
Function<Integer,Integer[]> function1 = Integer[] :: new;
}
2、强大的StreamAPI
2.1Stream概述
- Stream API**(java.util.Stream)**把真正的函数式编程风格引入到Java中,这是目前为止对Java类库最好的补充,因为Stream API可以极大的提供Java程序员的生产力,让程序员写出高效率 干净 简洁的代码
- Stream是Java8处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的
查找
过滤
和映射
数据等操作,使用Stream API对集合数据进行操作,就类似使用SQL执行的数据库查询
,也可以使用Stream API来并行执行操作,简言之,Stream API提供了一种高效且易于使用的处理数据的方式 - Stream和Collection集合的区别,Collection是一种静态的内存数据结构,而Stream是有关计算的,前者是主要面向内存,存储在内存中,后者主要是面向
CPU
,通过CPU实现计算
什么是Stream?
是数据渠道,用于操作数据源(数组 集合等)所生成的元素系列
集合讲的是数据 Stream讲的是计算
注意:
一、Stream自己不会存储数据
二、Stream不会改变源对象
,相反,他们会返回一个持有结果的新Stream
三、Stream操作是延迟执行的,这意味着他们会等到**需要结果的时候才执行(**即终止的时候才会执中间操作链)
Stream操作的三个步骤
2.2使用
2.2.1创建Stream
方式一:通过集合
Java8中的Collection接口被拓展,提供了两个获取流的方法
default Stream<E> stream() 返回一个顺序流
default Stream<E> parallelStream() 返回一个并行流
创建
@Test
public void test1通过集合获取Stream(){
List<Employee> empList = EmployeeData.getEmployees();
// 直接调方法返回一个顺序流(顺序的操作集合中的数据)
Stream<Employee> empStream = empList.stream();
//返回一个并行流(并行的操作集合中的数据,不一定是顺序的)
Stream<Employee> empParallelSream = empList.parallelStream();
}
方式二:通过数组
通过Arrays内部的静态方法传入数组就能返回一个对象数据类型的流
public static <T> Stream<T> stream(T[] array)
获取
@Test
public void 通过数组获取Stream(){
// public static <T> Stream<T> stream(T[] array) 通过Arrays工具类的静态方法获取数组的Stream 返回对象数据类型的泛型流
int[] arr = {1,2,3,2,2};
IntStream intStream = Arrays.stream(arr);
Employee e1 = new Employee(1001, "tom");
Employee e2 = new Employee(1002, "jack");
Employee[] empArray = new Employee[]{e1,e2};
Stream<Employee> empStream = Arrays.stream(empArray);
}
方式三:通过Stream的of()方法
如果我们没有数组和集合,我们就可以直接调用Stream的of方法传入我们的数据直接获取流
public static<T> Stream<T> of(T... values)
使用
@Test
public void 通过Stream的of方法创建Stream(){
//通过传入数据,返回对应的流
Stream<Integer> integerStream = Stream.of(1, 2, 3, 3, 2, 2, 1);
Employee e1 = new Employee(1001, "tom");
Employee e2 = new Employee(1002, "jack");
Stream<Employee> employeeStream = Stream.of(e1, e2);
}
2.2.2中间链操作
概述:
- 中间操作可以链式调用,因为每一个中间方法的返回值都是一个Stream
- 在中间操作中有的方法可能参数是函数式接口,如果我们想要使用Lambda表达式或者方法引用的话,函数式接口的泛型一般的都是我们流的泛型,即
集合或者数组中的元素的类型
,所以我们可以直接使用lambda表达式或者方法引用
1.筛选与切片
filter(非常常用)
相当于SQL语句中的where后面的条件
select * from xxx where a>xx(将相当于是条件语句)
- 1、需要传入一个断定型接口的实现类,接口的泛型就是集合或者数组的元素的数据类型
- 2、返回一个Stream泛型也是集合或者数组的数据类型
作用
用于根据集合中的元素的值或者元素的某一个属性进行条件判断然后过滤出符合条件的元素
Stream<T> filter(Predicate<? super T> predicate);
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);}
应用
1、找出集合中大于3的元素
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 5, 6, 7, 8);
list.stream().filter(num -> num>3).forEach(System.out::println);
2、找出集合中员工工资大于9000的
empStream.filter(employee -> employee.getSalary()>9000).forEach(System.out::println);
limit(非常常用)
相当于是SQL语句中的limit,只要前几条记录
- 传入一个int类型的值,继续返回一个当前集合数据类型对象的Stream
作用
返回一个集合中的前maxSize条数据的一个Stream
Stream<T> limit(long maxSize);
skip
- 传入一个int类型的值,继续返回一个当前集合数据类型对象的Stream
作用
返回一个跳过(丢弃)前n条数据的一个Stream
Stream<T> skip(long n);
distinct()
- 空参 返回一个当前的流
作用
返回一个 经过比较元素的hashCode() 和 equals() 后去掉重复的元素的一个流
Stream<T> distinct();
2.映射
map(非常常用)
1、传入一个函数型接口,接口的第一个参数就是当前集合的数据类型作为抽象方法的参数的数据类型 第二个参数的数据类型R即返回类型是一个不确定的,默认就是Object
2、相当于是SQL语句中的 将集合中的所有元素看做是一张表,我们只取表中的某一列的元素,对其进行一些操作,然后返回一列操作后的集合
select 函数(name/age....) from xxx
xxx;
作用
- 返回一个当前集合的所有元素经过某种操作后的得到一个新的集合的一个流(数据类型可能发生变化)
- 通俗的讲 就是说 有一个集合里面有很多元素 你可以根据集合中的元素生成一个这个集合中的所有元素经过同一个操作后形成的新集合(新集合的数据类型可以发生改变)
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
//T默认是当前集合中的数据类型
//R 是不确定的 即可以返回一个任意数据类型的数据构成的集合 在你进行返回后判断出新集合的数据类型返回一个确定类型的一个新流
R apply(T t);
举例
应用1、给定一个泛型是String的ArrayList集合,要求返回一个新集合,且新集合的元素全部变为大写
List<String> list = Arrays.asList("aa", "Bb", "Cc", "DD");
List<String> list1 =list.stream().map(str -> str.toUpperCase).收集集合(后面讲)
应用二 给一个泛型是自定义类的集合,返回一个集合中所有对象的name属性构成的新集合
//假设有这样的一个集合
List<Employee> emps = new ArrayList();
//注意 收集之后的集合的泛型发生了变化 因为取的是name 是String类型的
//小技巧 ,一般的如果只想去取集合中对象的某一个属性而不进行操作,一般都可以使用
// 第三种方法引用 类::非静态方法名
List<String> names = emps.stream().map(Employee::getName).收集();
// select name from emoplyee 相当于这种SQL语句 从employee表中只查出所有的name
flatMap
接受一个函数作为参数,将流中的每个值都换成一个流,然后把所有流连接成一个流
总而言之就是如果操作集合的每一个元素后返回的是一个流的话,那么使用flatMap自动的把 一个个流合并成一个流,不进行流的嵌套
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
举例
processOn图
List<String> strList = Arrays.asList("aa", "bb", "cc", "dd");
//如果使用map调fromGetStream方法的话,就会把集合中的所有字符串都转换一个Stream<Character>
//然后最后收集成一个Stream 所有可以确定 是嵌套Stream<Stream<Character>>
Stream<Stream<Character>> stream = strList.stream().map(str -> fromGetStream(str));
stream.forEach(stream1 ->stream1.forEach(System.out::println));
//即map对集合中的数据都返回一个流,但是流不会合并 最终就形成了流的嵌套
//如果使用了flatMap的话,最后的返回值不会形成流的嵌套 就会把一个个的流合并成一个总的流
System.out.println("-----------");
Stream<Character> characterStream = strList.stream().flatMap(TestStream::fromGetStream);
characterStream.forEach(System.out::println);
//将一个字符串转换成对应的字符数组的一个Stream
private static Stream<Character> fromGetStream(String str){
List<Character> list = new ArrayList();
for (Character c : str.toCharArray()){
list.add(c);
}
return list.stream();
}
3.修改
peek(非常常用)
用来修改集合中的数据,返回的还是原始数据类型Stream,不会改变返回Stream的数据类型,
所以跟map的区别就在这里,map可以改变整个流的数据类型,peek只是进行修改操作
Stream<T> peek(Consumer<? super T> action);
应用:
修改集合中所有员工的姓名 实际应用时peek都会调用对象的set
方法,而map都会调用对象的get
方法
empList.stream().peek(e ->e.setName(e.getName().substring(0,2))).forEach(System.out::println);
map和peek的区别
https://blog.csdn.net/tckt75433/article/details/81510743
4.排序
sorted()(非常常用)
sorted()自然排序 使用的是类实现了Comparable接口中的方法
sorted(Comparator c)定制排序 需要传入一个Comparator接口的实现类
@Test
public void 排序(){
List<Integer> list = Arrays.asList(1, 2, 3, 3, 1, 3, 6, 7, 8);
//自然排序,默认调用的是类实现的comparable接口中的compare方法
list.stream().sorted().forEach(System.out::println);
List<Employee> empList = EmployeeData.getEmployees();
//定制排序 传入一个Comparator接口的实现类,
empList.stream().sorted((e1,e2)->Integer.compare(e1.getAge(),e2.getAge()));
}
2.2.3终止操作
终止操作意味着你调了一个终止操作的方法后,就无法在调用任何的其他方法,终止方法的返回值就是当前流最终的返回值
1.匹配与查找
allMatch
判断集合中的元素是否全部满足某一条件
boolean anyMatch(Predicate<? super T> predicate);
应用
判断集合中所有员工的年龄是否都大于30岁
List<Employee> empList = EmployeeData.getEmployees();
boolean match = empList.stream().allMatch(e -> e.getAge() > 30);
anyMatch
判断集合中的元素是否有满足某一条件的
boolean anyMatch(Predicate<? super T> predicate);
应用
:判断集合中是否有某个员工的工资大于22000
boolean anyMatch = empList.stream().anyMatch(e -> e.getSalary() > 22000);
System.out.println(anyMatch);
noneMatch
判断集合中元素是否没有符合某一条件的元素
boolean noneMatch(Predicate<? super T> predicate);
应用
判断集合中是否存在员工姓雷
boolean noneMatch = empList.stream().noneMatch(e ->e.getName().startsWith("雷"));
findFirst
返回集合中的第一个元素
Optional<T> findFirst();
findAny
随机返回一个元素
Optional<T> findAny();
count
返回集合中元素的个数
long count();
max
按照定制排序规则找出集合中最大的元素
Optional<T> max(Comparator<? super T> comparator);
min
按照定制排序规则找出集合中最大的元素
Optional<T> min(Comparator<? super T> comparator);
forEach(常用)
void forEach(Consumer<? super T> action);
2.规约
reduce(常用)
可以对集合中的数据反复结合起来进行某个操作(加减乘除等)
Optional<T> reduce(BinaryOperator<T> accumulator);
实际应用
List<Integer> list = Arrays.asList(1, 2, 3, 3, 32, 2, 1, 2, 3, 2, 33);
//计算集合中的所有元素的和 就是反复的将元素进行结合起来进行计算
Optional<Integer> reduce1 = list.stream().reduce(Integer::sum);
//计算集合中所有元素的乘积
Optional<Integer> reduce = list.stream().reduce((num1, num2) -> num1 * num2);
reduce(初始值,计算方法)
这个方法跟上面的基本都一样,只是多了一个初始值,计算时会带上这个初始值一并计算
3.收集
collect(最常用)
collect(Collector c)
-
将流转换成其他形式,接受一个Collector接口的实现,用于给Stream中的元素做汇总的方法
-
Collector接口中方法的实现决定了如何对流执行收集的操作(如收集到List,Set,Map里)
-
Collectors工具类提供了很多静态方法,可以方便的创建常见收集器实例,
常用方法如下
应用:
找出工资大于6000的员工,并收集成一个List集合
List<Employee> employeeList = empList.stream().filter(emp -> emp.getSalary() > 6000).collect(Collectors.toList());
找出工资大于6000的员工,并收集成一个Set集合
Set<Employee> employeeSet = empList.stream().filter(emp -> emp.getSalary() > 6000).collect(Collectors.toSet());
将员工的List集合转换成一个Map,key是员工的id,value就是员工对象
toMap方法需要传入两个函数型接口的实现类,就是通过操作集合中的数据得到两个值,泛型已经指定了就是集合中的元素数据类型,只需要关心返回值类型就可以
Map<Integer, Employee> collect = empList.stream().filter(emp -> emp.getSalary() > 6000).collect(Collectors.toMap(Employee::getId, emp -> emp));
toMap方法声明
Collector toMap(Function keyMapper,Function valueMapper)
应用:
找出工资大于6000的员工,并收集成一个List集合
List<Employee> employeeList = empList.stream().filter(emp -> emp.getSalary() > 6000).collect(Collectors.toList());
找出工资大于6000的员工,并收集成一个Set集合
Set<Employee> employeeSet = empList.stream().filter(emp -> emp.getSalary() > 6000).collect(Collectors.toSet());
将员工的List集合转换成一个Map,key是员工的id,value就是员工对象
toMap方法需要传入两个函数型接口的实现类,就是通过操作集合中的数据得到两个值,泛型已经指定了就是集合中的元素数据类型,只需要关心返回值类型就可以
Map<Integer, Employee> collect = empList.stream().filter(emp -> emp.getSalary() > 6000).collect(Collectors.toMap(Employee::getId, emp -> emp));
toMap方法声明
Collector toMap(Function keyMapper,Function valueMapper)