Bagaimana cara saya bergabung dengan dua daftar di Jawa?

749

Ketentuan: jangan memodifikasi daftar asli; Hanya JDK, tidak ada perpustakaan eksternal. Poin bonus untuk versi satu-liner atau JDK 1.3.

Apakah ada cara yang lebih sederhana daripada:

List<String> newList = new ArrayList<String>();
newList.addAll(listOne);
newList.addAll(listTwo);
Robert Atkins
sumber
5
Jika Anda melakukan ini semata-mata untuk tujuan iterasi, lihat pertanyaan lain - ada solusi google jambu dan java 8 stackoverflow.com/questions/4896662/…
Boris Treukhov
Solusi Java 8 dengan metode utilitas: stackoverflow.com/a/37386846/1216775
akhil_mittal
Setelah membaca beberapa jawaban, saya minta maaf saya bertanya.
Anthony Rutledge

Jawaban:

591

Di Jawa 8:

List<String> newList = Stream.concat(listOne.stream(), listTwo.stream())
                             .collect(Collectors.toList());
Dale Emery
sumber
82
Aduh, itu ada di Java 8? Secara teknis Anda menang saya kira, tapi itu heck of a long line :-)
Robert Atkins
4
Untuk pembaca biasa, berikut adalah solusi yang lebih pendek menggunakan Java _ Streams: stackoverflow.com/a/34090554/363573
Stephan
7
Ini jelek tapi setidaknya lancar dan dapat digunakan tanpa lambda multi-baris. Saya benar-benar berharap ada addAll yang lancar yang mengembalikan daftar yang telah dikonatinasi.
Usman Ismail
6
Saya kira perlu dicatat bahwa sangat mudah untuk mendapatkan daftar yang berbeda dari ini juga, seperti:List<String> newList = Stream.concat(listOne.stream(), listTwo.stream()).distinct().collect(Collectors.toList());
Roger
1
Alternatif konser: aliran sungaiStream.of(listOne, listTwo).flatMap(Collection::stream).collect(Collectors.toList())
Peter Walser
569

Dari atas kepala saya, saya dapat mempersingkatnya dengan satu baris:

List<String> newList = new ArrayList<String>(listOne);
newList.addAll(listTwo);
AdamC
sumber
156
Meskipun secara teknis Anda benar, Anda telah mempersingkatnya dengan satu baris, asimetri ini menggangguku. Cukup bahwa saya lebih bahagia untuk "menghabiskan" garis tambahan.
Robert Atkins
13
Apakah tidak ada masalah di sini di mana array internal newList akan diinisialisasi ke ukuran listOne dan kemudian harus berpotensi berkembang ketika menambahkan semua item dari listTwo? Apakah lebih baik untuk mengambil ukuran dari setiap daftar dan menggunakannya untuk mengukur array baru?
Eric
2
Ini adalah solusi yang paling berhasil bagi saya. Saya membuat perbandingan pada kinerja berbagai solusi yang keluar pemenang ini, bersama-sama dengan membuat daftar kosong dan kemudian addAll()keduanya. Saya mencoba semua yang menyarankan untuk tidak menyalin daftar dan hasilnya ada banyak overhead yang tidak kita butuhkan saat ini.
manuelvigarcia
bagus tetapi Anda bahkan dapat membuatnya lebih pendek: Daftar daftar = ArrayList baru <> (list1) .addAll (list2);
kecepatan
1
@velocity: tidak, itu tidak akan berhasil. addAll(Collection)mengembalikan a boolean.
Stijn Van Bael
306

Anda bisa menggunakan pustaka -koleksi Apache commons :

