结合Junit测试类的注解和代码,就不难发现,jdk8默认的map流收集器是会抛出异常的,跟普通的hashmap不一样,不符合业务逻辑习惯,需要对它进行修改一下才能使用,或者使用for循环也可以.
package com.gupaoedu.vip.pattern.strategy;
import org.junit.Before;
import org.junit.Test;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.Collectors;
public class TestTest {
List<User> users = new ArrayList<>();
@Before
public void before(){
User user1 = new User(); user1.setName("小明"); user1.setAge(6);
User user2 = new User(); user2.setName("小明"); user2.setAge(8);//一个重复的key
User user3 = new User(); user3.setName("小红"); user3.setAge(null);//一个空value
users.add(user1);
users.add(user2);
users.add(user3);
}
/**
* 不可以有重复key,不可以有null值
*/
@Test
public void one(){
Map<String, Integer> collect = users.stream().collect(Collectors.toMap(User::getName, User::getAge));
}
/**
* 可以有重复key,但不可以有null值
*/
@Test
public void two(){
Map<String, Integer> collect =
users.stream().collect(Collectors.toMap(User::getName, User::getAge, (k1, k2) -> k2));
}
/**
* 可以有重复key,可以有null值
*/
@Test
public void three(){
HashMap<Object, Object> collect =
users.stream().collect(HashMap::new, (m, v) -> m.put(v.getName(), v.getAge()), HashMap::putAll);
System.out.println(collect);//{小明=8, 小红=null}
}
/**
* 可以有重复key,可以有null值,自定义一个Collectors的实现类
*/
@Test
public void four(){
Map<String, Integer> collect = users.stream().collect(new MyMapCollector());
System.out.println(collect);//{小明=8, 小红=null}
}
/**
* 可以有重复key,可以有null值
*/
@Test
public void five(){
Map<String, Integer> collect = users.stream().collect(this.toMap(User::getName, User::getAge));
System.out.println(collect);//{小明=8, 小红=null}
}
public <T, K, U>Collector<T, ? , Map<K, U>> toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper){
return Collectors.collectingAndThen(Collectors.toList(), list -> {
Map<K, U> result = new HashMap<>();
for (T t : list) {
K key = keyMapper.apply(t);
result.put(key, valueMapper.apply(t));
}
return result;
});
}
}
package com.gupaoedu.vip.pattern.strategy;
import lombok.Data;
import lombok.ToString;
@ToString
@Data
class User {
//姓名
private String name;
//年龄
private Integer age;
}
package com.gupaoedu.vip.pattern.strategy;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;
public class MyMapCollector implements Collector<com.gupaoedu.vip.pattern.strategy.User, Map<String, Integer>, Map<String, Integer>> {
@Override
public Supplier<Map<String, Integer>> supplier() {
System.out.println("用于创建并返回一个可变的结果容器");
return HashMap<String, Integer>::new;
}
@Override
public BiConsumer<Map<String, Integer>, com.gupaoedu.vip.pattern.strategy.User> accumulator() {
System.out.println("可以将元素累加到可变的结果容器中,也就是supplier()返回的容器");
return (m, t) -> {
m.put(t.getName(), t.getAge());
};
}
@Override
public BinaryOperator<Map<String, Integer>> combiner() {
System.out.println("将两部分结果容器(也就是supplier()返回的容器)合并起来," +
"可以是将一个结果容器合并到另一个结果容器中,也可以是将两个结果容器合并到一个新的空结果容器");
return (Map<String, Integer> s1, Map<String, Integer> s2) -> {
s1.putAll(s2);
return s1;
};
}
@Override
public Function<Map<String, Integer>, Map<String, Integer>> finisher() {
System.out.println("执行最终的转换,将中间结果类型转换成最终的结果类型");
return Function.identity();
}
/**
* 表示这个收集器的特征
* Characteristics
* CONCURRENT:
* 这个表示一个结果容器可以到个线程调用, 要保证线程安全 他和并行流是不一样的 如果这个收集器不是UNORDERED 那么仅能用于无序的数据源
* UNORDERED:
* 他并不保证输入元素的顺序 也就是无序的
* IDENTITY_FINISH:
* 标识的是: finisher 就是 identity函数 就是收集器的的类型和结果的类型相同 但是必须要保证 A 转换成 R 类型是成功的
* ---------------------------------
* 如果不满足以上三个条件 那么就直接返回一个空的set集合就可以了
*
* @return result
*/
@Override
public Set<Characteristics> characteristics() {
System.out.println("收集器的特性集合 不同的特性执行机制也不同");
EnumSet<Characteristics> characteristicsEnumSet = EnumSet.of(Characteristics.UNORDERED,
Characteristics.IDENTITY_FINISH);//remove IDENTITY_FINISH finisher method will be invoked
return Collections.unmodifiableSet(characteristicsEnumSet);
}
}