Bir lambda ifadesi, tek bir yöntemle anonim bir iç sınıftan daha fazlası mıdır?


40

Java 8'de uzun zamandır beklenen lambda ifadeleriyle yeni bir yutturmaca var; Her 3 günde bir, ne kadar havalı olduklarını gösteren başka bir makale var.

Anladığım kadarıyla lamda ifadesi, tek bir yöntemle (en azından bayt kodu düzeyinde) anonim bir iç sınıftan başka bir şey değildir. Bunun yanında başka bir güzel özellik tipi çıkarım ile geliyor ama bunun eşdeğerinin bir düzeyde jeneriklerle elde edilebileceğine inanıyorum (elbette lambda ifadelerinde olduğu gibi düzgün bir şekilde değil).

Bunu bilerek, Java'da lambda ifadeleri sözdizimsel bir şekerlemeden başka bir şey mi getirecek? Mevcut dil özellikleri ile inşa edilemeyen lambda ifadeleriyle daha güçlü ve esnek sınıflar veya başka nesne yönelimli yapılar oluşturabilir miyim?


30
Bir dil tamamlanırken, eklenen her özellik teorik olarak "sözdizimsel şeker" olarak tanımlanabilir.
Philipp

34
@Philipp: Bu yanlış. Sözdizimsel şekerin belirleyici özelliği, ıssızlığın tamamen yerel olması ve programın küresel yapısını değiştirmemesidir. Sadece yerel dönüşümlerle uygulanamayan birçok özellik var. Örneğin, Java ile aynı olan ancak uygun kuyruk çağrılarıyla aynı olan bir varsayımsal dil alırsanız, kuyruk programlarını "tümüyle" Java'ya "bütünüyle" dönüştürmeden "saf" Java'ya çevirmek mümkün olmazdı.
Jörg W Mittag

2
@Philipp: Maalesef, yorumlar için yalnızca bir oylama var, aksi halde Joerg'in yorumuna 1000 kez puan veririm. Hayır, herhangi bir özelliğin sözdizimsel şeker olarak tanımlanması yanlıştır. Sözdizimsel şeker yeni anlambilim eklemiyor. Aslında AFAIK, önerilen Java lambdaları özel anonim iç sınıflar için sözdizimsel bir şeker DEĞİLDİR, çünkü farklı semantikleri var.
Giorgio,

1
@ Giorgio: ve onların farklı anlambilimleri nelerdir?
user102008

2
@ Giorgio: Evet, ancak thisiçine dönüşme, OuterClass.thislambda ifadelerinin isimsiz bir sınıfa ayrılması sürecinin bir parçasıdır.
user102008

Yanıtlar:


47

tl; dr: bu kadar süre çoğunlukla sözdizimsel şeker, o güzel sözdizimi parantez ve parantez sonsuz, okunamayan hatlarında sonuna kadar kullanılan pratik bir sürü şey yapar.

Aslında, bu lambdaların Java'dan çok daha yaşlı olması gibi bir durum . Tek bir yöntemle anonim iç sınıflar, Java'nın lambdalara en yakın olduğu idi. Bir süredir "yeterince iyi" olan, ancak çok kötü bir sözdizimine sahip olan yaklaşık bir yaklaşım.

Yüzeyde, Java 8 lambdaları sözdizimsel şekerden çok daha fazla gözükmüyor, ancak yüzeyin altına baktığınızda, tonlarca ilginç soyutlamalar görüyorsunuz. Örneğin, JVM spesifikasyonu bir lambdaya bir "gerçek" nesneden oldukça farklı davranır ve onları nesnelerin olduğu yerler gibi ele alırken , JVM'nin bunları uygulaması gerekli değildir.