List<String> newList = ListUtils.union(list1, list2);
Guillermo
sumber
52
Bagus, tetapi membutuhkan apache commons. Dia memang menentukan 'tidak ada perpustakaan eksternal'
Quantum7
101
@ Quantum7, masih berguna untuk orang lain;) Juga, apache commons bahkan perpustakaan eksternal? Saya tidak memulai apapun tanpa itu!
kisah
28
@ Platinum Tidak, menurut dokumen ListUtils.union persis sama dengan kode OP. Tetapi mungkin menyesatkan untuk menggunakan operasi SET ("Union") dalam konteks daftar. Saya dapat melihat bagaimana Anda dapat mengharapkan ini untuk menghapus duplikat atau sesuatu, tetapi tampaknya metode ini tidak melakukan itu.
Quantum7
24
Hindari Koleksi Apache Commons. Ini bukan typesafe, tidak ada obat generik. Hebat jika Anda menggunakan Java 1.4, tetapi untuk Java 5 dan di atasnya, saya lebih suka Google Guava.
Michael Piefel
11
@MichaelPiefel Apache Commons Collections 4 terbaru aman digunakan. Dengan referensi metode Java 8, utilitas statis semacam ini menjadi sangat penting.
mingfai
93

Salah satu persyaratan Anda adalah mempertahankan daftar asli. Jika Anda membuat daftar baru dan menggunakan addAll(), Anda secara efektif menggandakan jumlah referensi ke objek dalam daftar Anda. Ini dapat menyebabkan masalah memori jika daftar Anda sangat besar.

Jika Anda tidak perlu mengubah hasil gabungan, Anda dapat menghindari ini menggunakan implementasi daftar kustom. Kelas implementasi kustom lebih dari satu baris, jelas ... tetapi menggunakannya pendek dan manis.

CompositeUnmodifiableList.java:

public class CompositeUnmodifiableList<E> extends AbstractList<E> {

    private final List<E> list1;
    private final List<E> list2;

    public CompositeUnmodifiableList(List<E> list1, List<E> list2) {
        this.list1 = list1;
        this.list2 = list2;
    }

    @Override
    public E get(int index) {
        if (index < list1.size()) {
            return list1.get(index);
        }
        return list2.get(index-list1.size());
    }

    @Override
    public int size() {
        return list1.size() + list2.size();
    }
}

Pemakaian:

List<String> newList = new CompositeUnmodifiableList<String>(listOne,listTwo);
Kevin K.
sumber
15
Ini adalah jawaban nyata untuk pertanyaan ini.
Wouter Lievens
9
Ini adalah solusi yang bisa diterapkan, tetapi perlu dicatat bahwa jika objek daftar yang mendasarinya berubah (list1, list2), konten dari daftar ini berubah. Anda mungkin tidak dapat memodifikasi instance dari CompositeUnmodifiableList itu sendiri tetapi jika Anda bisa mendapatkan referensi ke daftar asli, maka Anda bisa. Juga bagi mereka yang tidak terbiasa: pengubah akhir hanya mempengaruhi referensi ke objek daftar itu sendiri tidak dapat berubah tetapi masih mungkin untuk isi daftar untuk berubah!
jwj
3
@jwj semua poin yang sangat bagus, terima kasih. Nama kelas mungkin pantas mendapat penjelasan. Saya melihat kelas ini melakukan sesuatu yang sangat mirip dengan Collections.unmodifiableList()metode, yang membungkus daftar untuk membuatnya tidak dapat dimodifikasi. CompositeUnmodifiableListmelakukan hal yang sama, kecuali membungkus dua daftar dan memberikan tampilan gabungan. Semua poin yang Anda buat CompositeUnmodifiableListjuga berlaku Collections.unmodifiableList()juga.
Kevin K
2
Konstruktor dapat mengambilList<? extends E>
Patrick Parker
84

Mungkin tidak sederhana, tetapi menarik dan jelek:

List<String> newList = new ArrayList<String>() { { addAll(listOne); addAll(listTwo); } };

Jangan menggunakannya dalam kode produksi ...;)

