成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Java8 collector接口的定制實(shí)現(xiàn)

zhangwang / 3410人閱讀

摘要:寫這個(gè)文章其實(shí)主要是因?yàn)閯傆袀€(gè)童鞋問(wèn)了個(gè)問(wèn)題正寫的帶勁安利的實(shí)現(xiàn)方式,結(jié)果還沒(méi)寫完無(wú)意發(fā)現(xiàn)問(wèn)題被關(guān)閉了哎都寫了一半了又不想放棄,就干脆寫成文章問(wèn)題主要就是把集合里的數(shù)據(jù)按照一定大小順序平均分成若干組的問(wèn)題,看起來(lái)挺簡(jiǎn)單的,不過(guò)我開始看到就想

寫這個(gè)文章其實(shí)主要是因?yàn)閯傆袀€(gè)童鞋問(wèn)了個(gè)問(wèn)題https://segmentfault.com/q/10...
正寫的帶勁安利Java8的實(shí)現(xiàn)方式,結(jié)果還沒(méi)寫完...無(wú)意發(fā)現(xiàn)問(wèn)題被關(guān)閉了...哎...都寫了一半了...又不想放棄,就干脆寫成文章

問(wèn)題主要就是把集合里的數(shù)據(jù)按照一定大小順序平均分成若干組的問(wèn)題,看起來(lái)挺簡(jiǎn)單的,不過(guò)我開始看到就想用用stream來(lái)實(shí)現(xiàn),但是想了想Collectors里并沒(méi)有適合的方法,所以就想到了用定制的collector來(lái)實(shí)現(xiàn)了。
原問(wèn)題的截圖:

正式開始回答(我是直接把之前的回答copy過(guò)來(lái)的哈):

集合處理的話,我還是推薦Java8stream,題主這個(gè)問(wèn)題設(shè)計(jì)到分組,那自然就要涉及到streamcollect方法了,這個(gè)方法是收集數(shù)據(jù)的意思,該方法的參數(shù)就是一個(gè)Collector接口,只要傳入一個(gè)Collector的實(shí)現(xiàn)類就可以了,常用的實(shí)現(xiàn)比如在工具類Collectors里有toList,toMap等,已經(jīng)幫你默認(rèn)寫了收集為集合或者M(jìn)ap的實(shí)現(xiàn)類了,但是明顯這些實(shí)現(xiàn)類都不合適,所以這里需要定制一個(gè)Collector接口的實(shí)現(xiàn)啦

其實(shí)就是仿照Collectors里的內(nèi)部類CollectorImpl寫一個(gè)就是了...

=====================(Collector介紹,如果你已經(jīng)清楚可以略過(guò)的...)==================

介紹哈Collector接口的方法,一共5個(gè)

Supplier supplier()
BiConsumer accumulator()
BinaryOperator combiner()
Function finisher()
Set characteristics()

方法中有泛型,所以要先要介紹哈Collector中的三個(gè)泛型T, A, R
Tstream在調(diào)用collect方法收集前的數(shù)據(jù)類型
AAT的累加器,遍歷T的時(shí)候,會(huì)把T按照一定的方式添加到A中,換句話說(shuō)就是把一些T通過(guò)一種方式變成A
RR可以看成是A的累加器,是最終的結(jié)果,是把A匯聚之后的數(shù)據(jù)類型,換句話說(shuō)就是把一些A通過(guò)一種方式變成R

了解了泛型的意思,咱們結(jié)合Collectors.toList構(gòu)造的默認(rèn)實(shí)現(xiàn)類的實(shí)現(xiàn)方式來(lái)看看Collector接口的方法

public static 
    Collector> toList() {
        return new CollectorImpl<>((Supplier>) ArrayList::new, List::add,
                                   (left, right) -> { left.addAll(right); return left; },
                                   CH_ID);
    }

官方寫的很簡(jiǎn)單,很隨意...

前三個(gè)參數(shù)分別對(duì)應(yīng)了Collector的前三個(gè)方法,也就是

(Supplier>) ArrayList::new 對(duì)應(yīng)Supplier supplier()第一個(gè)方法
List::add 對(duì)應(yīng)BiConsumer accumulator()第二個(gè)方法
(left, right) -> { left.addAll(right); return left; }對(duì)應(yīng)BinaryOperator
combiner()第三個(gè)方法

