文章目录
1 使用的实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
@String
public class User(){
private String userId;
private String userName;
private Integer userAge;
}
2 利用Collectors.toMap去重
2.1 toMap去重说明
List<User> userList = new ArrayList<>();
userList.add(new User("a", "xiaoming",12));
userList.add(new User("b", "xiaoming",13));
userList.add(new User("d", "xiaoming",15));
userList.add(new User("a", "xiaoming",14));
System.out.println("利用Collectors.toMap去重:");
//利用Collectors.toMap去重
userList.stream()
.collect(Collectors.toMap(User::getUserId,
Function.identity(), (oldValue, newValue) -> oldValue))
.values()
.stream()
.forEach(System.out::println); //打印
输出结果:
[{"userAge":12,"userId":"a","userName":"xiaoming"},
{"userAge":13,"userId":"b","userName":"xiaoming"},
{"userAge":15,"userId":"d","userName":"xiaoming"}]
其中,Collectors.toMap
需要使用三个参数的版本,前两个参数一个是keyMapper
函数一个是valueMapper
函数的,用过toMap
的都知道,去重的关键在于第三个参数BinaryOperator
函数接口。
这个BinaryOperator
函数接收两个参数,如上面代码,一个oldValue
,一个newValue
,字面意思,第一个旧值,第二个是新值。当stream
构造Map时,会先调用Map的get方法获取该key对应节点的旧值,如果该值为null,则不会调用BinaryOperator
函数,如果不为null,则会把获取的旧值与新值作为参数传给函数执行,然后把函数的返回值作为新值put到Map中。如果看不懂,请看源码吧
2.2 Funcion.identity()解释
Java 8允许在接口中加入具体方法。接口中的具体方法有两种,default
方法和static
方法,identity()
就是Function
接口的一个静态方法
。
Function.identity()
返回一个输出跟输入一样的Lambda
表达式对象,等价于形如t -> t
形式的Lambda
表达式。
identity()
方法JDK源码如下:
static Function identity() {
return t -> t;
}
下面的代码中,Task::getTitle
需要一个task
并产生一个仅有一个标题的key
task -> task
是一个用来返回自己的lambda
表达式,上例中返回一个task
private static Map<String, Task> taskMap(List<Task> tasks) {
return tasks.stream().collect(toMap(Task::getTitle, task -> task));
}
可以使用Function
接口中的默认方法identity
来让上面的代码代码变得更简洁明了、传递开发者意图时更加直接,下面是采用identity函数的代码。
import static java.util.function.Function.identity;
private static Map<String, Task> taskMap(List<Task> tasks) {
return tasks.stream().collect(toMap(Task::getTitle, identity()));
}
3 利用Collectors.toCollection和TreeSet去重
List<User> userList = new ArrayList<>();
userList.add(new User("a", "xiaoming",12));
userList.add(new User("b", "xiaoming",13));
userList.add(new User("d", "xiaoming",15));
userList.add(new User("a", "xiaoming",14));
System.out.println("利用Collectors.toMap去重:");
//利用Collectors.toMap去重
userList.stream()
.collect(Collectors.toCollection(() ->
new TreeSet<>(Comparator.comparing(User::getUserId))))
.values()
.stream()
.forEach(System.out::println); //打印
输出结果:
[{"userAge":12,"userId":"a","userName":"xiaoming"},
{"userAge":13,"userId":"b","userName":"xiaoming"},
{"userAge":15,"userId":"d","userName":"xiaoming"}]
利用TreeSet
原理去重,TreeSet
内部使用的是TreeMap
,使用指定Comparator
比较元素,如果元素相同,则新元素代替旧元素,
TreeMap
的put
方法来放入元素的,有兴趣可以自己找源码
如果不想要返回TreeSet
类型,那也可以使用Collectors.collectingAndThen
转换成ArrayList
,也可以用new ArrayList(set)
,原理一样,如下:
List<Person> distinctList = personList.stream()
.collect(Collectors.collectingAndThen(Collectors.toCollection(()
-> new TreeSet<>(Comparator.comparing(User::getUserId))), ArrayList::new));