List.of ve Arrays.asList arasındaki fark nedir?


117

Java 9, listeler için yeni fabrika yöntemlerini tanıttı List.of:

List<String> strings = List.of("first", "second");

Önceki ve yeni seçenek arasındaki fark nedir? Yani, bunun arasındaki fark nedir:

Arrays.asList(1, 2, 3);

ve bu:

List.of(1, 2, 3);

1
Ayrıca Stuart "Beaker" Marks'ın bu konuşmasına bakın .
user1803551

20
@ user1803551 Hayal kırıklığınızı anlasam da, bu mantık gerçekten istenmeyen bir emsal oluşturabilir. Bir çok soru burada en 'açıkça belirtildiği' (kimse bu nasıl tanımlar bağlı olarak) olduğu bir cevabın var. Bu tartışmayı
metaya

4
@ user1803551 Javadocs, bu iki yöntemin uygulama ayrıntıları arasındaki farktan bahsetmez (alan tüketimi veya performans gibi). Bence insanlar da bu detayları bilmek ister.
ZhekaKozlov

5
@ZhekaKozlov Kabul edilen ve çok olumlu oylanan cevap da değil. Bu size kabul edilen standartlar hakkında ne anlatıyor? Hatta dokümanlardakinden daha az bilgiye sahiptir (serileştirme, kimlik, sıralama). Herhangi bir şey varsa, bu bilgiyi eklemek için OpenJDK'ye bir istek gönderin.
user1803551

3
Bu soru meta üzerinde tartışılıyor .
Dimitris Fasarakis Hilliard

Yanıtlar:


173

Arrays.asListtarafından döndürülen liste ise bir değişken listesini döndürür List.ofolduğunu değişmez :

List<Integer> list = Arrays.asList(1, 2, null);
list.set(1, 10); // OK

List<Integer> list = List.of(1, 2, 3);
list.set(1, 10); // Fails with UnsupportedOperationException

Arrays.asListboş öğelere izin verirken List.of:

List<Integer> list = Arrays.asList(1, 2, null); // OK
List<Integer> list = List.of(1, 2, null); // Fails with NullPointerException

contains null değerlerle farklı davranır:

List<Integer> list = Arrays.asList(1, 2, 3);
list.contains(null); // Returns false

List<Integer> list = List.of(1, 2, 3);
list.contains(null); // Fails with NullPointerException

Arrays.asListaktarılan dizinin bir görünümünü döndürür, böylece dizideki değişiklikler de listeye yansıtılır. Çünkü List.ofbu doğru değil:

Integer[] array = {1,2,3};
List<Integer> list = Arrays.asList(array);
array[1] = 10;
System.out.println(list); // Prints [1, 10, 3]

Integer[] array = {1,2,3};
List<Integer> list = List.of(array);
array[1] = 10;
System.out.println(list); // Prints [1, 2, 3]

22
Bir listenin nasıl oluşturulduğuna bağlı olarak farklı davranması bana pek nesne odaklı görünmüyor. Belki List.of bir ImmutableList türü döndürdüyse bu mantıklı olacaktır. Bu, burada çok sızdıran bir soyutlamadır.
Sandy Chapman

5
Java geliştiricisi değilim, bu yüzden bunu sıradan bir gözlem olarak kabul edin. Davranışın farklı olması için muhtemelen iyi bir neden vardır, ancak örnek gibi bir List <Tamsayı> döndüren bir yöntemim olsaydı, kontrol edersem bir çalışma zamanı istisnası alıp almayacağımı bilmem için arayüz yeterli olmazdı boş değerler için. Aynı şekilde, bu yöntem uygulamasındaki bir değişiklik, eğer bu kontrol başka bir yerde olursa, yöntemimin çağrı sitesinden uzaktaki kodu etkileyebilir. @Nicolai
Sandy Chapman