所以對(duì)應(yīng)著來(lái)看就清楚了
Supplier
supplier() 怎么創(chuàng)建一個(gè)累加器(這里對(duì)應(yīng)的是如何創(chuàng)建一個(gè)List
BiConsumer accumulator()怎么把一個(gè)對(duì)象添加到累加器中(這里對(duì)應(yīng)的是如何在List里添加一個(gè)對(duì)象,當(dāng)然是調(diào)用add方法咯)
BinaryOperator
combiner()怎么把一個(gè)累加器和另一個(gè)累加器合并起來(lái)(這里對(duì)應(yīng)的是如何把ListList合并起來(lái),當(dāng)然是調(diào)用addAll,這里由于最終要返回List,所以A和R是一個(gè)類型,都是List所以才調(diào)用addAll

再來(lái)看看第四個(gè)方法Function finisher(),其實(shí)就是怎么把A轉(zhuǎn)化為R,由于是toList,所以AR是一樣的類型,這里其實(shí)用就是Function.identity
最后第五個(gè)方法Set characteristics()其實(shí)就是這個(gè)Collector的一些性質(zhì),toList這里只用了Characteristics.IDENTITY_FINISH,表示第四個(gè)方法可以不用設(shè)置,A類型就是最終的結(jié)果

=====================(Collector介紹完了)==================

現(xiàn)在創(chuàng)建自定義的collector,類名我就叫NumberCollectorImpl,由于collector這里要求有三個(gè)泛型,根據(jù)題主的需求,這三個(gè)泛型只有第一個(gè)是未知的,另外兩個(gè)應(yīng)該是確認(rèn)的List結(jié)構(gòu),所以寫出來(lái)應(yīng)該是這么個(gè)效果

static class NumberCollectorImpl implements Collector>, List>>

ok,針對(duì)collector要求實(shí)現(xiàn)的5個(gè)方法來(lái)依次說(shuō)明
第一個(gè)方法Supplier>> supplier(),很明顯應(yīng)該就是ArrayList::new
第二個(gè)方法BiConsumer>, T>,這個(gè)稍微麻煩點(diǎn),起始應(yīng)該寫成(list, item) -> {},主要就是補(bǔ)充{}中的代碼了
最開始的遍歷的時(shí)候,這個(gè)list其實(shí)是父list,它肯定是空的,所以這個(gè)時(shí)候要?jiǎng)?chuàng)建一個(gè)新子List,然后把item塞進(jìn)子list中,最后再把創(chuàng)建的新子list放入到父list

if (list.isEmpty()){
  list.add(this.createNewList(item));
}

這里簡(jiǎn)單封了一個(gè)小方法createNewList,因?yàn)榇龝?huì)還要用

private List createNewList(T item){
   List newOne = new ArrayList();
   newOne.add(item);
   return newOne;
}

若父list不為空,那就要把當(dāng)前父list中最后一個(gè)子list取出來(lái),若空的話,當(dāng)然又是要?jiǎng)?chuàng)建一個(gè)新子list然后按照之前的方法做,若不為空,就判斷子list大小咯,若大小超過(guò)2,就再次創(chuàng)建一個(gè)新子list然后塞item,若沒(méi)有超過(guò)就在之前子list中塞入item,寫出來(lái)大概就是這個(gè)樣子

List last = (List) list.get(list.size() - 1);
if (last.size() < 2){
    last.add(item);
}else{
    list.add(this.createNewList(item));
}

第三個(gè)方法BinaryOperator>> combiner(),其實(shí)就是兩個(gè)List如何合并,當(dāng)然是addAll方法

(list1, list2) -> {
   list1.addAll(list2);
   return list1;
};

第四個(gè)方法Function>, List>> finisher(),由于這個(gè)時(shí)候A和R的類型一樣,都是List>,所以這里直接就是Function.identity()

最后一個(gè)方法Set characteristics()這里直接可以按照Collectors.toList來(lái)弄就行了,也就是直接采用Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH))

綜上所述,完整代碼如下

/**
 * 自定義Collector
 *
 * @author imango
 * @since 2017/7/13
 */
public class CustomCollectors {

    // 默認(rèn)采用2個(gè)一起分組
    public static  Collector>, List>> groupByNumber(){
        return CustomCollectors.groupByNumber(2);
    }
    
    // 根據(jù)number的大小進(jìn)行分組
    public static  Collector>, List>> groupByNumber(int number){
        return new NumberCollectorImpl(number);
    }

    /**
     * 個(gè)數(shù)分組器
     * @param 
     */
    static class NumberCollectorImpl implements Collector>, List>> {
        // 每組的個(gè)數(shù)
        private int number;

        public NumberCollectorImpl(int number) {
            this.number = number;
        }

        @Override
        public Supplier>> supplier() {
            return ArrayList::new;
        }

        @Override
        public BiConsumer>, T> accumulator() {
            return (list, item) -> {
                if (list.isEmpty()){
                    list.add(this.createNewList(item));
                }else {
                    List last = (List) list.get(list.size() - 1);
                    if (last.size() < number){
                        last.add(item);
                    }else{
                        list.add(this.createNewList(item));
                    }
                }
            };
        }

        @Override
        public BinaryOperator>> combiner() {
            return (list1, list2) -> {
                list1.addAll(list2);
                return list1;
            };
        }

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

        @Override
        public Set characteristics() {
            return Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH));
        }

        private List createNewList(T item){
            List newOne = new ArrayList();
            newOne.add(item);
            return newOne;
        }
    }
}

