Saya sangat ingin menggunakan Map.computeIfAbsent tetapi sudah terlalu lama sejak lambdas di undergrad.
Hampir langsung dari dokumen: ini memberikan contoh cara lama untuk melakukan sesuatu:
Map<String, Boolean> whoLetDogsOut = new ConcurrentHashMap<>();
String key = "snoop";
if (whoLetDogsOut.get(key) == null) {
Boolean isLetOut = tryToLetOut(key);
if (isLetOut != null)
map.putIfAbsent(key, isLetOut);
}
Dan cara baru:
map.computeIfAbsent(key, k -> new Value(f(k)));
Tetapi dalam contoh mereka, saya pikir saya tidak cukup "mengerti". Bagaimana saya mengubah kode untuk menggunakan cara lambda baru untuk mengekspresikannya?
java
dictionary
lambda
java-8
Benjamin H.
sumber
sumber
Jawaban:
Misalkan Anda memiliki kode berikut:
Kemudian Anda akan melihat pesan
creating a value for "snoop"
tepat satu kali karena pada pemanggilan keduacomputeIfAbsent
sudah ada nilai untuk kunci itu. Dalamk
ekspresi lambdak -> f(k)
hanya placeolder (parameter) untuk kunci yang peta akan lolos ke lambda Anda untuk menghitung nilai. Jadi dalam contoh, kunci dilewatkan ke pemanggilan fungsi.Atau Anda dapat menulis:
whoLetDogsOut.computeIfAbsent("snoop", k -> k.isEmpty());
untuk mencapai hasil yang sama tanpa metode helper (tetapi Anda tidak akan melihat keluaran debugging saat itu). Dan bahkan lebih sederhana, karena ini adalah pendelegasian sederhana ke metode yang sudah ada, Anda dapat menulis:whoLetDogsOut.computeIfAbsent("snoop", String::isEmpty);
Delegasi ini tidak memerlukan parameter apa pun untuk ditulis.Untuk lebih mendekati contoh dalam pertanyaan Anda, Anda dapat menuliskannya sebagai
whoLetDogsOut.computeIfAbsent("snoop", key -> tryToLetOut(key));
(tidak masalah apakah Anda menamai parameterk
ataukey
). Atau menulis sebagaiwhoLetDogsOut.computeIfAbsent("snoop", MyClass::tryToLetOut);
jikatryToLetOut
adalahstatic
atauwhoLetDogsOut.computeIfAbsent("snoop", this::tryToLetOut);
jikatryToLetOut
merupakan metode contoh.sumber
Baru-baru ini saya juga bermain dengan metode ini. Saya menulis algoritma memoized untuk menghitung bilangan Fibonacci yang dapat berfungsi sebagai ilustrasi lain tentang cara menggunakan metode ini.
Kita bisa mulai dengan mendefinisikan peta dan memasukkan nilai-nilai di dalamnya untuk kasus dasar, yaitu,
fibonnaci(0)
danfibonacci(1)
:Dan untuk langkah induktif yang harus kita lakukan adalah mendefinisikan kembali fungsi Fibonacci kita sebagai berikut:
Seperti yang Anda lihat, metode ini
computeIfAbsent
akan menggunakan ekspresi lambda yang disediakan untuk menghitung angka Fibonacci saat angka tersebut tidak ada di peta. Ini menunjukkan peningkatan yang signifikan atas algoritme rekursif pohon tradisional.sumber
HashMap
internal rusak, seperti di bugs.openjdk.java.net/browse/JDK-8172951 dan akan gagalConcurrentModificationException
di Java 9 ( bugs.openjdk.java.net/browse/JDK-8071667 )Contoh lain. Saat membuat peta peta yang kompleks, metode computeIfAbsent () adalah pengganti metode get () peta. Melalui rangkaian panggilan computeIfAbsent () bersama-sama, container yang hilang dibuat secara on-the-fly oleh ekspresi lambda yang disediakan:
sumber
multi-peta
Ini sangat membantu jika Anda ingin membuat multimap tanpa menggunakan pustaka Google Guava untuk implementasinya
MultiMap
.Misalnya, Anda ingin menyimpan daftar siswa yang mendaftar untuk mata pelajaran tertentu.
Solusi normal untuk ini menggunakan perpustakaan JDK adalah:
Karena memiliki beberapa kode boilerplate, orang cenderung menggunakan Guava
Mutltimap
.Dengan menggunakan Map.computeIfAbsent, kita dapat menulis dalam satu baris Multimap tanpa jambu sebagai berikut.
Stuart Marks & Brian Goetz melakukan pembicaraan yang baik tentang ini https://www.youtube.com/watch?v=9uTVXxJjuco
sumber
studentListSubjectWise.stream().collect(Collectors.GroupingBy(subj::getSubjName, Collectors.toList());
Ini menghasilkan multi-map tipeMap<T,List<T>
di JDK hanya lebih singkat imho.