java8-08-自定義Collector-groupBy

[TOC]

聲明

這一系列文章旨在幫助大家理解 Collector 的執(zhí)行流程,至于實現(xiàn)的是否高效辟犀、是否優(yōu)雅俏竞、是否合理等暫且不論。


現(xiàn)在來實現(xiàn)一個和 java.util.stream.Collectors#groupingBy() 一樣效果的 GroupByCollector

當(dāng)然此處的實現(xiàn)肯定沒有jdk那樣靈活魂毁,效率就先不提了玻佩,至少貧道的這個實現(xiàn)不支持多級分組V_V。

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

簡單實現(xiàn)

// 這個是從jdk8源碼里提出來的一個 Characteristics
// 只包含一個恒等函數(shù)的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(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}

博客源碼

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末席楚,一起剝皮案震驚了整個濱河市咬崔,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌烦秩,老刑警劉巖垮斯,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異只祠,居然都是意外死亡兜蠕,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進店門抛寝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來牺氨,“玉大人,你說我怎么就攤上這事墩剖。” “怎么了夷狰?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵岭皂,是天一觀的道長。 經(jīng)常有香客問我沼头,道長爷绘,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任进倍,我火速辦了婚禮土至,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘猾昆。我一直安慰自己陶因,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布垂蜗。 她就那樣靜靜地躺著楷扬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪贴见。 梳的紋絲不亂的頭發(fā)上烘苹,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天,我揣著相機與錄音片部,去河邊找鬼镣衡。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的廊鸥。 我是一名探鬼主播望浩,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼黍图!你這毒婦竟也來了曾雕?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤助被,失蹤者是張志新(化名)和其女友劉穎剖张,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體揩环,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡搔弄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了丰滑。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片顾犹。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖褒墨,靈堂內(nèi)的尸體忽然破棺而出炫刷,到底是詐尸還是另有隱情,我是刑警寧澤郁妈,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布浑玛,位于F島的核電站,受9級特大地震影響噩咪,放射性物質(zhì)發(fā)生泄漏顾彰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一胃碾、第九天 我趴在偏房一處隱蔽的房頂上張望涨享。 院中可真熱鬧,春花似錦仆百、人聲如沸厕隧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽栏账。三九已至,卻和暖如春栈源,著一層夾襖步出監(jiān)牢的瞬間挡爵,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工甚垦, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留茶鹃,地道東北人涣雕。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像闭翩,于是被迫代替她去往敵國和親挣郭。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,611評論 2 353

推薦閱讀更多精彩內(nèi)容