8
@SandyChapman bu bazıları (veya çoğu?) İçin beklenmedik bir davranış olabilir, ancak belgelenmiş bir davranıştır. Gönderen List.contains(Object o)'ın javadoc : 'Atar [...] NullPointerException - Belirtilen eleman null ve bu liste boş elemanları (opsiyonel) izin vermediğinde'. Veya arayüzün uzun girişinden çok az kişinin okuduğu: "Bazı koleksiyon uygulamalarının içerebilecekleri öğeler üzerinde kısıtlamaları vardır"
Aaron,

11
@Aaron en azından iyi belgelenmiş, sızdıran bir soyutlama :)
Sandy Chapman

6
@Sandy Chapman: List.of yok bazı return ImmutableListtürü, gerçek ismi sadece kamuya açık olmayan uygulama detay. Herkese açıksa ve birisi Listtekrar yayınladıysa, fark neredeydi? İçin fark nerede Arrays.asListbir halka açık olmayan döndüren Listçalışırken bir durum oluşturmaz, uygulama addya da removeya göre liste döndürülen Collections.unmodifiableListhangi hiç hiçbir modifikasyon verir? Her şey Listarayüzde belirtilen sözleşmelerle ilgili . Opsiyonel yöntemlerle Koleksiyonları arayüzleri hep ... Java 1.2 beri saf olmayan cepten vardı
Holger

31

Arasındaki farklar Arrays.asListveList.of

JavaDocs ve Stuart Marks'ın (veya önceki sürümlerinin) bu konuşmasına bakın .

Kod örnekleri için aşağıdakileri kullanacağım:

List<Integer> listOf = List.of(...);
List<Integer> asList = Arrays.asList(...);
List<Integer> unmodif = Collections.unmodifiableList(asList);

Yapısal değişmezlik (Veya: değiştirilemezlik)

Yapısal olarak değiştirmeye yönelik herhangi bir girişim List.of, bir UnsupportedOperationException. Bu, ekleme , ayarlama ve kaldırma gibi işlemleri içerir . Bununla birlikte, listedeki nesnelerin içeriğini değiştirebilirsiniz (nesneler değişmez değilse), böylece liste "tamamen değişmez" olmaz.

Bu, ile oluşturulan değiştirilemez listeler için aynı kaderdir Collections.unmodifiableList. Yalnızca bu liste orijinal listenin bir görünümüdür , dolayısıyla orijinal listeyi değiştirirseniz değişebilir.

Arrays.asListtamamen değişmez değildir, üzerinde bir kısıtlama yoktur set.

listOf.set(1, "a");  // UnsupportedOperationException
unmodif.set(1, "a"); // UnsupportedOperationException
asList.set(1, "a");  // modified unmodif! unmodif is not truly unmodifiable

Benzer şekilde, destek dizisini değiştirmek (tutarsanız) listeyi değiştirir.

Yapısal değişmezlik, savunma kodlaması, eşzamanlılık ve güvenlikle ilgili olarak bu cevabın kapsamı dışında kalan birçok yan etkiyle birlikte gelir.

Boş düşmanlık

List.ofve Java 1.5'ten beri herhangi bir koleksiyon nullbir öğe olarak izin vermez . nullBir öğe olarak geçmeye çalışmak veya hatta bir arama, bir NullPointerException.

Yana Arrays.asList1.2 dan bir koleksiyon (Koleksiyonları Framework), o verir nulls.

listOf.contains(null);  // NullPointerException
unmodif.contains(null); // allowed
asList.contains(null);  // allowed

Serileştirilmiş form

Yana List.ofJava 9 tanıtılan ve bu yöntemle oluşturulan listeler kendi (ikili) tefrika formu var olmuştur, daha önce JDK sürümleri (hayır üzerine serisi kaldırılan olamaz ikili uyumluluk ). Ancak, örneğin JSON ile de / serileştirebilirsiniz.

Kimlik

Arrays.asListnew ArrayListreferans eşitsizliğini garanti eden dahili çağrılar .

List.ofdahili uygulamaya bağlıdır. Döndürülen örnekler referans eşitliğine sahip olabilir, ancak bu garanti edilmediğinden buna güvenemezsiniz.

