矩阵累积相乘 java_累积:轻松自定义Java收集器
矩陣?yán)鄯e相乘 java
Accumulative是針對Collector<T, A, R>的中間累積類型A提出的接口Collector<T, A, R>以使定義自定義Java Collector更加容易。
介紹
如果您曾經(jīng)使用過Java Stream ,那么很可能會使用了一些Collector ,例如:
- Collectors.toList
- Collectors.toMap
但是你有沒有使用過……
- 它使用另一個 Collector作為參數(shù),例如: Collectors.collectingAndThen 。
- 其功能在Collector.of明確指定。
這篇文章是關(guān)于custom Collector的。
集電極
讓我們回想一下Collector合同的本質(zhì) (我的評論):
/** * @param <T> (input) element type * @param <A> (intermediate) mutable accumulation type (container) * @param <R> (output) result type */ public interface Collector<T, A, R> { Supplier<A> supplier(); // create a container BiConsumer<A, T> accumulator(); // add to the container BinaryOperator<A> combiner(); // combine two containers Function<A, R> finisher(); // get the final result from the container Set<Characteristics> characteristics(); // irrelevant here }上面的合同本質(zhì)上是功能性的,這非常好! 這使我們可以使用任意累積類型( A )創(chuàng)建Collector ,例如:
- A : StringBuilder ( Collectors.joining )
- A : OptionalBox ( Collectors.reducing )
- A : long[] ( Collectors.averagingLong )
提案
在我提供任何理由之前,我將提出建議,因為它很簡短。 該提議的完整源代碼可以在GitHub上找到 。
累積接口
我建議將以下稱為Accumulative (名稱待討論)的接口添加到JDK:
public interface Accumulative<T, A extends Accumulative<T, A, R>, R> { void accumulate(T t); // target for Collector.accumulator() A combine(A other); // target for Collector.combiner() R finish(); // target for Collector.finisher() }與Collector相反,此接口本質(zhì)上是面向?qū)ο蟮?/strong> ,實現(xiàn)該接口的類必須表示某種可變狀態(tài) 。
過載收集器
具有Accumulative ,我們可以添加以下Collector.of重載:
public static <T, A extends Accumulative<T, A, R>, R> Collector<T, ?, R> of( Supplier<A> supplier, Collector.Characteristics... characteristics) { return Collector.of(supplier, A::accumulate, A::combine, A::finish, characteristics); }普通開發(fā)者故事
在本部分中,我將展示該建議會對普通開發(fā)人員產(chǎn)生怎樣的影響,因為他們只了解 Collector API的基礎(chǔ)知識 。 如果您精通此API,請在繼續(xù)閱讀之前盡力想象您不知道。
例
讓我們重用我最近的文章中的示例(進一步簡化)。 假設(shè)我們有一個Stream :
interface IssueWiseText { int issueLength(); int textLength(); }并且我們需要計算問題覆蓋率 :
 總發(fā)行時長 
 ───────────── 
 總文字長度 
此要求轉(zhuǎn)換為以下簽名:
Collector<IssueWiseText, ?, Double> toIssueCoverage();解
一般的開發(fā)人員可能會決定使用自定義累積類型A來解決此問題(不過其他解決方案也是可能的 )。 假設(shè)開發(fā)人員將其命名為CoverageContainer這樣:
- T : IssueWiseText
- A : CoverageContainer
- R : Double
下面,我將展示這樣的開發(fā)人員如何實現(xiàn)CoverageContainer的結(jié)構(gòu) 。
無累積結(jié)構(gòu)
注意 :本節(jié)很長,目的是說明該過程對于沒有使用Collector的開發(fā)人員可能有多復(fù)雜 。 如果您已經(jīng)意識到這一點,則可以跳過它
如果沒有Accumulative ,則開發(fā)人員將查看Collector.of ,并看到四個主要參數(shù):
要處理Supplier <A> supplier ,開發(fā)人員應(yīng):
要處理BiConsumer <A, T> accumulator ,開發(fā)人員應(yīng):
void accumulate(IssueWiseText t)
處理BinaryOperator <A> combiner :
要處理Function <A, R> finisher :
這個漫長的過程導(dǎo)致:
class CoverageContainer { void accumulate(IssueWiseText t) { } CoverageContainer combine(CoverageContainer other) { } double issueCoverage() { } }開發(fā)人員可以定義toIssueCoverage() (必須以正確的順序提供參數(shù)):
Collector<IssueWiseText, ?, Double> toIssueCoverage() { return Collector.of( CoverageContainer:: new , CoverageContainer::accumulate, CoverageContainer::combine, CoverageContainer::finish ); }累積結(jié)構(gòu)
現(xiàn)在, 使用 Accumulative ,開發(fā)人員將查看新的Collector.of重載,并且將僅看到一個主要參數(shù):
和一個有界類型參數(shù) :
- A extends Accumulative<T, A, R>
因此,開發(fā)人員將自然而然地開始- 實施 Accumulative<T, A, R>并第一次和最后一次解析T , A和R :
class CoverageContainer implements Accumulative<IssueWiseText, CoverageContainer, Double> { }此時,一個不錯的IDE會抱怨該類必須實現(xiàn)所有抽象方法。 而且,這是最美麗的部分 ,它將提供快速修復(fù)。 在IntelliJ中,您單擊“ Alt + Enter”→“實施方法”,然后…就完成了!
class CoverageContainer implements Accumulative<IssueWiseText, CoverageContainer, Double> { @Override public void accumulate(IssueWiseText issueWiseText) { ????} @Override public CoverageContainer combine(CoverageContainer other) { return null ; } @Override public Double finish() { return null ; } }因此,您不必弄亂類型,手動編寫任何內(nèi)容或命名任何內(nèi)容!
哦,是的-您仍然需要定義toIssueCoverage() ,但是現(xiàn)在很簡單:
Collector<IssueWiseText, ?, Double> toIssueCoverage() { return Collector.of(CoverageContainer:: new ); }那不是很好嗎?
實作
這里的實現(xiàn)無關(guān)緊要,因為這兩種情況( diff )幾乎相同。
基本原理
程序太復(fù)雜
我希望我已經(jīng)演示了如何定義自定義Collector是一個挑戰(zhàn)。 我必須說,即使我總是不愿意定義一個。 但是,我也感覺到-有了Accumulative ,這種不情愿就消失了,因為程序?qū)⒖s小為兩個步驟:
推動實施
JetBrains創(chuàng)造了“ 發(fā)展動力 ”,我想將其轉(zhuǎn)變?yōu)椤皩嵤﹦恿Α薄?
由于Collector是一個簡單的功能的設(shè)備中,這通常是沒有意義的(據(jù)我可以告訴)來實現(xiàn)它(也有例外 )。 但是,通過Google搜索“實施收集器” ,可以看到(約5000個結(jié)果)人們正在這樣做。
這很自然,因為要在Java中創(chuàng)建“自定義” TYPE ,通常會擴展/實現(xiàn)TYPE 。 實際上,即使是經(jīng)驗豐富的開發(fā)人員(例如Java冠軍Tomasz Nurkiewicz )也可以做到這一點。
綜上所述,人們感到有實現(xiàn)的動力 ,但在這種情況下,JDK沒有為他們提供實現(xiàn)的任何東西。 Accumulative可以填補這一空白……
相關(guān)例子
最后,我搜索了一些易于實現(xiàn)Accumulative示例。
在OpenJDK(盡管這不是目標(biāo)位置)中,我發(fā)現(xiàn)了兩個:
對堆棧溢出,雖然,我發(fā)現(xiàn)大量的: 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47 , 48 , 49 , 50 , 51 , 52 , 53 。
我還發(fā)現(xiàn)了一些基于數(shù)組的示例,可以將其重構(gòu)為Accumulative以獲得更好的可讀性: a , b , c 。
命名
Accumulative不是最好的名字,主要是因為它是一個形容詞 。 但是,我選擇它是因為:
- 我希望名稱以A開頭(如<T, A, R> ),
- 我最好的候選人( Accumulator )已經(jīng)被BiConsumer<A, T> accumulator() ,
- AccumulativeContainer似乎太長。
在OpenJDK中, A稱為:
- 可變結(jié)果容器
- 累積類型
- 容器
- 州
- 框
提示以下替代方法:
- AccumulatingBox
- AccumulationState
- Collector.Container
- MutableResultContainer
當(dāng)然,如果這個想法被接受,這個名字將通過“傳統(tǒng)”的名字
摘要
在本文中,我建議向JDK添加Accumulative接口和新的Collector.of重載。 有了它們,開發(fā)人員將不再費勁地創(chuàng)建自定義Collector 。 取而代之的是,它只是變成了“執(zhí)行合同”和“引用構(gòu)造函數(shù)”。
換句話說,該提案旨在降低進入“定制Collector世界的門檻 !
附錄
下面的可選閱讀。
解決方案示例:JDK 12+
在JDK 12+中,由于Collectors.teeing ( JDK-8209685 ),我們將toIssueCoverage()定義為組合的Collector :
static Collector<IssueWiseText, ?, Double> toIssueCoverage() {return Collectors.teeing(Collectors.summingInt(IssueWiseText::issueLength),Collectors.summingInt(IssueWiseText::textLength),(totalIssueLength, totalTextLength) -> (double) totalIssueLength / totalTextLength); }上面的內(nèi)容很簡潔,但是對于Collector API新手來說,可能很難遵循。
示例解決方案:JDK方法
另外, toIssueCoverage()可以定義為:
static Collector<IssueWiseText, ?, Double> toIssueCoverage() {return Collector.of(() -> new int[2],(a, t) -> { a[0] += t.issueLength(); a[1] += t.textLength(); },(a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; },a -> (double) a[0] / a[1]); }我稱其為“ JDK方式”,因為某些Collector的實現(xiàn)與OpenJDK中的實現(xiàn)類似(例如Collector.averagingInt )。
但是,盡管這樣的簡潔代碼可能適用于OpenJDK,但由于可讀性高(這很低,我稱之為cryptic ),因此它肯定不適合業(yè)務(wù)邏輯。
翻譯自: https://www.javacodegeeks.com/2019/02/accumulative-custom-java-collectors.html
矩陣?yán)鄯e相乘 java
總結(jié)
以上是生活随笔為你收集整理的矩阵累积相乘 java_累积:轻松自定义Java收集器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: pbfunc外部扩展函数_从外部CorD
- 下一篇: 光伏不备案就并网(光伏不备案)