tembakan
sumber
44
Jelek dan jahat, seperti hampir semua penggunaan inisialisasi penjepit ganda. Ini lebih pendek, meskipun;)
Jorn
4
@MarnixKlooster: Eclipse tahu bahwa Anda tidak boleh menggunakannya dan membuatnya tidak menyenangkan untuk digunakan ;-)
Joachim Sauer
20
Meskipun secara fisik satu baris, saya tidak menganggap ini "satu-liner".
splungebob
11
mengapa orang membenci inisialisasi blok anonim
NimChimpsky
18
@NimChimpsky Saya pikir itu sebagian besar karena itu bukan hanya penginisialisasi blok anonim, tetapi Anda benar-benar membuat subkelas anonim dari ArrayList. Yang sedang berkata, jika Anda mempercayai hasil pertanyaan Initilisasi Double Brace ini , sepertinya membenci DBI sebagian besar adalah masalah selera dan optimasi mikro. Sejauh yang saya tahu, tidak ada hukuman besar untuk melakukannya. Kelemahan liciknya adalah jika Anda pernah mencoba membandingkan kelasnya karena itu bukan ArrayList.
Patrick
75

Satu baris Java 8 lainnya:

List<String> newList = Stream.of(listOne, listTwo)
                            .flatMap(Collection::stream)
                            .collect(Collectors.toList());

Sebagai bonus, karena Stream.of()variadik, Anda dapat menggabungkan daftar sebanyak yang Anda suka.

List<String> newList = Stream.of(listOne, listTwo, listThree)
                            .flatMap(Collection::stream)
                            .collect(Collectors.toList());
Menandai
sumber
35
x -> x.stream()bisa diganti dengan Collection::stream.
Martin
10
... atau bahkan dengan List::stream.
MC Kaisar
73

Tidak sederhana, tetapi tanpa mengubah ukuran overhead:

List<String> newList = new ArrayList<>(listOne.size() + listTwo.size());
newList.addAll(listOne);
newList.addAll(listTwo);
Martin
sumber
55

Menemukan pertanyaan ini mencari untuk menggabungkan jumlah daftar sewenang-wenang, tidak mengurus perpustakaan eksternal. Jadi, mungkin itu akan membantu orang lain:

com.google.common.collect.Iterables#concat()

Berguna jika Anda ingin menerapkan logika yang sama ke sejumlah koleksi berbeda dalam satu untuk ().

Yuri Geinish
sumber
9
Sebagai contoh: Lists.newArrayList (Iterables.concat (list1, list2));
meilechh
Anda harus menelepon com.google.common.collect.Iterators#concat(java.util.Iterator<? extends java.util.Iterator<? extends T>>)alih-alih Iterables#concat(); karena nanti masih menyalin elemen ke tautan temp!
bob
45

Java 8 ( Stream.ofdan Stream.concat)

Solusi yang diusulkan adalah untuk tiga daftar meskipun itu dapat diterapkan untuk dua daftar juga. Di Java 8 kita dapat menggunakan Stream.of atau Stream.concat sebagai:

List<String> result1 = Stream.concat(Stream.concat(list1.stream(),list2.stream()),list3.stream()).collect(Collectors.toList());
List<String> result2 = Stream.of(list1,list2,list3).flatMap(Collection::stream).collect(Collectors.toList());

Stream.concatmengambil dua aliran sebagai input dan menciptakan aliran gabungan yang malas yang elemen-elemennya adalah semua elemen dari aliran pertama diikuti oleh semua elemen dari aliran kedua. Karena kami memiliki tiga daftar, kami telah menggunakan metode ini (Stream.concat ) dua kali.

Kami juga dapat menulis kelas utilitas dengan metode yang mengambil sejumlah daftar (menggunakan varargs ) dan mengembalikan daftar gabungan sebagai:

public static <T> List<T> concatenateLists(List<T>... collections) {
        return Arrays.stream(collections).flatMap(Collection::stream).collect(Collectors.toList()); 
}

Maka kita dapat menggunakan metode ini sebagai:

