[TOC]java
這一系列文章旨在幫助你們理解 Collector
的執行流程,至於實現的是否高效、是否優雅、是否合理等暫且不論。git
如今來實現一個和 java.util.stream.Collectors#groupingBy()
同樣效果的 GroupByCollector
。github
固然此處的實現確定沒有jdk那樣靈活,效率就先不提了,至少貧道的這個實現不支持多級分組V_V。app
若對 Collector
的各個流程有疑問請移駕此處:http://blog.csdn.net/hylexus/...ide
// 這個是從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; } }
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(1, "java", 1, 25), new User(2, "C", 1, 22), new User(3, "scala", 0, 23), new User(4, "C++", 0, 11), new User(5, "Spark", 1, 25), new User(6, "PHP", 0, 45), new User(7, "Python", 1, 89), new User(8, "JavaScript", 0, 110), new User(9, "C#", 1, 33) ); 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); }
0 User{id=3, name='scala', gender=0, age=23} User{id=4, name='C++', gender=0, age=11} User{id=6, name='PHP', gender=0, age=45} User{id=8, name='JavaScript', gender=0, age=110} 1 User{id=1, name='java', gender=1, age=25} User{id=2, name='C', gender=1, age=22} User{id=5, name='Spark', gender=1, age=25} User{id=7, name='Python', gender=1, age=89} User{id=9, name='C#', gender=1, age=33}