Java'da akışların döngülere göre avantajları nelerdir? [kapalı]


133

Bu bir röportajda soruldu ve verebileceğim en iyi cevabı verdiğime ikna olmadım. Paralel arama yapabileceğinizi ve boş değerlerin hatırlayamadığım bir şekilde ele alındığını söylemiştim. Şimdi Opsiyonelleri düşündüğümü anlıyorum. Burada neyi özlüyorum? Daha iyi veya daha özlü bir kod olduğunu iddia ediyorlar, ancak kabul ettiğimden emin değilim.


Ne kadar kısa ve öz bir şekilde yanıtlandığı düşünüldüğünde, sonuçta bu çok geniş bir soru değilmiş gibi görünüyor.


Bu soruyu röportajlarda soruyorlarsa ve açıkça soruyorlarsa, cevabı bulmayı zorlaştırmaktan başka hangi amaca hizmet edebilir? Demek istediğim, ne arıyorsun? Soruyu parçalara ayırabilir ve tüm alt soruların yanıtlanmasını sağlayabilirim, ancak ardından tüm alt sorularla bağlantılı bir ana soru oluşturabilirim ... yine de oldukça aptalca görünüyor. Biz oradayken, lütfen bana daha az kapsamlı bir soru örneği verin. Bu sorunun sadece bir kısmını sormanın ve yine de anlamlı bir cevap almanın bir yolunu bilmiyorum. Tam olarak aynı soruyu farklı bir şekilde sorabilirim. Örneğin, "Akışlar hangi amaca hizmet eder?" Diye sorabilirim. veya "For döngüsü yerine bir akışı ne zaman kullanırım?" veya "Neden döngüler yerine akışlarla uğraşasınız?" Bunların hepsi tamamen aynı soru.

... ya da birisi gerçekten çok uzun bir cevap verdiği için çok geniş olarak mı değerlendiriliyor? Açıkçası bilen herhangi biri bunu neredeyse her soruyla yapabilirdi. Örneğin, JVM'nin yazarlarından biri olursanız, muhtemelen çoğumuzun yapamadığı tüm gün boyunca döngüler hakkında konuşabilirsiniz.

"Lütfen, yeterli bir cevabı belirlemek için yeterli ayrıntıya sahip belirli bir problemle sınırlandırmak için soruyu düzenleyin. Aynı anda birden fazla farklı soru sormaktan kaçının. Bu soruyu açıklığa kavuşturmak için Nasıl Sorulur sayfasına bakın."

Aşağıda belirtildiği gibi, bir tane olduğunu ve vermenin yeterince kolay olduğunu kanıtlayan yeterli bir cevap verilmiştir.


7
Bu fikir temelli. Kişisel olarak, kodu daha okunaklı hale getirdiği için akışları tercih ederim. Bu yazmasına olanak tanır neyi sen yerine istediğiniz nasıl . Dahası, tek gömleklerle harika şeyler yapmak tamamen kötüdür.
Arnaud Denoyelle

19
30 satır olsa bile, tek satırlık mı? Uzun zincirleri sevmiyorum.
user447607

1
Ayrıca, burada aradığım tek şey röportaj için uygun cevap. Önemli olan tek "fikir" budur.
user447607

1
Eğitimsel olarak konuşursak, bu soru beni gelecekteki bir röportajda da biraz aşağılamadan kurtardı, @slim bunu gerçekten çiviledi, ancak endüstriyel olarak konuşursak, Microsoft programlama dillerinin kariyerlerini java dilini koparmak üzerine nasıl inşa ettiklerini ve sonunda java'nın intikamını kopararak aldığından da bahsediyor. kapalı Lambda İfade ve akışları muhaliflerden, :) java gelecekte Yapılar ve Birlikler ilgili ne olup bittiğini görmenizi sağlar
ShayHaned

5
Akışların işlevsel programlamada gücün yalnızca bir kısmını kullandığını unutmayın: - /
Thorbjørn Ravn Andersen

Yanıtlar:


252

Mülakat sorusunun dezavantajları sormadan avantajları sorması ilginç, çünkü ikisi de var.

Akışlar daha açıklayıcı bir stildir . Veya daha etkileyici bir tarz. Niyetinizi bir kodla belirtmek, nasıl yapıldığını açıklamaktan daha iyi düşünülebilir :

 return people
     .filter( p -> p.age() < 19)
     .collect(toList());

... bir listeden eşleşen öğeleri filtrelediğinizi oldukça açık bir şekilde söylüyor, oysa:

 List<Person> filtered = new ArrayList<>();
 for(Person p : people) {
     if(p.age() < 19) {
         filtered.add(p);
     }
 }
 return filtered;

"Bir döngü yapıyorum" diyor. Döngünün amacı mantığın derinliklerine gömülüdür.