List<String> result3 = Utils.concatenateLists(list1,list2,list3);
akhil_mittal
sumber
Anda mungkin bersedia mengatakan Daftar <String> result1 = Stream.concat (Stream.concat (list1.stream (), list2.stream ()), list3.stream ()). Collect (Collectors.toList ()); di operator pertama Anda. Tolong perbaiki.
WebComer
44

Berikut ini adalah solusi java 8 menggunakan dua baris:

List<Object> newList = new ArrayList<>();
Stream.of(list1, list2).forEach(newList::addAll);

Sadarilah bahwa metode ini tidak boleh digunakan jika

  • asal newListtidak diketahui dan mungkin sudah dibagikan dengan utas lainnya
  • aliran yang memodifikasi newListadalah aliran paralel dan akses ke newListtidak disinkronkan atau threadsafe

karena pertimbangan efek samping.

Kedua kondisi di atas tidak berlaku untuk kasus menggabungkan dua daftar di atas, jadi ini aman.

Berdasarkan jawaban ini untuk pertanyaan lain.

SpaceTrucker
sumber
12
Jika saya tidak salah ini sebenarnya tidak dianjurkan - docs.oracle.com/javase/8/docs/api/java/util/stream/… Silakan lihat bagian efek samping. > Efek samping dalam parameter perilaku untuk mengalirkan operasi, secara umum, tidak disarankan, karena sering kali dapat mengakibatkan pelanggaran tanpa disadari terhadap persyaratan kewarganegaraan, serta bahaya keselamatan benang lainnya. Jadi dalam hal ini lebih baik menggunakan Collectors.toList ()
Anton Balaniuc
@AntonBalaniuc Pertanyaannya adalah apakah ini benar-benar efek samping. Pada saat newListitu tidak dapat diamati oleh utas lainnya. Tetapi Anda benar bahwa ini mungkin tidak boleh dilakukan jika tidak diketahui dari mana nilai newListberasal (misalnya jika newListdisahkan sebagai parameter.
SpaceTrucker
2
Saya penasaran; mengapa .forEach(newList::addAll);bukannya .collect(Collectors.toList());?
11684
4
@ 11684 karena pengumpul akan mengumpulkan a List<List<Object>>. Apa yang mungkin ada dalam pikiran Anda adalah sesuatu seperti ini: stackoverflow.com/questions/189559/…
SpaceTrucker
@ SpaceTrucker Ups, saya mengabaikannya. Terima kasih telah membereskan kebingungan saya. Ya, saya seharusnya memikirkannya flatMap.
11684
34

Ini sederhana dan hanya satu baris, tetapi akan menambahkan konten listTwo ke listOne. Apakah Anda benar-benar perlu memasukkan konten ke daftar ketiga?

Collections.addAll(listOne, listTwo.toArray());
ceklock
sumber
11
Tidak mengubah daftar asli adalah salah satu kriteria, tetapi ini berguna untuk memiliki di sini sebagai contoh untuk situasi di mana itu bukan kendala.
Robert Atkins
1
Terima kasih, atau bahkan listOne.addAll (listTwo) yang lebih sederhana
Jay
27

Sedikit lebih sederhana:

List<String> newList = new ArrayList<String>(listOne);
newList.addAll(listTwo);
Tim
sumber
Apakah ini akan menyebabkan String yang digandakan? Berarti String yang ada di kedua daftar akan ada dua kali di daftar yang dihasilkan?
AgentKnopf
4
@ Zainodis Ya, mungkin ada duplikat. The ListStruktur membebankan ada kendala keunikan. Anda dapat menghapus dupes dengan melakukan hal yang sama dengan set. Set<String> newSet = new HashSet<>(setOne); newSet.addAll(setTwo);
Patrick
20

Sedikit lebih pendek adalah:

List<String> newList = new ArrayList<String>(listOne);
newList.addAll(listTwo);
Jorn
sumber
17

Anda dapat membuat metode utilitas Java 8 generik untuk menyelesaikan sejumlah daftar .

@SafeVarargs
public static <T> List<T> concat(List<T>... lists) {
    return Stream.of(lists).flatMap(List::stream).collect(Collectors.toList());
}
Daniel Hári
sumber
13

Anda dapat melakukan oneliner jika daftar target sudah ditentukan sebelumnya.

(newList = new ArrayList<String>(list1)).addAll(list2);
deterb
sumber
11

Di Java 8 (sebaliknya):

List<?> newList = 
Stream.of(list1, list2).flatMap(List::stream).collect(Collectors.toList());
Nitin Jain
sumber
Pendekatan ini sudah disarankan oleh jawaban ini: stackoverflow.com/a/37386846
Miles
9

solusi satu liner lainnya menggunakan Java8stream, karena flatMapsolusi sudah diposting, berikut adalah solusi tanpaflatMap

List<E> li = lol.stream().collect(ArrayList::new, List::addAll, List::addAll);

atau

List<E> ints = Stream.of(list1, list2).collect(ArrayList::new, List::addAll, List::addAll);

kode

    List<List<Integer>> lol = Arrays.asList(Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6));
    List<Integer> li = lol.stream().collect(ArrayList::new, List::addAll, List::addAll);
    System.out.println(lol);
    System.out.println(li);

