Koleksiyonu diziye dönüştürmenin en kolay yolu?


126

Bir Collection<Foo>. Onu dönüştürmenin en iyi (mevcut bağlamda LoC'de en kısa) yolu Foo[]nedir? Herhangi tanınmış kütüphaneler izin verilir.

UPD: (bu bölümde bir durum daha var; bunun için başka bir iş parçacığı oluşturmaya değer olduğunu düşünüyorsanız yorum bırakın): 1 parametre türünde yani yapıcıyı nereye sahip hale Collection<Foo>getirmeye ne dersiniz ?Bar[]BarFoopublic Bar(Foo foo){ ... }


Bu yanıtı , aynı işlemi benzer performansla ve onunla birlikte açıklamayla gerçekleştirmek için JDK-11'de tanıtılan alternatif bir API ile yaptı. Ayrıca sözdizimi Stream.toArray, JDK'daki mevcut API ile eşleşir .
Naman

Yanıtlar:


257

xKoleksiyon nerede :

Foo[] foos = x.toArray(new Foo[x.size()]);

35
daha basit (daha kolay) ama en iyisi değil (bellek): x.toArray(new Foo[0]) - dokümantasyon : okumak için zaman yok ...
user85421

6
@Carlos aslında daha iyi bellek kullanıyor (new Foo[0]). Collection.toArray belgelerine göre, "@param, eğer yeterince büyükse, bu koleksiyonun öğelerinin depolanacağı dizidir", bu da onları doğrudan bu yeni dizide depolayacağı anlamına gelir. Eğer ona 0 boyutunda bir dizi verirseniz, yeni bir dizi oluşturacaktır, yani küçük bir diziniz ve gereksiz olduğunda yapılan büyük bir diziniz var demektir.
corsiKa

4
@glowcoder - ancak boş bir diziyi bir kez statik sabit olarak tanımlarsanız bu en aza indirilebilir. toArrayDoğru türde bir hedef dizi oluşturmak için sadece bir ipucu . Ve bu durumda, dürüst olmak gerekirse, uygulamamda fazladan tek bir boş dizi umursamam. Bu gürültü seviyesinin çok altında.
Andreas Dolk

2
@glowcoder - tam da bu yüzden ( denedim ) kullanmanın new Foo[0]daha basit olduğunu yazdım "ama en iyisi değil (bellek)" ... yani, çözümümün daha kolay olduğunu ama en iyisi olmadığını söyledim (kullanmamın nedeni bu :).
user85421

21
Senkronize bir koleksiyon kullanıyor olsanız bile bu kodun iş parçacığı güvenli olmadığını unutmayın. Çoğu durumda kendi kendine davranır, ancak x.size () ve x.toArray () çağrısı arasında bir öğe silinirse, ortaya çıkan dizi sonunda fazladan bir boş öğe içerecektir. new Foo[0]Carlos tarafından teklif edilen varyant bu sorunu düşmez.
Jules

36

Java 8 kullanarak güncellenmiş soruya alternatif çözüm:

Bar[] result = foos.stream()
    .map(x -> new Bar(x))
    .toArray(size -> new Bar[size]);

35
Bu kısaltılabilir Bar[] result = foos.stream().map(Bar::new).toArray(Bar[]::new);
lpandzic

Sözdizimi açısından, kabul edilen yanıtı daha çok tercih ederim. Keşke insanların hepsi Python'a geçebilsin.
Eric Chen

@EricChen Java'dan yorumlanmış ve dinamik olarak yazılmış bir dil olan Python'a geçin - kodlama sözdizimi ve sayı satırları farklı olduğundan 'derlenmiş ve statik olarak yazılmış dil' mi? İyi bir fikir değil.
RafiAlhamd

10

Birden fazla kullanırsanız veya bir döngüde kullanırsanız, bir sabit

public static final Foo[] FOO = new Foo[]{};

ve dönüşümü aynen yapın

Foo[] foos = fooCollection.toArray(FOO);

toArrayYöntem, hedef dizinin doğru türünü belirlemek için boş dizi çekmek ve sizin için yeni bir dizi oluşturur.


İşte güncelleme için önerim:

Collection<Foo> foos = new ArrayList<Foo>();
Collection<Bar> temp = new ArrayList<Bar>();
for (Foo foo:foos) 
    temp.add(new Bar(foo));
Bar[] bars = temp.toArray(new Bar[]{});

1
ups, constJava değil! public static final Foo[] FOO = {}
user85421

1
neden halka açık olsun?
Zoltán

@ Zoltán - neden olmasın? Değişmez, dolayısıyla bir güvenlik sorunu oluşturmaz. Biraz dağınıklıktır, ancak diğer kodlarda yararlı olabilir, bu nedenle genellikle zararsızdır. Belki tüm bu sabitlerle merkezi bir sınıf bile yaratabilir ve sonra import staticbunlara ulaşmak için kullanabilirsiniz.
Jules

@Jules dizinin referansı değişmez, ancak içeriği değişmez. Sınıfın dışındaki herkes dizinin öğelerini serbestçe değiştirebilir. Öte yandan, genel bir kural olarak, tüm alanların sınıf dışında ihtiyaç duyulana kadar özel yapılması gerektiğine inanıyorum.
Zoltán

2
Sıfır uzunlukta olduğundan değiştirilebilecek içerik yok
Jules

5

JDK / 11, bir dönüştürme alternatif yol ile Collection<Foo>bir etmek Foo[]yararlanmak olabilir Collection.toArray(IntFunction<T[]> generator)gibidir:

Foo[] foos = fooCollection.toArray(new Foo[0]); // before JDK 11
Foo[] updatedFoos = fooCollection.toArray(Foo[]::new); // after JDK 11

Posta listesinde @Stuart tarafından açıklandığı gibi (benim vurgu), bunun performansı esasen mevcut olanla aynı olmalıdır.Collection.toArray(new T[0]) -

Sonuç olarak,) kullanan uygulamalar en hızlıdır, Arrays.copyOf(çünkü muhtemelen bir içseldir .

Yeni tahsis edilen dizinin sıfır doldurulmasını önleyebilir çünkü tüm dizi içeriğinin üzerine yazılacağını bilir. Bu, genel API'nin nasıl göründüğüne bakılmaksızın geçerlidir.

API'nin JDK içindeki uygulaması şu şekildedir:

default <T> T[] toArray(IntFunction<T[]> generator) {
    return toArray(generator.apply(0));
}

Varsayılan uygulama generator.apply(0), sıfır uzunluklu bir dizi almayı çağırır ve ardından basitçe çağırır toArray(T[]). Bu Arrays.copyOf() hızlı yoldan geçer , bu yüzden aslında aynı hızdır toArray(new T[0]).


Not : - API kullanımı,değerlerlekod için kullanıldığında geriye dönük bir uyumsuzluk ile birlikte yönlendirilmelidir,nullörneğin,toArray(null)bu çağrılar artık mevcut olduğundan dolayı belirsiztoArray(T[] a)olacak ve derlenemeyeceğinden.



3

Orijinal için doublep cevabına bakınız :

Foo[] a = x.toArray(new Foo[x.size()]);

Güncellemeye gelince:

int i = 0;
Bar[] bars = new Bar[fooCollection.size()];
for( Foo foo : fooCollection ) { // where fooCollection is Collection<Foo>
    bars[i++] = new Bar(foo);
}    

3

İşte güncelleme bölümündeki vaka için son çözüm (Google Koleksiyonları yardımıyla):

Collections2.transform (fooCollection, new Function<Foo, Bar>() {
    public Bar apply (Foo foo) {
        return new Bar (foo);
    }
}).toArray (new Bar[fooCollection.size()]);

Ancak, buradaki temel yaklaşım doublep'nin cevabında belirtilmişti ( toArrayyöntemi unuttum ).


1
Doublep'nin bu çözüm için de geçerli olan iş parçacığı güvenliği hakkındaki cevabına bakın. new Bar[0]sorunu önler.
Jules

-1

Örneğin, Student class öğelerini içeren ArrayList koleksiyonunuz var:

List stuList = new ArrayList();
Student s1 = new Student("Raju");
Student s2 = new Student("Harish");
stuList.add(s1);
stuList.add(s2);
//now you can convert this collection stuList to Array like this
Object[] stuArr = stuList.toArray();           // <----- toArray() function will convert collection to array
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.