第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Java流圖中可重用的單實例包裝器/對象

Java流圖中可重用的單實例包裝器/對象

瀟瀟雨雨 2023-01-05 10:09:53
似乎這個問題應該已經有了答案,但我找不到重復的答案。無論如何,我想知道社區(qū)如何看待這樣的Stream.map用例?Wrapper wrapper = new Wrapper();list.stream()    .map( s -> {        wrapper.setSource(s);        return wrapper;    } )    .forEach( w -> processWrapper(w) );    public static class Source {    private final String name;            public Source(String name) {        this.name = name;    }            public String getName() {        return name;    }}    public static class Wrapper {    private Source source = null;            public void setSource(Source source) {        this.source = source;    }            public String getName() {        return source.getName();    }}public void processWrapper(Wrapper wrapper) {}我不是這種用法的忠實粉絲,map但它可能有助于在處理大型流時提高性能并避免Wrapper為每個Source.這肯定有其局限性,例如對于并行流和終端操作(如collect.更新 - 問題不在于“如何做”,而是“我可以這樣做嗎”。例如,我可以有一個僅適用于 Wrapper 的代碼,我想在其中調用它,forEach但又想避免為每個Source元素創(chuàng)建它的新實例?;鶞蕼y試結果使用可重復使用的包裝紙顯示大約8倍的改進-基準 (N) 模式 Cnt 得分誤差單位BenchmarkTest.noReuse 10000000 平均 5 870,253 ± 122,495 毫秒/操作BenchmarkTest.withReuse 10000000 平均 5 113.694 ± 2.528 毫秒/操作
查看完整描述

3 回答

?
呼如林

TA貢獻1798條經驗 獲得超3個贊

您的方法恰好有效,因為流管道僅包含無狀態(tài)操作。在這種情況下,順序流評估可能一次處理一個元素,因此對包裝器實例的訪問不會重疊,如此處所示。但請注意,這不是保證的行為。

它絕對不適用于像sorted和這樣的有狀態(tài)操作distinct。它也不能用于歸約操作,因為它們總是必須至少保存兩個元素進行處理,其中包括reduce、minmax。在 的情況下collect,這取決于特定的CollectorforEachOrdered由于需要緩沖,因此不適用于并行流。

請注意,即使您使用TheadLocal創(chuàng)建線程受限包裝器,并行處理也會出現問題,因為無法保證在一個工作線程中創(chuàng)建的對象保持在該線程的本地。工作線程可能會在獲取另一個不相關的工作負載之前將部分結果移交給另一個線程。

所以這個共享的可變包裝器在特定實現的順序執(zhí)行中與一組特定的無狀態(tài)操作一起工作,比如mapfilterforEachfindFirst/Any, 。all/any/noneMatch您無法獲得 API 的靈活性,因為您必須限制自己,不能將流傳遞給期望 a 的任意代碼,Stream也不能使用任意Collector實現。您也沒有接口的封裝,因為您假設了特定的實現行為。

換句話說,如果你想使用這樣一個可變的包裝器,你最好使用一個實現特定操作的循環(huán)。您確實已經有了這種手動實施的缺點,那么為什么不實施它來獲得優(yōu)勢呢。


另一個要考慮的方面是,你從重用這樣一個可變包裝器中得到了什么。它僅適用于類似循環(huán)的用法,在這種情況下,臨時對象在應用逃逸分析后可能會被優(yōu)化掉。在這種情況下,重用對象、延長它們的生命周期實際上可能會降低性能。

當然,對象標量化不是一種有保證的行為??赡艽嬖谝恍﹫鼍?,例如超過 JVM 內聯限制的長流管道,其中對象不會被刪除。但是,臨時對象并不一定很昂貴。

這已在此答案中進行了解釋。臨時對象的分配成本很低。垃圾收集的主要成本是由仍然存在的對象引起的。這些需要遍歷,并且在為新分配騰出空間時需要移動這些。臨時對象的負面影響是它們可能會縮短垃圾收集輪次之間的時間。但這是分配率和可用分配空間的函數,所以這確實是一個可以通過投入更多 RAM 來解決的問題。更多的 RAM 意味著 GC 周期之間的時間更長,GC 發(fā)生時死對象更多,這使得 GC 的凈成本更小。

盡管如此,避免過度分配臨時對象是一個有效的問題。IntStream、LongStream和的存在DoubleStream表明。但這些是特殊的,因為使用原始類型是使用包裝器對象的可行替代方案,而且沒有重用可變包裝器的缺點。它的不同之處還在于它適用于原始類型和包裝類型在語義上等同的問題。相反,您想解決操作需要包裝器類型的問題。對于原始流也適用,當您需要對象來解決問題時,沒有辦法繞過裝箱,這將為不同的值創(chuàng)建不同的對象,而不是共享可變對象。

因此,如果您同樣遇到一個問題,即存在語義等效的包裝對象避免替代方案而沒有實質性問題,例如在可行Comparator.comparingInt的情況下使用而不是Comparator.comparing,您可能仍然會喜歡它。但只有那時。


簡而言之,大多數時候,這種對象重用的節(jié)?。ㄈ绻械脑挘┎⒉荒茏C明其缺點。在特殊情況下,在有益且重要的情況下,使用循環(huán)或完全控制的任何其他構造可能會更好,而不是使用Stream.


查看完整回答
反對 回復 2023-01-05
?
米脂

TA貢獻1836條經驗 獲得超3個贊

你可以有一些方便的功能,也可以有線程安全的版本來并行工作。


Function<T,U> threadSafeReusableWrapper(Supplier<U> newWrapperInstanceFn, BiConsumer<U,T> wrapFn) {

   final ThreadLocal<T> wrapperStorage = ThreadLocal.withInitial(newWrapperInstanceFn);

   return item -> {

      T wrapper = wrapperStorage.get();

      wrapFn.consume(wrapper, item);

      return wrapper;

   }

}


Function<T,U> reusableWrapper(U wrapper, BiConsumer<U,T> wrapFn) {

   return item -> {

      wrapFn.consume(wrapper, item);

      return wrapper;

   };

}


list.stream()

    .map(reusableWrapper(new Wrapper(), Wrapper::setSource))

    .forEach( w -> processWrapper(w) );

list.stream()

    .map(threadSafeReusableWrapper(Wrapper::new, Wrapper::setSource))

     .parallel()

    .forEach( w -> processWrapper(w) );

但是,我認為不值得。這些包裝器是短暫的,所以不太可能離開年輕一代,所以會很快被垃圾收集。不過,我認為這個想法值得用微基準庫 JMH檢查


查看完整回答
反對 回復 2023-01-05
?
LEATH

TA貢獻1936條經驗 獲得超7個贊

盡管這是可能的,但引用流外的對象會使代碼在風格上功能性降低。可以使用輔助函數簡單地實現一個封裝得更好的非常接近的等價物:


public class Context {


    private static final Wrapper WRAPPER = new Wrapper();


    private static void helper(Source source) {

        WRAPPER.setSource(source);

        processWrapper(WRAPPER);

    }


    public static void main(String[] args) {

        List<Source> list = Arrays.asList(new Source("Foo"), new Source("Baz"), new Source("Bar"));

        list.stream().forEach(Context::helper);

}


查看完整回答
反對 回復 2023-01-05
  • 3 回答
  • 0 關注
  • 168 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號