keluaran

[[1, 2, 3], [4, 5, 6]]
[1, 2, 3, 4, 5, 6]
Saravana
sumber
1
Saya akan menambahkan bahwa solusi ini mungkin lebih berkinerja daripada yang menggunakan flatMap, karena daftar hanya diulang sekali ketika mereka dikumpulkan
Stefan Haberl
7

Yang paling cerdas menurut saya:

/**
 * @param smallLists
 * @return one big list containing all elements of the small ones, in the same order.
 */
public static <E> List<E> concatenate (final List<E> ... smallLists)
{
    final ArrayList<E> bigList = new ArrayList<E>();
    for (final List<E> list: smallLists)
    {
        bigList.addAll(list);
    }
    return bigList;
}
Olivier Faucheux
sumber
3
Jangan lupakan @SafeVarargs!
Radon Rosborough
6

Anda bisa melakukannya dengan impor statis dan kelas pembantu

nb generifikasi kelas ini mungkin dapat ditingkatkan

public class Lists {

   private Lists() { } // can't be instantiated

   public static List<T> join(List<T>... lists) {
      List<T> result = new ArrayList<T>();
      for(List<T> list : lists) {
         result.addAll(list);
      }
      return results;
   }

}

Maka Anda dapat melakukan hal-hal seperti

import static Lists.join;
List<T> result = join(list1, list2, list3, list4);
Dave Cheney
sumber
Bagaimana impor statis atau kelas pembantu relevan?
shmosel
6

Versi Java 8 dengan dukungan untuk bergabung dengan kunci objek:

public List<SomeClass> mergeLists(final List<SomeClass> left, final List<SomeClass> right, String primaryKey) {
    final Map<Object, SomeClass> mergedList = new LinkedHashMap<>();

    Stream.concat(left.stream(), right.stream())
        .map(someObject -> new Pair<Object, SomeClass>(someObject.getSomeKey(), someObject))
        .forEach(pair-> mergedList.put(pair.getKey(), pair.getValue()));

    return new ArrayList<>(mergedList.values());
}
cslysy
sumber
4
public static <T> List<T> merge(List<T>... args) {
    final List<T> result = new ArrayList<>();

    for (List<T> list : args) {
        result.addAll(list);
    }

    return result;
}
martyglaubitz
sumber
4

Gunakan kelas Helper.

Saya menyarankan:

public static <E> Collection<E> addAll(Collection<E> dest, Collection<? extends E>... src) {
    for(Collection<? extends E> c : src) {
        dest.addAll(c);
    }

    return dest;
}

