Neden for döngüsü yerine “fonksiyonel işlemler” kullanmalıyım?


39
for (Canvas canvas : list) {
}

NetBeans, "işlevsel işlemleri" kullanmamı önerir:

list.stream().forEach((canvas) -> {
});

Fakat bu neden tercih edilir ? Bir şey olursa, okumak ve anlamak daha zordur. Daha stream()sonra forEach()parametre ile bir lambda ifadesi kullanarak çağırıyorsunuz canvas. Bunun forilk pasajdaki döngüden daha iyi olduğunu nasıl göremiyorum .

Açıkçası sadece estetikten bahsediyorum. Belki de burada eksik olduğum teknik bir avantaj var. Bu ne? Neden ikinci yöntemi kullanmalıyım?



15
Özel örneğinizde, tercih edilmeyecektir.
Robert Harvey

1
Tek operasyon Her Bir için tek olduğu sürece, sana katılıyorum. Boru hattına başka işlemler eklediğiniz anda veya bir çıkış dizisi ürettiğinizde, akış yaklaşımı tercih edilir hale gelir.
JacquesB

@RobertHarvey öyle değil mi? neden olmasın?
sara

@RobertHarvey iyi Kabul edilen cevabın gerçekten de, versiyonun daha karmaşık durumlar için sudan nasıl atıldığını gösterdiğini kabul ediyorum, ancak önemsiz durumda neden "kazandıklarını" anlamıyorum. kendini açık bir şekilde ifade ediyorsun ama ben göremiyorum, ben de sordum.
sara

Yanıtlar:


45

Akışlar, koleksiyonların veya gelen veri akışlarının üzerine yapmak istediğiniz farklı işlemlerin bileşimi için çok daha iyi bir soyutlama sağlar. Özellikle öğeleri eşlemeniz, filtrelemeniz ve dönüştürmeniz gerektiğinde.

Örneğiniz pek pratik değil. Oracle sitesinden aşağıdaki kodu göz önünde bulundurun .

List<Transaction> groceryTransactions = new Arraylist<>();
for(Transaction t: transactions){
  if(t.getType() == Transaction.GROCERY){
    groceryTransactions.add(t);
  }
}
Collections.sort(groceryTransactions, new Comparator(){
  public int compare(Transaction t1, Transaction t2){
    return t2.getValue().compareTo(t1.getValue());
  }
});
List<Integer> transactionIds = new ArrayList<>();
for(Transaction t: groceryTransactions){
  transactionsIds.add(t.getId());
}

akışları kullanarak yazılabilir:

List<Integer> transactionsIds = 
    transactions.stream()
                .filter(t -> t.getType() == Transaction.GROCERY)
                .sorted(comparing(Transaction::getValue).reversed())
                .map(Transaction::getId)
                .collect(toList());

İkinci seçenek çok daha okunur. Bu nedenle, kısmi işlem yapan iç içe döngüler veya çeşitli döngüler olduğunda, Streams / Lambda API kullanımı için çok iyi bir adaydır.


5
Harita füzyonu ( stream.map(f).map(g)stream.map(f.andThen(g))) füzyon oluşturma / azaltma (bir yöntemde bir akış oluştururken ve daha sonra onu tüketen başka bir yönteme geçirirken, derleyici akıntıyı ortadan kaldırabilir) ve akış füzyonu gibi optimizasyon teknikleri vardır (birçok akış işlemlerini kaynaştırabilir Akarsu işlemlerini çok daha verimli hale getirebilen tek bir zorunluluk döngüsüne birlikte). Bunlar, GHC Haskell derleyicisinde ve ayrıca bazı Haskell ve diğer fonksiyonel dil derleyicilerinde uygulanmaktadır ve Scala için deneysel araştırma uygulamaları bulunmaktadır.
Jörg W Mittag

Netbeans yapabiliyorsa ve en uygun yol olarak belirlenirse, performans muhtemelen döngüleyici vs döngüyü dikkate alırken, derleyici bir for döngüsünden işlevsel bir işleme dönüşüm yapabileceği / yapması gerektiği için bir faktör değildir.
Ryan

İkincisinin daha okunaklı olduğuna katılmıyorum. Neler olduğunu anlamak biraz zaman alıyor. İkinci metodu yapmanın performans avantajı var mı, aksi halde göremiyorum mu?
Bok McDonagh

@BokMcDonagh, Me deneyimi, yeni soyutlamalara aşina olmak için uğraşmayan geliştiriciler için daha az okunabilir olmasıdır. Gelecekte olduğu için daha fazla tanımak için bu tür API'leri daha fazla kullanmanızı öneririm. Sadece Java dünyasında değil.
luboskrnac

16

İşlevsel akış API'sini kullanmanın diğer bir avantajı, uygulama ayrıntılarını gizlemesidir. Sadece ne yapılması gerektiğini açıklar. Bu avantaj, yapılması gereken değişikliklere bakıldığında, tek dişli diziden paralel kod yürütmeye geçmek için belirginleşir. Sadece değiştirmek .stream()için .parallelStream().


13

Bir şey olursa, okumak ve anlamak daha zordur.

Bu oldukça özneldir. İkinci versiyonun okunması ve anlaşılması çok daha kolay. Diğer dillerin (örneğin Ruby, Smalltalk, Clojure, Io, Ioke, Seph) yaptığı gibi eşleşir, anlamak için daha az kavram gerektirir (bu, diğer herhangi bir gibi normal bir yöntem çağrısıdır, oysa ilk örnek özel sözdizimidir).

Bir şey olursa, bu bir aşinalık meselesidir.


6
Evet doğru. Fakat bu bana bir cevaptan çok bir yorum gibi gözüküyor.
Omega

İşlevsel işlem de özel bir sözdizimi kullanıyor: "->" yeni
Ryan
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.