Ancak tüm bu teknik hile ilginç ve alakalı olsa da (JVM'de gelecekteki optimizasyonlara izin verdiği için!), Asıl fayda sözdizimsel şeker kısmı "sadece" dır.

Okumak için daha kolay:

myCollection.map(new Mapper<String,String>() {
  public String map(String input) {
    return new StringBuilder(input).reverse().toString();
  }
});

veya:

myCollection.map(element -> new StringBuilder(element).reverse().toString());

veya (bir lambda yerine bir yöntem tutamacı kullanarak):

myCollection.map(String::toUpperCase);

Sonunda daha önce 5 kod satırı olacak şekilde (3'ü tamamen sıkıcı olan) kısa bir şekilde ifade edebileceğiniz gerçeği, pratik olanın (ancak mümkün olanın değil) ne olduğuna dair gerçek bir değişiklik getirir .


1
Sözdizimi şekerleme kısmına tamamen katılıyorum; Benim sorum sadece lambda ifadeleriyle mümkün olan yeni nesne yönelimli yapılardı; Sonuçta Java nesne yönelimli bir dildir. Jeneriklerle karşılaştırmayı ve Java’da esnekliği nasıl aldıklarını, onsuz alınamayan esnekliği düşünün.
m3th0dman

7
@ m3th0dman: aslında jenerikler yeni bir yetenek eklememişlerdir. Bir Listherhangi bir nesneyi tutabilir, bir List<String>teneke "sadece" tutabilir. Jenerikler bir kısıtlama ekledi (ve kısıtlamaları resmileştirme seçeneği!), İktidara bir ilave değil. Java 1.1'den bu yana hemen hemen her şey sözdizimsel bir şeker olmuştur. Ve bu mutlaka kötü bir şey değil.
Joachim Sauer

3
@ m3th0dman: Aslında jenerikler yeni yetenekler eklemiyor, çünkü Java'da bunlar sadece sözdizimsel bir şeker. Bir List<String>sadece olduğu Listiçin alçı ile Stringbazı dönüş değerleri etrafında eklendi. Yine de son derece kullanışlıdırlar ve dili yazmak için çok daha uygun hale getirdiler. Lambdas da benzer bir durum.
Jan Hudec

3
Aslında sözdizimsel şekerden çok daha fazlası. İşlevselliklerin çoğu, JVM'de, invokedynamic bytecode +, Tip çıkarım sistemine oldukça ciddi ilerlemeler sağlayan birinci sınıf bir vatandaş olarak uygulanmaktadır. Anonim iç sınıflar olarak uygulanmadı.
Martijn Verburg

1
@ JanHudec: Eh, derleyici aslında onlara saygı duydukları için, sözdizimsel şekerden biraz daha fazladır . Çalışma zamanı onları umursamıyor, bu doğru.
Joachim Sauer

14

Java için evet, isimsiz bir iç sınıf yaratmanın daha iyi bir yolundan başka bir şey değil. Bunun nedeni, java’daki her bit bayt kodunun belirli bir sınıf içinde yaşamaya mecbur olduğu temel karardan kaynaklanmaktadır, ki bunlar artık göz önünde bulundurularak on yıllarca eski kodun ardından değiştirilemez.

Ancak, bu lambda ifadelerinin gerçekte ne olduğu değildir. Bant atlayışındaki çarpılmadan ziyade doğal kavramlar oldukları formalizmde, lambdalar temel yapı taşlarıdır; Hem sözdizimleri hem de insanların onlara karşı tutumu çok farklı. Bilgisayar Programlarının Yapısı ve Yorumlanmasında tamamen lambdalardan oluşan anonim bir özyinelemeli fonksiyon örneği, tüm hesaplama anlayışınızı değiştirebilir. (Ancak, programlamayı öğrenmenin ana akım bir başarı öyküsü olmak için sadece ezoterik olacağından eminim.)


1
Her şeyin lambdalarla uygulanabileceğini öğrenmek bence çok öğretici ve "ezoterik" değil. (Ancak, çoğu "kodlayıcı" ilginç CS teorisine aldırış etmiyor sanırım.) Bu lambdaların özel olduğu anlamına gelmez; bu sadece lambdaların bir tür evrensel yapı olduğu anlamına gelir. SKI birleştiricileri gibi diğerleri de var. Lambdalar fonksiyonel paradigmalarda temel yapı taşlarıdır, ancak belki başka bir paradigmada başka bir şey temel olabilir.
user102008

'' Atlama bandwagon contortion '' için +1: Sık sık bazı dillerin neden diğer popüler dilleri taklit ettiğini ve programcıların neden buna eklediklerini merak ediyorum. Lambdaları severim ve onları Scala, Lisp, Haskell'de çok kullanırım, ancak Java ya da C ++ 'da, diğer dillerde popüler oldukları için dile bağlı bir düşünce gibi hissederler.
Giorgio

2

Evet, sadece sözdizimsel bir şeker, bir lambda yazdığınız her yerde, bu ifadeyi sınıfın lambda bağlamı için çıkarılan işlevsel arayüzü uyguladığı bir yöntemle anonim bir iç sınıf ifadesi olarak yeniden yazabilirsiniz. anlamsal olarak tam olarak eşdeğer olacaktır . Bunu, lambda ifadesini başka bir ifade veya kod satırını değiştirmeden, anonim sınıf ifadesiyle değiştirerek yapabilirsiniz.


1
neden aşağı oy? söylediklerim tamamen doğru
user102008

Yazdıklarınız Java lambdaları için makul bir öneridir ancak bu öneri farklı bir lehine atılmıştır ( doanduyhai.wordpress.com/2012/07/12/… ).
Giorgio

1
@ Giorgio: Ben bir şey "teklif" değilim. Tam olarak ne dediğime katılmıyor musun? Evet, ifadenin içi farklı görünecek, örneğin bir yöntem ekleyeceğiz ve evet, thisdönüştürülmeye ihtiyaç duyacak OuterClass.this. Bu söylediklerimle çelişmiyor - her lambda ifadesi , ifadenin dışında hiçbir şey değiştirmeden , anlamsal olarak eşdeğer bir anonim sınıf ifadesine dönüştürülebilir . İçinin değişmeyeceğini söylemedim.
user102008

3
Söylediklerin yanlış. Lambda anlam ve Anon iç sınıflar değildir tam olarak (bunlar benzer), aynı. Kafamın ait anlam anlamı üst Kapalı Bu değişikliklerin; ve anon iç sınıfları her zaman yeni bir nesnenin örneğiyle sonuçlanır, oysa bir lambda olabilir veya olmayabilir.
Stuart,

1
@StuartMarks: Hayır, cevabımı okumadın. Her birinin diğerinin yaptığı her şeyi yapabileceğini söylemedim. Bir lambda'nın anlamsal olarak aynı olan eşdeğer bir isimsiz sınıfa sahip olduğunu söyledim. Daha önce de söylediğim gibi this, lambda'da sözdizimsel şekerin bir parçasıdır ve anlambilimde bir fark yoktur. Ve uygulamadaki farklılıklar hakkında, uygulama! = Anlambilim. Nesne kimliğindeki farklılıklar hakkında; nesne kimliği, lambdaların işlevselliği için son derece tedirgindir; kimse lambdas / anon sınıflarının nesne kimliğini kontrol etmiyor çünkü yararlı değil.
user102008

1

Joachim Sauer zaten sorunuzu yanıtlamak için iyi bir iş çıkardı, ancak yalnızca önemli olarak gördüğüm bir şeyi ima etti. Lambdalar sınıf olmadığından onlar da böyle derlenmedi. Tüm anonim iç sınıflar, ClassLoader tarafından yüklenmesi gereken bir .class dosyası oluşturulmasına neden olur. Bu yüzden Lambdas kullanmak sadece kodunuzu daha güzel hale getirmekle kalmaz, aynı zamanda derlenmiş kodunuzun boyutunu, ClassLoader'ınızın hafıza alanını ve bitleri sabit sürücünüzden aktarmak için harcadığınız zamanı azaltır.


-1

Hayır değiller.

Bunu söylemenin bir başka yolu da lambdalar nesneye yönelik değil, özlü, ancak anonim bir sınıf veya benim tercihime göre iç sınıfın nesne yönelimli bir şekilde elde edeceği şeyi başarmanın bir yoludur.


1
İşlevsel programlama, Nesne Yönelimli programlamaya tamamen dik olabilir (bakınız: Scala ve F #). Bu, ilke olarak işlevsel programlamayı basitçe beğenmeyen birinin görüşü gibi görünüyor.
KChaloux

1
@KChaloux - İşlevsel bir programlama zorunluluğu değil. Cevap bir Hammerdriver yerine çekiç ve tornavida kullanmayı tercih eden biri tarafından yazılmıştır. OO Programlama, fonksiyonel programlama gibi iyi bir paradigmadır. Bir dilde tercihim onun niyetleri hakkında net olması. Lambdas Java'nın aksi halde OO'nun doğasını çamurlu hissediyorum. Java işlevsel bir dil olarak tasarlanmamıştır. İnsanların ellerinden gelenin en iyisini yapmak için yapıya ihtiyaçları vardır.
Guido Anselmi
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.