public static void main(String[] args) {
    System.out.println(addAll(new ArrayList<Object>(), Arrays.asList(1,2,3), Arrays.asList("a", "b", "c")));

    // does not compile
    // System.out.println(addAll(new ArrayList<Integer>(), Arrays.asList(1,2,3), Arrays.asList("a", "b", "c")));

    System.out.println(addAll(new ArrayList<Integer>(), Arrays.asList(1,2,3), Arrays.asList(4, 5, 6)));
}
alex
sumber
3
public static <T> List<T> merge(@Nonnull final List<T>... list) {
    // calculate length first
    int mergedLength = 0;
    for (List<T> ts : list) {
      mergedLength += ts.size();
    }

    final List<T> mergedList = new ArrayList<>(mergedLength);

    for (List<T> ts : list) {
      mergedList.addAll(ts);
    }

    return mergedList;
  }
Langusten Gustel
sumber
2

Kita dapat bergabung dengan 2 daftar menggunakan java8 dengan 2 pendekatan.

    List<String> list1 = Arrays.asList("S", "T");
    List<String> list2 = Arrays.asList("U", "V");

1) Menggunakan concat:

    List<String> collect2 = Stream.concat(list1.stream(), list2.stream()).collect(toList());
    System.out.println("collect2 = " + collect2); // collect2 = [S, T, U, V]

2) Menggunakan flatMap:

    List<String> collect3 = Stream.of(list1, list2).flatMap(Collection::stream).collect(toList());
    System.out.println("collect3 = " + collect3); // collect3 = [S, T, U, V]
Himank Batra
sumber
1
Ketika menjawab pertanyaan berusia sebelas tahun dengan tiga puluh jawaban lain, pastikan untuk menunjukkan aspek baru dari pertanyaan yang dijawab oleh jawaban Anda, dan untuk mencatat apakah teknik-teknik ini akan berfungsi ketika pertanyaan itu diajukan, atau jika mereka bergantung pada fitur yang telah diperkenalkan selama bertahun-tahun.
Jason Aller
2

Hampir semua jawaban menyarankan untuk menggunakan ArrayList.

List<String> newList = new LinkedList<>(listOne);
newList.addAll(listTwo);

Lebih suka menggunakan LinkedList untuk operasi penambahan yang efisien.

ArrayList add adalah O (1) diamortisasi, tetapi O (n) terburuk karena array harus diubah ukurannya dan disalin. Sedangkan LinkedList add selalu konstan O (1).

info lebih lanjut https://stackoverflow.com/a/322742/311420

Raymond Chenon
sumber
0

Saya tidak mengklaim bahwa itu sederhana, tetapi Anda menyebutkan bonus untuk satu-liner ;-)

Collection mergedList = Collections.list(new sun.misc.CompoundEnumeration(new Enumeration[] {
    new Vector(list1).elements(),
    new Vector(list2).elements(),
    ...
}))
ddimitrov
sumber
mengapa seseorang tidak pernah menggunakannya?
David
5
@ David karena bertujuan untuk digunakan secara internal di JDK. Jika Anda menggunakannya dalam kode Anda, kode Anda kemungkinan besar tidak akan berjalan pada non-Sun (atau non-Oracle sekarang) JDK / JRE.
Adrian Shum
@AdrianShum Apakah ada JDK / JRE selain Oracle? Itu akan mengejutkan saya. Bahkan jika terbatas pada fungsi API yang paling umum, membangun kembali seluruh hal itu mungkin akan memakan waktu lama ...
Egor Hans
1
Ada cukup banyak JVM. Yang paling umum terlihat di dunia perusahaan adalah IBM yang, iirc, dibundel dengan websphere
Adrian Shum
0

Tidak jauh dari one-liner, tapi saya pikir ini yang paling sederhana:

List<String> newList = new ArrayList<String>(l1);
newList.addAll(l2);

for(String w:newList)
        System.out.printf("%s ", w);