asList1 == asList2; // false
listOf1 == listOf2; // true or false

List.equalsNasıl oluşturulduklarına veya hangi işlemleri desteklediklerine bakılmaksızın, aynı öğeleri aynı sırayla içeriyorlarsa listelerin eşit (aracılığıyla ) olduğunu belirtmek gerekir .

asList.equals(listOf); // true i.f.f. same elements in same order

Uygulama (uyarı: ayrıntılar sürümlere göre değişebilir)

Listesindeki öğe sayısı List.of2 veya daha azsa, öğeler özel (dahili) bir sınıfın alanlarında saklanır. Bir örnek, 2 öğeyi (kısmi kaynak) depolayan listedir:

static final class List2<E> extends AbstractImmutableList<E> {
    private final E e0;
    private final E e1;

    List2(E e0, E e1) {
        this.e0 = Objects.requireNonNull(e0);
        this.e1 = Objects.requireNonNull(e1);
    }
}

Aksi takdirde, ile benzer şekilde bir dizide saklanırlar Arrays.asList.

Zaman ve Mekan verimliliği

List.ofAlan bazlı (boyut <2) olan uygulamalar bazı işlemler ile biraz daha hızlı yapar. Örnek olarak, size()dizi uzunluğunu getirmeden bir sabit döndürebilir ve contains(E e)yineleme ek yükü gerektirmez.

Değiştirilemez bir liste oluşturmak List.ofda daha hızlıdır. Yukarıdaki yapıcıyı 2 referans atamasıyla (ve hatta keyfi sayıda öğe için olanı) karşılaştırın:

Collections.unmodifiableList(Arrays.asList(...));

bu 2 liste artı diğer ek yükler oluşturur. Alan açısından, UnmodifiableListambalajı ve birkaç kuruş tasarruf edersiniz . Sonuçta, HashSeteşdeğerdeki tasarruf daha ikna edicidir.


Sonuç zamanı: List.ofdeğişmeyen Arrays.asListbir liste istediğinizde ve değişebilen bir liste istediğinizde kullanın (yukarıda gösterildiği gibi).


1
Bu cevap neden var merak insanlar için bkz bu .
user1803551

3
Arrays.asListtamamen değiştirilebilir değil. asList.add(1);bir atar UnsupportedOperationException.
mapeters

"Boş düşman", onu ifade etmenin harika bir yoludur. List.ofİnsanların aramak isteyebilecekleri containsve bir NullPointerException tarafından şaşırtılmayacakları herhangi bir zamanı kullanamıyorum .
Numen

14

List.of ve Arrays.asList arasındaki farkları özetleyelim

  1. List.ofen iyi veri seti daha az olduğunda ve değişmediğinde Arrays.asListkullanılabilirken, en iyi şekilde büyük ve dinamik veri kümesi durumunda kullanılabilir.

  2. List.ofçok daha az ek yük alanı kaplar çünkü alan tabanlı uygulamaya sahiptir ve hem sabit ek yük hem de öğe başına temelde daha az yığın alanı tüketir. iken Arrays.asListalmak daha havai uzayda o yığın fazla nesne oluşturur başlatma sırasında çünkü.

  3. Tarafından döndürülen koleksiyon List.ofsabittir ve bu nedenle iş parçacığı açısından güvenlidir, ancak tarafından döndürülen Koleksiyon Arrays.asListdeğiştirilebilir ve iş parçacığı güvenli değildir. (Değişmez toplama örnekleri genellikle değiştirilebilir emsallerine göre çok daha az bellek tüketir.)

  4. List.ofizin vermez boş iken elemanlarını Arrays.asListtanır boş elemanlar.


2
"Değişmez toplama örnekleri genellikle değiştirilebilir emsallerine göre çok daha az bellek tüketir." - Gerçekten mi? Bunu biraz detaylandırmak ister misiniz - güvenli bir şekilde paylaşılabilecekleri için mi yoksa örneklerin kendilerinin bir şekilde daha verimli bir şekilde uygulanabileceğini mi kastediyorsunuz?
Hulk