外面那個(gè)類CustomCollectors 主要是為了封裝NumberCollectorImpl類,以后也可以把其他自定義的收集器實(shí)現(xiàn)放在這里面,并對(duì)外提供工具方法,并且我在NumberCollectorImpl類中新增了一個(gè)number成員變量,這樣就可以自定義分組大小了,CustomCollectors提供了兩個(gè)對(duì)外方法groupByNumber,帶參數(shù)的那個(gè)就是可以自定義分組個(gè)數(shù)的了,沒(méi)有參數(shù)的就是默認(rèn)按照2個(gè)分組了,這樣的話,測(cè)試寫法就是這樣

public static void main(String[] args) {
   List list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
   // 按照2個(gè)分組
   List> twoNumberList = list.stream().collect(CustomCollectors.groupByNumber());
   // 按照5個(gè)分組
   List> fiveNumberList = list.stream().collect(CustomCollectors.groupByNumber(5));
}

這樣代碼就非常漂亮了~哈哈哈~~

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/71143.html

相關(guān)文章

  • 樂(lè)字節(jié)-Java8新特性之Stream流(下)

    摘要:歸約操作計(jì)算有效訂單總金額有效訂單總金額收集數(shù)據(jù)收集將流轉(zhuǎn)換為其他形式,方法作為終端操作,接收一個(gè)接口的實(shí)現(xiàn),用于給中元素做匯總的方法。 接上一篇:《Java8新特性之stream》,下面繼續(xù)接著講Stream 5、流的中間操作 常見的流的中間操作,歸為以下三大類:篩選和切片流操作、元素映射操作、元素排序操作:showImg(https://segmentfault.com/img/b...

    20171112 評(píng)論0 收藏0
  • Java8中創(chuàng)建Stream 流四種方式以及 Stream 中間操作

    摘要:一創(chuàng)建里流的四種方式第一種通過(guò)得方法串行流或者方法并行流創(chuàng)建。終止操作時(shí)一次性全部處理,稱為延遲加載篩選切片過(guò)濾中建操作。終止操作只有執(zhí)行終止操作才會(huì)執(zhí)行全部。即延遲加載結(jié)果中建操作。截?cái)嗔?,使其元素不超過(guò)給定數(shù)量。返回流中最大值。 Stream api **Stream api 是java8 中提供的對(duì)集合處理的api , 對(duì)數(shù)據(jù)進(jìn)行一系列的中間操作,元數(shù)據(jù)不會(huì)發(fā)生改變 ...

    0xE7A38A 評(píng)論0 收藏0
  • Java8流特性和Lambda表達(dá)式

    摘要:表達(dá)式體現(xiàn)了函數(shù)式編程的思想,即一個(gè)函數(shù)亦可以作為另一個(gè)函數(shù)參數(shù)和返回值,使用了函數(shù)作參數(shù)返回值的函數(shù)被稱為高階函數(shù)。對(duì)流對(duì)象進(jìn)行及早求值,返回值不在是一個(gè)對(duì)象。 Java8主要的改變是為集合框架增加了流的概念,提高了集合的抽象層次。相比于舊有框架直接操作數(shù)據(jù)的內(nèi)部處理方式,流+高階函數(shù)的外部處理方式對(duì)數(shù)據(jù)封裝更好。同時(shí)流的概念使得對(duì)并發(fā)編程支持更強(qiáng)。 在語(yǔ)法上Java8提供了Lamb...

    gaara 評(píng)論0 收藏0
  • Stream流與Lambda表達(dá)式(二) Stream收集器 Collector接口

    摘要:一收集器接口陳楊收集器接口匯聚操作的元素類型即流中元素類型匯聚操作的可變累積類型匯聚操作的結(jié)果類型接口一種可變匯聚操作將輸入元素累積到可變結(jié)果容器中在處理完所有輸入元素后可以選擇將累積的結(jié)果轉(zhuǎn)換為最終表示可選操作歸約操作 一、Stream收集器 Collector接口 package com.java.design.java8.Stream; import com.java.desi...

    or0fun 評(píng)論0 收藏0
  • 樂(lè)字節(jié)-Java8核心特性實(shí)戰(zhàn)之Stream(流)

    摘要:大家好,我是樂(lè)字節(jié)的小樂(lè)。需要注意的是很多流操作本身就會(huì)返回一個(gè)流,所以多個(gè)操作可以直接連接起來(lái),如下圖這樣,操作可以進(jìn)行鏈?zhǔn)秸{(diào)用,并且并行流還可以實(shí)現(xiàn)數(shù)據(jù)流并行處理操作。為集合創(chuàng)建并行流。 大家好,我是樂(lè)字節(jié)的小樂(lè)。說(shuō)起流,我們會(huì)聯(lián)想到手機(jī)、電腦組裝流水線,物流倉(cāng)庫(kù)商品包裝流水線等等,如果把手機(jī) ,電腦,包裹看做最終結(jié)果的話,那么加工商品前的各種零部件就可以看做數(shù)據(jù)源,而中間一系列的...

    wenshi11019 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<