Comparator.reversed () lambda kullanarak derlemez


111

Bazı Kullanıcı nesneleri içeren bir listem var ve listeyi sıralamaya çalışıyorum, ancak yalnızca yöntem referansını kullanarak çalışıyor, derleyici lambda ifadesi ile bir hata veriyor:

List<User> userList = Arrays.asList(u1, u2, u3);
userList.sort(Comparator.comparing(u -> u.getName())); // works
userList.sort(Comparator.comparing(User::getName).reversed()); // works
userList.sort(Comparator.comparing(u -> u.getName()).reversed()); // Compiler error

Hata:

com\java8\collectionapi\CollectionTest.java:35: error: cannot find symbol
            userList.sort(Comparator.comparing(u -> u.getName()).reversed());
                                                     ^
symbol:   method getName()
location: variable u of type Object
1 error

Yanıtlar:


145

Bu, derleyicinin tür çıkarım mekanizmasındaki bir zayıflıktır. Lambda'nın türünü anlamak için u, lambda için hedef türünün oluşturulması gerekir. Bu, aşağıdaki şekilde gerçekleştirilir. userList.sort()türden bir argüman bekliyor Comparator<User>. İlk satırda Comparator.comparing()geri dönmesi gerekiyor Comparator<User>. Bu , bir argüman alan bir a Comparator.comparing()ihtiyacı Functionolduğu anlamına gelir User. Bu nedenle, ilk satırdaki lambda utüründe olmalıdır Userve her şey çalışır.

İkinci ve üçüncü satırlarda, hedef yazımı, çağrının varlığı ile bozulur reversed(). Neden olduğundan tam olarak emin değilim; Alıcı ve dönüş türü hem de reversed()vardırComparator<T> geri alıcıya yayılır edilmelidir hedef türü gibi görünüyor öyle, ama öyle değil. (Dediğim gibi, bu bir zayıflık.)

İkinci satırda, yöntem referansı bu boşluğu dolduran ek tür bilgileri sağlar. Derleyici çıkarır, böylece bu verileri, üçüncü hattan yoktur uolduğu Objectbaşarısız (son çare çıkarım geri dönüş).

Açıkçası bir yöntem referansı kullanabilirseniz, bunu yapın ve işe yarayacaktır. Bazen bir yöntem başvurusu kullanamazsınız, örneğin, ek bir parametre iletmek istiyorsanız, bu nedenle bir lambda ifadesi kullanmanız gerekir. Bu durumda, lambda'da açık bir parametre türü sağlarsınız:

userList.sort(Comparator.comparing((User u) -> u.getName()).reversed());

Gelecekteki bir sürümde derleyicinin bu durumu kapsayacak şekilde geliştirilmesi mümkün olabilir.


28
Lambdalar, örtük olarak yazılmış (parametreler için bildirim türü yok) ve açıkça yazılan ; yöntem referansları tam (aşırı yük yok) ve kesin olmayan olarak bölünmüştür . Bir alıcı konumundaki genel bir yöntem çağrısında lambda bağımsız değişkenleri olduğunda ve tür parametreleri diğer bağımsız değişkenlerden tam olarak çıkarılamadığında, açık bir lambda, kesin bir yöntem ref, bir hedef tür ataması veya açık türden tanıklar sağlamanız gerekir. devam etmek için gereken ek tür bilgilerini sağlamak için genel yöntem çağrısı.
Brian Goetz

1
@StuartMarks, derleyicinin böyle davrandığından "tam olarak emin değilsiniz". Ancak dil özelliği ne diyor? Dil spesifikasyonuna göre jenerik türleri belirlemek için yeterli bilgi olmalı mı? Eğer öyleyse, bu bir derleyici hatasıdır ve buna göre dosyalanmalı ve ilgilenilmelidir. Aksi takdirde Java dilinin geliştirilmesi gereken bir alandır. Hangisi?
Garret Wilson

8
Brian'ın yorumlarını, söz konusu spesifikasyonu yazarken kesin olarak ele alabileceğimizi düşünüyorum :-)
minimalis

1
Ne yazık ki bunların hiçbiri, tersine çalışmadığı halde neden tersine çevrilmeden çalıştığını açıklamıyor.
Chris311

90

İki bağımsız değişkeni Comparator.comparingile Comparator.reverseOrder()ikinci bağımsız değişken olarak bu sınırlamayı aşabilirsiniz:

users.sort(comparing(User::getName, reverseOrder()));

4
Güzel. Bunu, açıkça yazılmış bir lambda kullanmaktan daha çok seviyorum. Ya da daha iyisi users.sort(reverseOrder(comparing(User::getName)));.
rolve

10
reverseOrder(Comparator<T>)Yukarıdaki yöntemin içinde java.util.Collectionsdeğil , içinde olduğunu unutmayın Comparator.
rolve
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.