天天看點

java8-08-自定義Collector-groupBy聲明簡單實作簡化代碼使用自定義Collector部落格源碼

  • 聲明
  • 簡單實作
  • 簡化代碼
  • 使用自定義Collector
  • 部落格源碼

聲明

這一系列文章旨在幫助大家了解

Collector

的執行流程,至于實作的是否高效、是否優雅、是否合理等暫且不論。

現在來實作一個和

java.util.stream.Collectors#groupingBy()

一樣效果的

GroupByCollector

當然此處的實作肯定沒有jdk那樣靈活,效率就先不提了,至少貧道的這個實作不支援多級分組V_V。

若對

Collector

的各個流程有疑問請移駕此處:http://blog.csdn.net/hylexus/article/details/78941843

簡單實作

// 這個是從jdk8源碼裡提出來的一個 Characteristics
// 隻包含一個恒等函數的Characteristics
static final Set<Collector.Characteristics> CH_ID
        = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH));
           
static class GroupByCollector<T, K> implements Collector<T, Map<K, List<T>>, Map<K, List<T>>> {

    Function<T, K> classifier;

    public GroupByCollector(Function<T, K> classifier) {
        this.classifier = classifier;
    }

    @Override
    public Supplier<Map<K, List<T>>> supplier() {
        return () -> new HashMap<>();
    }

    @Override
    public BiConsumer<Map<K, List<T>>, T> accumulator() {
        return (map, e) -> {
            K key = classifier.apply(e);
            List<T> value = map.get(key);
            if (map.get(key) == null) {
                map.put(key, Lists.newArrayList());
            }

            map.get(key).add(e);
        };
    }

    @Override
    public BinaryOperator<Map<K, List<T>>> combiner() {
        return (map1, map2) -> {
            map2.forEach((k, v) -> {
                if (map1.get(k) == null) {
                    map1.put(k, v);
                } else {
                    map1.get(k).addAll(v);
                }
            });
            return map1;
        };
    }

    @Override
    public Function<Map<K, List<T>>, Map<K, List<T>>> finisher() {
        return Function.identity();
    }

    @Override
    public Set<Characteristics> characteristics() {
        return CH_ID;
    }
}
           

簡化代碼

static class GroupByCollector2<T, K> implements Collector<T, Map<K, List<T>>, Map<K, List<T>>> {
    Function<T, K> classifier;

    public GroupByCollector2(Function<T, K> classifier) {
        this.classifier = classifier;
    }

    @Override
    public Supplier<Map<K, List<T>>> supplier() {
        return HashMap::new;
    }

    @Override
    public BiConsumer<Map<K, List<T>>, T> accumulator() {
        return (map, e) -> {
            K key = classifier.apply(e);
            List<T> value = Optional.ofNullable(map)
              .map(m -> m.get(key)).orElse(Lists.newArrayList());
            value.add(e);
            map.put(key, value);
        };
    }

    @Override
    public BinaryOperator<Map<K, List<T>>> combiner() {
        return (m1, m2) -> {
            m2.forEach((k, v) -> {
                List<T> value = Optional.ofNullable(m1)
                  .map(m -> m.get(k)).orElse(Lists.newArrayList());
                value.addAll(v);
                m1.put(k, value);
            });

            return m1;
        };
    }

    @Override
    public Function<Map<K, List<T>>, Map<K, List<T>>> finisher() {
        return Function.identity();
    }

    @Override
    public Set<Characteristics> characteristics() {
        return CH_ID;
    }
}
           

使用自定義Collector

static class User {
    private Integer id;
    private String name;
    private Integer gender;
    private Integer age;

    User(Integer id, String name, Integer gender, Integer age) {
        this.id = id;
        this.name = name;
        this.gender = gender;
        this.age = age;
    }
    // getter,setter
}

List<User> users = Lists.newArrayList(
        new User(, "java", , ),
        new User(, "C", , ),
        new User(, "scala", , ),
        new User(, "C++", , ),
        new User(, "Spark", , ),
        new User(, "PHP", , ),
        new User(, "Python", , ),
        new User(, "JavaScript", , ),
        new User(, "C#", , )
);

void printUserMap(Map<Integer, List<User>> map) {
    map.forEach((k, v) -> {
        System.out.println(k);
        v.forEach(e-> System.out.println("\t"+e));
    });
}

@Test
public void test2() {
    Map<Integer, List<User>> map = users.stream()
      .collect(Collectors.groupingBy(User::getGender));
    printUserMap(map);

    map = users.stream().
      collect(new GroupByCollector<>(User::getGender));
    printUserMap(map);

    map = users.stream().collect(new GroupByCollector2<>(User::getGender));
    printUserMap(map);

}
           
  • 輸出效果
User{id=, name='scala', gender=, age=}
    User{id=, name='C++', gender=, age=}
    User{id=, name='PHP', gender=, age=}
    User{id=, name='JavaScript', gender=, age=}

    User{id=, name='java', gender=, age=}
    User{id=, name='C', gender=, age=}
    User{id=, name='Spark', gender=, age=}
    User{id=, name='Python', gender=, age=}
    User{id=, name='C#', gender=1, age=33}
           

部落格源碼

https://github.com/hylexus/blog-src/blob/master/java-core/src/test/java/cn/hylexus/lambda/CollectorTest.java