1
@Hulk Cevap veren kişi alan verimliliği konusunda haklı. Stuart Marks'ın konuşmasına bakın: youtu.be/q6zF3vf114M?t=49m48s
ZhekaKozlov

2
@ZhekaKozlov görünür genel olarak doğru gibi Yani, ama bahsederken bu doğru çok şüpheci Arrays.asListkarşı List.ofeski anlamıyla bir dizi etrafında sarıcı olduğu göz önüne alındığında,. En azından OpenJDK uygulamasının son derece küçük bir ek yükü var gibi görünüyor. Aslında, List.ofaktarılan herhangi bir dizinin kopyalarını yapmak gerekir, bu nedenle dizinin kendisi yakında GC olacaksa, List.ofönemli ölçüde daha büyük bir bellek ayak izine sahip gibi görünür .
Chris Hayes

4
@ChrisHayes En azından List.of(x)ve List.of(x, y)dizileri hiç
ayırmadıkları

2
@Hulk: List.ofHer seferinde yeni listeler döndürmek için yöntemlerin gerekli olmadığını unutmayın . Bu listelerin tanımlanmamış bir kimliği vardır, bu nedenle JVM düzeyinde önbelleğe alma veya tekilleştirme veya ölçeklendirme olabilir. Bu versiyonda değilse, belki bir sonraki versiyonda. Sözleşme izin veriyor. Buna karşılık, Array.asListsonuçta ortaya çıkan liste, tüm çift yönlü olarak değişmeyi yansıtan, dizi üzerinde değiştirilebilir bir görünüm olduğundan, geçtiğiniz dizinin kimliğine bağlıdır.
Holger

3

Bunun haricinde cevaplardan her ikisi üzerinde belli işlemler vardır List::ofve Arrays::asListfarklılık gösterir:

+----------------------+---------------+----------+----------------+---------------------+
|      Operations      | SINGLETONLIST | LIST::OF | ARRAYS::ASLIST | JAVA.UTIL.ARRAYLIST |
+----------------------+---------------+----------+----------------+---------------------+
|          add         |             |       |              |          ✔️          |
+----------------------+---------------+----------+----------------+---------------------+
|        addAll        |             |       |              |          ✔️          |
+----------------------+---------------+----------+----------------+---------------------+
|         clear        |             |       |              |          ✔️          |
+----------------------+---------------+----------+----------------+---------------------+
|        remove        |             |       |              |          ✔️          |
+----------------------+---------------+----------+----------------+---------------------+
|       removeAll      |       ❗️       |        |        ❗️       |          ✔️          |
+----------------------+---------------+----------+----------------+---------------------+
|       retainAll      |       ❗️       |       |        ❗️        |          ✔️          |
+----------------------+---------------+----------+----------------+---------------------+
|      replaceAll      |             |       |        ✔️       |          ✔️          |
+----------------------+---------------+----------+----------------+---------------------+
|          set         |             |       |        ✔️       |          ✔️          |
+----------------------+---------------+----------+----------------+---------------------+
|         sort         |       ✔️       |        |        ✔️      |          ✔️          |
+----------------------+---------------+----------+----------------+---------------------+
|  remove on iterator  |             |       |              |          ✔️          |
+----------------------+---------------+----------+----------------+---------------------+
| set on list-iterator |             |       |        ✔️       |          ✔️          |
+----------------------+---------------+----------+----------------+---------------------+
  1. ✔️, yöntemin desteklendiği anlamına gelir
  2. ❌, bu yöntemi çağırmanın bir UnsupportedOperationException oluşturacağı anlamına gelir
  3. ❗️, yöntemin yalnızca yöntemin bağımsız değişkenleri bir mutasyona neden olmazsa desteklendiği anlamına gelir, örneğin, Collections.singletonList ("foo"). ) bir UnsupportedOperationException oluşturur

Koleksiyonlar hakkında daha fazla bilgi :: singletonList Vs. Listesi


1
java sınavı için cevap
povis
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.