Hai habr!
Saya seorang Insinyur Perangkat Lunak di EPAM. Selama lebih dari 8 tahun saya telah bekerja dengan kode warisan yang ditulis di Jawa (mengantisipasi komentar, saya perhatikan bahwa pemahaman dan toleransi untuk warisan dimulai jauh sebelum EPAM, sebagai kesimpulan Anda akan menemukan jawabannya mengapa). Seringkali dalam pekerjaan saya menemukan kesalahan berulang yang sama. Ini mendorong saya untuk menulis catatan, dan saya ingin memulai dengan struktur data dan kelas pembantu
Koleksi dan
Array . Untuk beberapa alasan, beberapa pengembang mengabaikan penggunaannya, dan sia-sia
Pengembang Java sering harus berurusan dengan berbagai struktur data. Ini bisa berupa array, semua jenis koleksi atau implementasi
Peta . Tampaknya segala sesuatu dengan mereka jelas dan dapat dimengerti, tetapi ada beberapa hal kecil yang mudah tersandung.
Catatan ini mungkin berguna untuk pemula yang belum tahu nuansa ini, dan pengembang berpengalaman yang mungkin melupakan sebagian dari ini.
Foto oleh ammiel jr di UnsplashCAT
Saya ingin segera memesan bahwa materi ini relevan untuk Java 8. Jelas bahwa beberapa hal telah dilakukan dengan lebih baik di Java 9+, tetapi sebagian besar proyek besar paling sering menggunakan versi Java 8 (dan kadang-kadang Java 6).
Apa cara terbaik untuk mendapatkan koleksi berbasis array?
Saya sarankan mulai dengan pembentukan koleksi berdasarkan array.
Paling sering, metode ini terjadi:
Integer[] someArray = {9, 10, 11, 12}; List<Integer> list = Arrays.asList(someArray);
Ini memang berhasil, tetapi apakah semuanya baik-baik saja dengan itu? Dan adakah solusi alternatif?
Dua minus dari pendekatan ini muncul sekaligus:
- Pertama, metode Arrays.asList mengembalikan Daftar . Tetapi bagaimana jika kita membutuhkan implementasi Collection yang lain? Arrays.asList tidak akan mengizinkan ini, tetapi suatu alternatif akan dipertimbangkan sedikit lebih jauh.
- Kedua, Daftar diperoleh dengan memanggil Arrays.asList tidak mendukung pengubahan ukuran. Saya pikir banyak yang datang dengan pengecualian yang timbul dari bekerja dengan daftar seperti itu.
Di antarmuka
Koleksi , Anda dapat menemukan alternatif metode
Arrays.asList - metode
Collections.addAll . Berikut cara menggunakannya:
Atau sederhananya:
Collections.addAll(collection, 11, 12, 13, 14);
Metode
Collections.addAll menerima objek
Koleksi dan array di input. Alih-alih array, Anda juga bisa menentukan elemen yang dipisahkan oleh koma.
Apa manfaat dari
Collections.addAll over
Arrays.asList ?
- Untuk mulai dengan, ketika membuat koleksi berdasarkan array Collections.addAll , ia bekerja jauh lebih cepat daripada metode addAll koleksi dengan input dari Array.asList . Ini dapat ditemukan di JavaDoc dari metode ini:
Perilaku metode kenyamanan ini identik dengan perilaku c.addAll (Arrays.asList (elemen)), tetapi metode ini cenderung berjalan secara signifikan lebih cepat di sebagian besar
- Selain itu, Collections.addAll bekerja tidak hanya dengan Daftar , tetapi dengan koleksi lainnya.
- Dan saat menggunakan metode ini, tidak ada masalah mengubah ukuran.
Apa cara termudah untuk mencetak array, array multidimensi, atau koleksi?
Mari kita beralih ke masalah mendapatkan representasi cetak dari array dan koleksi.
Jika kita hanya membuat
System.out.println (someArray) , kita mendapatkan sesuatu seperti ini:
[Ljava.lang.Integer; @ 6d06d69c.Hasil serupa diharapkan ketika menggunakan metode
toString () pada array.
Untuk menampilkan array, metode
Arrays.toString (...) datang untuk
menyelamatkan .
Integer[] someArray = new Integer[]{1, 2, 3}; System.out.println(Arrays.toString(someArray));
Output untuk baris ini adalah:
[1, 2, 3]
Jika kita berbicara tentang array multidimensi, maka Anda dapat menggunakan metode:
Arrays.deeptoString .
int[][] a = { {1, 2, 3}, {4, 5, 6} }; System.out.println(Arrays.deepToString(a));
Output dari cuplikan ini adalah:
[[1, 2, 3], [4, 5, 6]]
Jadi, tidak perlu menyortir array melalui loop apa pun secara manual untuk menampilkan elemen-elemennya, cukup menggunakan metode ini.
Sedangkan untuk koleksi atau implementasi
Peta , tidak ada masalah. Semua struktur data kecuali array biasanya adalah output.
Misalkan ada contoh:
Collection<Integer> someCollection = new HashSet<>(); someCollection.add(1); someCollection.add(2); System.out.println(someCollection); Map<Integer, String> someMap = new HashMap<>(); someMap.put(1, "Some 1"); someMap.put(2, "Some 2"); System.out.println(someMap);
Perhatikan dalam output di bawah ini bahwa set dan
Peta ditampilkan dalam format yang mudah dibaca:
[1, 2]
{1 = Beberapa 1, 2 = Beberapa 2}
Seberapa mudah membandingkan array satu sama lain?
Ada beberapa situasi ketika Anda perlu membandingkan array. Ada metode di kelas
Array yang memungkinkan perbandingan seperti itu. Metode
Arrays.equals membandingkan jumlah elemen dan memeriksa kesetaraan elemen yang sesuai.
Katakanlah kita memiliki kelas
Elemen dengan satu bidang dan sederajat tertentu
private class Element { final String name; private Element(String name) { this.name = name; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Element element = (Element) o; return Objects.equals(name, element.name); } @Override public int hashCode() { return Objects.hash(name); } }
Tentukan tiga array:
Element[] firstElementArray = { new Element("a"), new Element("b"), new Element("c") }; Element[] secondElementArray = {new Element("c"), new Element("b"), new Element("a") }; Element[] thirdElementArray = { new Element("a"), new Element("b"), new Element("c") };
Perhatikan bahwa array pertama dan ketiga memiliki elemen dalam urutan yang sama.
Sekarang Anda dapat melakukan perbandingan menggunakan metode
Arrays.equals .
System.out.println("first equals to second? " + Arrays.equals(firstElementArray, secondElementArray)); System.out.println("second equals to third? " + Arrays.equals(secondElementArray, thirdElementArray)); System.out.println("first equals to third? " + Arrays.equals(firstElementArray, thirdElementArray));
Hasilnya adalah sebagai berikut:
pertama sama dengan kedua? salah
kedua sama dengan ketiga? salah
pertama sama dengan ketiga? benar
Bagaimana cara menyalin array secara efisien?
Seringkali Anda dapat melihat dalam kode menyalin array secara manual menggunakan loop. Namun, ada metode
System.arraycopy yang akan menyalin lebih cepat.
Saya sarankan lihat contoh sederhana seperti ini:
Element[] elements = { new Element("a"), new Element("b"), new Element("c") }; Element[] copyOfElements = new Element[elements.length]; System.arraycopy(elements, 0, copyOfElements, 0, elements.length); System.out.println(Arrays.toString(copyOfElements));
Kami memiliki berbagai elemen. Kami membuat array kosong dengan panjang yang sama dan menyalin semua elemen dari yang pertama ke yang kedua. Hasilnya, kami memperoleh kesimpulan berikut:
[Elemen {name = 'a'}, Elemen {name = 'b'}, Elemen {name = 'c'}]
Bagaimana cara mengurutkan array atau koleksi dengan cara yang berbeda?
Array dapat diurutkan menggunakan metode
Arrays.sort (someArray) . Jika Anda ingin mengurutkan array dalam urutan terbalik, Anda dapat meneruskan
Collections.reverseOrder () sebagai parameter kedua ke input ke metode ini.
Misalnya, ada array yang kami sortir langsung dan kemudian dalam urutan terbalik:
String[] someArray = new String[]{"b", "a", "c"}; Arrays.sort(someArray); System.out.println(Arrays.toString(someArray)); Arrays.sort(someArray, Collections.reverseOrder()); System.out.println(Arrays.toString(someArray));
Kesimpulannya adalah sebagai berikut:
[a, b, c]
[c, b, a]
Selain pengurutan langsung dan mundur, kadang-kadang terjadi bahwa Anda perlu mengurutkan array string terlepas dari kasus. Ini mudah dilakukan dengan meneruskan
String.CASE_INSENSITIVE_ORDER sebagai parameter kedua ke
Arrays.sort .
Sayangnya,
Collections.sort hanya memungkinkan implementasi
Daftar untuk diurutkan.
Algoritma apa yang memilah Java?
Hal terakhir yang disebutkan ketika berbicara tentang pengurutan di Jawa adalah bahwa di Jawa, "pengurutan sederhana" digunakan untuk jenis yang paling sederhana, dan "stabil gabungan" digunakan untuk objek. Jadi Anda tidak boleh menghabiskan sumber daya untuk mengembangkan implementasi Anda sendiri dari metode penyortiran sampai profiler menunjukkan bahwa itu perlu.
Bagaimana jika kita memiliki array dan metode menerima Iterable?
Saya mengusulkan sekarang untuk beralih ke pertanyaan seperti melewati array ke metode yang membutuhkan
Iterable . Biarkan saya mengingatkan Anda bahwa
Iterable adalah antarmuka yang berisi metode
iterator () , yang harus dikembalikan oleh Iterator.
Jika ada metode yang menerima Iterable di input, maka array tidak dapat ditransfer begitu saja. Meskipun Anda bisa mengulangi lebih dari satu array dalam
for for loop, itu bukan
Iterable .
String[] someArray = new String[]{"a", "b", "c"}; for (String currentString : someArray) { ... }
Dalam contoh ini, semuanya baik-baik saja. Tetapi jika ada metode:
private static void someIteration(Iterable<String> iterable) { ... }
Baris itu tidak akan dikompilasi:
someIteration(someArray);
Satu-satunya jalan keluar dalam situasi ini adalah dengan mengubah array ke koleksi dan sudah mengumpankannya ke metode seperti itu.
Secara singkat tentang beberapa metode Koleksi yang berguna
Apa yang layak dibaca?
Ini hanya sebagian kecil dari alat yang dapat membuat hidup lebih mudah bagi pengembang ketika bekerja dengan struktur data. Banyak poin menarik dalam karya koleksi itu sendiri dan alat yang mudah untuk bekerja dengannya dapat ditemukan dalam buku Bruce Eckel “Java Philosophy” (edisi penuh ke-4). Namun, Anda harus berhati-hati, karena menghadapi situasi yang tidak lagi dapat dimainkan di Java 7, Java 8 dan lebih tinggi. Meskipun Java 6 dijelaskan dalam buku ini, materinya tetap relevan hingga saat ini.
Tentu saja, “Filosofi Jawa” tidak boleh dibatasi. Membaca salah satu buku ini tidak akan merugikan pengembang Java mana pun:
- "Jawa. Pemrograman yang Efektif, ”Joshua Bloch.
- “Refactoring. Meningkatkan Desain Kode yang Ada, ”Martin Fowler.
- “Kode bersih. Penciptaan, analisis, dan refactoring ”, Robert Martin.
- Spring 5 untuk Profesional, Julian Kozmin dan lainnya.
- “Pengembangan Java Berbasis Tes”, Viktor Farcic, Alex Garcia (belum dirilis dalam bahasa Rusia).
Apa hasilnya?
Jika Anda menemukan ide-ide menarik yang dapat melengkapi apa yang ditulis dalam artikel ini, bagikan dalam komentar.
Saya juga ingin mengucapkan semoga sukses dan kesabaran kepada mereka yang bekerja dengan kode lama yang lama. Sebagian besar proyek besar adalah warisan. Dan signifikansi mereka bagi pelanggan sulit ditaksir terlalu tinggi. Dan perasaan kemenangan dari menghilangkan bug, yang membutuhkan waktu lebih dari seminggu untuk menemukan alasannya, tidak kalah dengan perasaan pada akhir penerapan fitur baru.
Terima kasih atas perhatian anda Saya akan senang jika ada yang disajikan akan bermanfaat.
Semua sukses!