邯城往事

>>> 展颜笑夙愿,一笑泯恩仇 <<<

目录
自定义jdk8的Stream流的收集器
/  

自定义jdk8的Stream流的收集器

结合Junit测试类的注解和代码,就不难发现,jdk8默认的map流收集器是会抛出异常的,跟普通的hashmap不一样,不符合业务逻辑习惯,需要对它进行修改一下才能使用,或者使用for循环也可以.

Junit测试类
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;
        });
    }
}
User类
package com.gupaoedu.vip.pattern.strategy;

import lombok.Data;
import lombok.ToString;

@ToString
@Data
class User {
    //姓名
    private String name;
    //年龄
    private Integer age;
}
自定义的map收集器
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);
    }
}
评论
取消