Akışlar genellikle daha zordur . Aynı örnek bunu göstermektedir. Terser her zaman daha iyi değildir, ancak aynı anda hem kısa hem de anlamlı olabilirseniz, çok daha iyi.

Akışların işlevlerle güçlü bir ilişkisi vardır . Java 8, güçlü tekniklerden oluşan bir oyuncak kutusunu açan lambdalar ve işlevsel arayüzler sunar. Akışlar, işlevleri nesne dizilerine uygulamanın en uygun ve doğal yolunu sağlar.

Akışlar daha az değişkenliği teşvik eder . Bu, işlevsel programlama yönü ile ilgilidir - akışları kullanarak yazdığınız program türleri, nesneleri değiştirmediğiniz türden programlar olma eğilimindedir.

Akışlar daha gevşek bağlanmayı teşvik eder . Akış işleme kodunuzun, akışın kaynağını veya nihai sonlandırma yöntemini bilmesi gerekmez.

Akışlar, oldukça karmaşık davranışları kısa ve öz bir şekilde ifade edebilir . Örneğin:

 stream.filter(myfilter).findFirst();

İlk bakışta tüm akışı filtreler ve ardından ilk öğeyi döndürür gibi bakabilirsiniz. Ancak aslında findFirst()tüm operasyonu yönlendirir, bu nedenle bir öğeyi bulduktan sonra verimli bir şekilde durur.

Akışlar, gelecekteki verimlilik kazanımları için kapsam sağlar . Bazı insanlar, bellek içi Listveya dizilerden gelen tek iş parçacıklı akışların eşdeğer döngüden daha yavaş olabileceğini değerlendirdi ve buldu . Bu mantıklı çünkü oyunda daha fazla nesne ve genel gider var.

Ancak akışlar ölçeklenir. Java'nın paralel akış işlemleri için yerleşik desteğinin yanı sıra, model uygun olduğu için API olarak Akışları kullanan dağıtılmış harita azaltma için birkaç kitaplık vardır.

Dezavantajları?

Performans : Bir fordizideki döngü, hem yığın hem de CPU kullanımı açısından son derece hafiftir. Ham hız ve hafıza tasarrufu bir öncelikse, akış kullanmak daha kötüdür.

Aşinalık: Dünya, birçok dil geçmişine sahip, döngüler tanıdık ve akışlar yeni olan deneyimli prosedür programcılarıyla doludur. Bazı ortamlarda, bu tür insanlara tanıdık gelen kodlar yazmak istersiniz.

Bilişsel ek yük . Bildirim niteliğindeki doğası ve altında olanlardan artan soyutlama nedeniyle, kodun yürütmeyle nasıl ilişkili olduğuna dair yeni bir zihinsel model oluşturmanız gerekebilir. Aslında bunu yalnızca işler ters gittiğinde veya performansı veya ince hataları derinlemesine analiz etmeniz gerektiğinde yapmanız gerekir. "Sadece çalıştığında", sadece çalışır.

Hata ayıklayıcılar gelişiyor, ancak şimdi bile, bir hata ayıklayıcıda akış kodunda adım adım ilerlediğinizde, eşdeğer döngüden daha zor bir iş olabilir, çünkü basit bir döngü, geleneksel bir hata ayıklayıcının çalıştığı değişkenlere ve kod konumlarına çok yakındır.


4
Bence akış benzeri şeylerin çok daha yaygın hale geldiğini ve şimdi özellikle FP odaklı olmayan birçok yaygın kullanılan dilde ortaya çıktığını görmek adil olurdu.
Casey

5
Burada listelenen artılar ve eksiler göz önüne alındığında, kritik olmayan performans bölümlerinde akışların çok basit kullanımlardan başka hiçbir şey için değmediğini düşünüyorum (küçük mantık, eğer / o zaman / değilse, çok sayıda iç içe çağrı veya lambda vb.)
Henrik

1
@HenrikKjusAlstad Bu kesinlikle iletmek istediğim paket servis değil. Akışlar olgun, güçlü, anlamlı ve üretim düzeyinde kod için tamamen uygundur.
ince

Oh, onu üretimde kullanmayacağımı söylemedim. Ancak bunun yerine, özellikle ortaya çıkan akış karmaşık görünüyorsa, akışlar yerine eski moda döngüler / ifs vb. Eminim bir akışın döngüleri geçeceği ve eğer netlik içindeyse, ancak çoğu zaman "bağlı" olduğunu düşünüyorum, hatta bazen tam tersi. Bu nedenle, eski yöntemlere bağlı kalmak için bilişsel genel tartışmaya ağırlık verdim.
Henrik Kjus Alstad

1
@lijepdam - ama yine de "Bu listeyi yineliyorum (nedenini öğrenmek için döngünün içine bakın)" yazan bir kodunuz var, "liste üzerinde yineleme" kodun ana amacı değilse.
ince

16