nirmal
sumber
0

Berikut ini pendekatan menggunakan stream dan java 8 jika daftar Anda memiliki tipe yang berbeda dan Anda ingin menggabungkannya ke daftar tipe lain.

public static void main(String[] args) {
    List<String> list2 = new ArrayList<>();
    List<Pair<Integer, String>> list1 = new ArrayList<>();

    list2.add("asd");
    list2.add("asdaf");
    list1.add(new Pair<>(1, "werwe"));
    list1.add(new Pair<>(2, "tyutyu"));

    Stream stream = Stream.concat(list1.stream(), list2.stream());

    List<Pair<Integer, String>> res = (List<Pair<Integer, String>>) stream
            .map(item -> {
                if (item instanceof String) {
                    return new Pair<>(0, item);
                }
                else {
                    return new Pair<>(((Pair<Integer, String>)item).getKey(), ((Pair<Integer, String>)item).getValue());
                }
            })
            .collect(Collectors.toList());
}
Shinzou
sumber
0

Jika Anda ingin melakukan ini secara statis, Anda dapat mengikuti yang berikut.

Contoh-contoh menggunakan 2 EnumSets dalam urutan alami (== Enum-urutan) A, Bdan bergabung kemudian dalam ALLdaftar.

public static final EnumSet<MyType> CATEGORY_A = EnumSet.of(A_1, A_2);
public static final EnumSet<MyType> CATEGORY_B = EnumSet.of(B_1, B_2, B_3);

public static final List<MyType> ALL = 
              Collections.unmodifiableList(
                  new ArrayList<MyType>(CATEGORY_A.size() + CATEGORY_B.size())
                  {{
                      addAll(CATEGORY_A);
                      addAll(CATEGORY_B);
                  }}
              );
Jan Weitz
sumber
Ini akan membuat kelas anonim baru. Pendekatan tidak direkomendasikan!
kravemir
-3
import java.util.AbstractList;
import java.util.List;


/**
 * The {@code ConcatList} is a lightweight view of two {@code List}s.
 * <p>
 * This implementation is <em>not</em> thread-safe even though the underlying lists can be.
 * 
 * @param <E>
 *            the type of elements in this list
 */
public class ConcatList<E> extends AbstractList<E> {

    /** The first underlying list. */
    private final List<E> list1;
    /** The second underlying list. */
    private final List<E> list2;

    /**
     * Constructs a new {@code ConcatList} from the given two lists.
     * 
     * @param list1
     *            the first list
     * @param list2
     *            the second list
     */
    public ConcatList(final List<E> list1, final List<E> list2) {
        this.list1 = list1;
        this.list2 = list2;
    }

    @Override
    public E get(final int index) {
        return getList(index).get(getListIndex(index));
    }

    @Override
    public E set(final int index, final E element) {
        return getList(index).set(getListIndex(index), element);
    }

    @Override
    public void add(final int index, final E element) {
        getList(index).add(getListIndex(index), element);
    }

    @Override
    public E remove(final int index) {
        return getList(index).remove(getListIndex(index));
    }

    @Override
    public int size() {
        return list1.size() + list2.size();
    }

    @Override
    public boolean contains(final Object o) {
        return list1.contains(o) || list2.contains(o);
    }

    @Override
    public void clear() {
        list1.clear();
        list2.clear();
    }

    /**
     * Returns the index within the corresponding list related to the given index.
     * 
     * @param index
     *            the index in this list
     * 
     * @return the index of the underlying list
     */
    private int getListIndex(final int index) {
        final int size1 = list1.size();
        return index >= size1 ? index - size1 : index;
    }

    /**
     * Returns the list that corresponds to the given index.
     * 
     * @param index
     *            the index in this list
     * 
     * @return the underlying list that corresponds to that index
     */
    private List<E> getList(final int index) {
        return index >= list1.size() ? list2 : list1;
    }

}
benez
sumber