Eran cevabı iki-arg ve üç arg sürümleri arasındaki farkların açıklamasını reduce
eski azalttığı içinde Stream<T>
hiç T
ikincisi azaltır oysa Stream<T>
etmek U
. Azaltılması Ancak, aslında ek birleştirici fonksiyonu olan ihtiyacı açıklama yapmadı Stream<T>
etmek U
.
Akış API'sinin tasarım ilkelerinden biri, API'nin sıralı ve paralel akışlar arasında farklılık göstermemesi veya başka bir yol koymasıyla, belirli bir API'nin bir akışın sırayla veya paralel olarak düzgün çalışmasını engellememesidir. Lambdalarınız doğru özelliklere (çağrışımsal, etkileşmeyen vb.) Sahipse, sırayla veya paralel olarak çalışan bir akış aynı sonuçları vermelidir.
İlk önce indirgemenin iki arg versiyonunu düşünelim:
T reduce(I, (T, T) -> T)
Sıralı uygulama basittir. Kimlik değeri I
bir sonuç vermek için sıfırıncı akım elemanı ile "birikir". Bu sonuç, ikinci akış elemanı ile biriken başka bir sonuç vermek üzere birinci akış elemanı ile birikir ve bu böyle devam eder. Son eleman toplandıktan sonra nihai sonuç döndürülür.
Paralel uygulama, akışı segmentlere bölerek başlar. Her bölüm, yukarıda tarif ettiğim sıralı bir şekilde kendi ipliği ile işlenir. Şimdi, N iş parçacığımız varsa, N ara sonucumuz var. Bunların bir sonuca indirgenmesi gerekir. Her ara sonuç T tipinde olduğundan ve birkaç tane var, bu N ara sonuçları tek bir sonuca indirmek için aynı akümülatör işlevini kullanabiliriz.
Şimdi azaltan varsayımsal bir iki-arg azaltma işlemini düşünelim Stream<T>
için U
. Diğer dillerde, buna "katlama" veya "katlama sollama" işlemi denir . Bunun Java'da mevcut olmadığını unutmayın.
U foldLeft(I, (U, T) -> U)
(Kimlik değerinin I
U türünde olduğuna dikkat edin .)
Sıralı versiyonu , ara değerlerin T tipi yerine U foldLeft
tipinde olması reduce
haricinde , sıralı versiyonuna benzer. Ama aksi halde aynıdır. (Varsayımsal bir foldRight
işlem, işlemlerin soldan sağa yerine sağdan sola gerçekleştirilmesi dışında benzer olacaktır.)
Şimdi foldLeft
. Akışı segmentlere bölerek başlayalım. Daha sonra her N iş parçacığının kendi segmentindeki T değerlerini U tipi N ara değerlerine indirmesini sağlayabiliriz. Şimdi ne olacak? U tipi N değerlerinden U tipi tek bir sonuca nasıl ulaşabiliriz?
Eksik olduğunu başka fonksiyondur birleştirir tip U. sonucunun tek tip U çoklu ara sonuçlarını biz yeterli olduğunu birine birleştiren iki U değerleri bire düştü değerlerin herhangi sayısını azaltmak için bir işlevi varsa - tıpkı yukarıdaki orijinal azalma. Bu nedenle, farklı bir tipin sonucunu veren azaltma işlemi iki işleve ihtiyaç duyar:
U reduce(I, (U, T) -> U, (U, U) -> U)
Veya Java sözdizimini kullanarak:
<U> U reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)
Özetle, farklı bir sonuç türü paralel bir azalma yapmak için iki fonksiyonları gerekir: bir biriken ara U değerleri T elemanları, ve bir ikinci bu biçerdöver tek bir U sonucu içine ara ürün, U-değeri. Türleri değiştirmezsek, akümülatör işlevinin birleştirici işleviyle aynı olduğu ortaya çıkar. Bu yüzden aynı tipte azaltmanın sadece akümülatör işlevi vardır ve farklı bir türe indirgemek için ayrı akümülatör ve birleştirici işlevleri gerekir.
Son olarak, Java, sunmaz foldLeft
ve foldRight
işlem yapmaz, çünkü doğası gereği ardışık olan işlemlerin belirli bir sırasını ima ederler. Bu, sıralı ve paralel çalışmayı eşit olarak destekleyen API'ler sağlamada yukarıda belirtilen tasarım ilkesiyle çelişmektedir.