Sözdizimsel eğlencenin yanı sıra, Akışlar potansiyel olarak sonsuz büyüklükte veri kümeleriyle çalışmak üzere tasarlanırken, diziler, Koleksiyonlar ve Yinelemeyi uygulayan neredeyse her Java SE sınıfı tamamen bellekte.

Bir Akışın bir dezavantajı, filtrelerin, eşlemelerin vb. Kontrol edilen istisnaları atamamasıdır. Bu, bir Stream'i örneğin ara G / Ç işlemleri için kötü bir seçim yapar.


7
Elbette sonsuz kaynaklar üzerinde de döngü yapabilirsiniz.
ince

Ancak işlenecek öğeler bir veritabanında saklanırsa, Akışları nasıl kullanırsınız? Küçük bir geliştirici, Akışları kullanmak için hepsini bir Koleksiyonda okumak isteyebilir. Ve bu bir felaket olur.
Lluis Martinez

2
@LluisMartinez, iyi bir DB istemci kitaplığı gibi bir şey döndürecektir Stream<Row>- ya da kişinin kendi Streamgerçekleştirim sarmalı DB sonuç imleci işlemlerini yazması mümkün olacaktır .
slim

Akımların istisnaları sessizce görmezden gelmesi, yakın zamanda ısırıldığım bir hata. Unintuitive.
xxfelixxx

@xxfelixxx Akışlar istisnaları sessizce göz ardı etmez. Arrays.asList("test", null).stream().forEach(s -> System.out.println(s.length()));
Şunu

8
  1. Yanlış anladınız: paralel işlemler Streams kullanır , Optionals kullanır.

  2. Akışlarla çalışan yöntemleri tanımlayabilirsiniz: onları parametre olarak almak, döndürmek, vb. Döngüyü parametre olarak alan bir yöntem tanımlayamazsınız. Bu, karmaşık bir akış işleminin bir kez ve birçok kez kullanılmasına izin verir. Java'nın burada bir dezavantajı olduğunu unutmayın: Yöntemleriniz, someMethod(stream)akışın kendisininkinin aksine çağrılmalıdır stream.someMethod(), bu nedenle onları karıştırmak okumayı zorlaştırır: işlemlerin sırasını

    myMethod2(myMethod(stream.transform(...)).filter(...))

    Diğer birçok dil (C #, Kotlin, Scala, vb.) Bazı "genişletme yöntemlerine" izin verir.

  3. Yalnızca sıralı işlemlere ihtiyaç duyduğunuzda ve bunları yeniden kullanmak istemediğinizde bile, akışları veya döngüleri kullanabilmeniz için akışlar üzerindeki basit işlemler, döngülerdeki oldukça karmaşık değişikliklere karşılık gelebilir.


Açıklayın 1. İsteğe bağlı arabirim, zincirlerde boş değerlerin işlendiği araç değil mi? 3 ile ilgili olarak, bu mantıklıdır, çünkü kısa devreli filtrelerde yöntem yalnızca belirli olaylar için çağrılacaktır. Verimli. Bunları kullanmanın test edilmesi gereken ek kod yazma ihtiyacını azalttığını
belirtebilirim

1. Optionalbir alternatiftir null, ancak paralel işlemlerle ilgisi yoktur. Sorunuzdaki "Opsiyonelleri düşündüğümü şimdi anlıyorum" sadece nullkullanımdan bahsetmiyorsa ?
Alexey Romanov

2 ve 3'ün sırasını değiştirdim ve ikisini de biraz genişlettim.
Alexey Romanov

6

Bir dizi (dizi, koleksiyon, girdi, ...) üzerinden döngü yaparsınız çünkü dizinin elemanlarına bazı işlevler uygulamak istiyorsunuz.

Akışlar , sekans öğeleri üzerinde işlevler oluşturma ve somut bir durumdan bağımsız olarak en yaygın işlevleri (örneğin, eşleme, filtreleme, bulma, sıralama, toplama, ...) gerçekleştirmenize olanak tanır .

Bu nedenle, çoğu durumda bir döngü görevi verildiğinde, bunu Akışları kullanarak daha az kodla ifade edebilirsiniz, yani okunabilirlik kazanırsınız .


4
Eh, bu sadece okunabilirlik değil. Yazmak zorunda olmadığınız kod, test etmeniz gerekmeyen koddur.
user447607

3
Görünüşe göre röportajınız için de iyi cevaplar
buluyorsunuz

6

Paralelleştirmesinin kullanımı çok kolay olduğunu söyleyebilirim . Bir for döngüsüyle paralel olarak milyonlarca girişi yinelemeyi deneyin. Daha hızlı değil, birçok cpus'a gidiyoruz; yani paralel koşmak ne kadar kolaysa o kadar iyidir ve Streams ile bu çocuk oyuncağı.

Çok sevdiğim şey, sundukları ayrıntılar . Nasıl yaptıklarının aksine gerçekte ne yaptıklarını ve ürettiklerini anlamak çok az zaman alır .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.