
Dari tanggal 28 hingga 29 Oktober, 
Joker 2019 diadakan di St. Petersburg - konferensi terbesar dan paling keras di luasnya Rusia yang didedikasikan untuk pembangunan Jawa. Acara ini diadakan untuk ketujuh kalinya dan, seperti biasa, memecahkan rekor kehadiran, kali ini acara tersebut menarik lebih dari 2.000 spesialis.
Teman sekelas secara tradisional mengambil bagian dalam Joker sebagai mitra acara. Tahun ini, di stan kami, seseorang dapat mencoba untuk mengatasi tugas-tugas "tidak terpecahkan" yang terkenal dari para insinyur OK.RU terkemuka. Peserta konferensi yang menjawab pertanyaan dengan benar menerima hadiah.
Dalam keadilan, saya harus mengatakan bahwa dari 1.000 selebaran dengan tugas yang kami bagikan, kurang dari 100 dikembalikan. Yang terbaik adalah solusi, yang mencetak 4,5 poin dari 5.
Kami menerbitkan tugas dan solusinya sehingga Anda dapat menguji kekuatan Anda.
1. Enum yang heroik
Kode sumber untuk gim yang kurang dikenal mengungkapkan kode tersebut. Apa implementasi 
Group.of buruk, dan bagaimana cara memperbaikinya?
 enum Group { Few(1, 4), Several(5, 9), Pack(10, 19), Lots(20, 49), Swarm(50, Integer.MAX_VALUE); Group(int min, int max) { ... } public static Group of(int count) { for (Group group : Group.values()) { if (count >= group.min && count <= group.max) { return group; } } throw new IllegalArgumentException(); } } 
SolusiJika Anda tidak berbicara tentang gaya pengkodean, fragmen ini memiliki kelemahan objektif - masalah kinerja potensial. Meskipun pencarian linear sering ternyata menjadi hambatan, dalam hal ini bukan itu masalahnya, karena enum ini hanya memiliki lima elemen. Dan yang benar-benar dapat memengaruhi kinerja secara negatif adalah alokasi memori yang berlebihan saat memanggil 
Group.values() . Masalahnya adalah bahwa 
values() metode enum setiap kali mengembalikan salinan baru array, dan HotSpot belum dapat mengoptimalkannya. Solusi sederhana adalah membuat salinan array 
values() Anda sendiri dan mengulanginya:
 private static final Group[] ALL_GROUPS = Group.values(); public static Group of(int count) { for (Group group : ALL_GROUPS) { .... } 
 2. Mimpi
Java 13 telah dirilis, dan Nikolai masih hanya memahami stream. Tunjukkan kesalahan dalam metode yang menghitung perbedaan antara elemen aliran maksimum dan minimum.
 int getDiameter(Stream<Integer> stream) { int min = stream.min(Integer::compare).get(); int max = stream.max(Integer::compare).get(); return max - min; } 
SolusiStreaming di Jawa biasanya satu kali: memanggil operasi terminal kedua (dalam hal ini, 
max ) akan gagal:
 java.lang.IllegalStateException: stream has already been operated upon or closed 
Selain itu, 
min dan 
max mengembalikan 
Optional , operasi 
get() yang akan melempar 
NoSuchElementException untuk aliran kosong. Oleh karena itu, lebih tepat untuk memeriksa 
isPresent() sebelum memanggil 
get() atau menggunakan metode 
Optional lainnya: 
orElse , 
atauElseThrow , dll.
Akhirnya, fakta bahwa perbedaan antara kedua 
int tidak dapat lagi masuk ke 
int tidak akan lepas dari pengembang yang cermat, dan akan sangat berguna untuk mengubah jenis nilai pengembalian menjadi 
long .
 3. Buffer aman
ByteBuffer primitif sinkronisasi Java yang dapat membuat 
put dan 
get operasi thread aman pada 
ByteBuffer generik?
 final ByteBuffer buf = ByteBuffer.allocate(SIZE); int get(int offset) { return buf.get(offset); } void put(int offset, int value) { buf.putInt(offset, value); } 
Pilih opsi yang paling efisien jika Anda tahu bahwa ada banyak utas, dan jalankan lebih sering daripada put.
- disinkronkan
- Reentrantlock
- ReentrantReadWriteLock
- Stampedlock
- Semaphore
- Membaca dan menulis di Jawa selalu bersifat atom
SolusiReentrantReadWriteLock memohon untuk 
ReentrantReadWriteLock pembaca dan penulis, dan seringkali ini akan menjadi solusi yang efektif. Tetapi perhatikan bahwa dalam kasus ini, operasi get and put sangat sederhana - probabilitas bahwa put kompetitif dapat mengganggu get adalah kecil, apalagi, kondisi put lebih kecil kemungkinannya terjadi dengan operasi put. Jadi, Anda dapat menerapkan mekanisme 
penguncian optimis yang diberikan 
StampedLock .
StampedLock akan lebih efisien daripada 
ReentrantReadWriteLock karena fakta bahwa dalam kasus keberhasilan jalur cepat yang optimis, variabel bersama tidak diperbarui sama sekali, sementara 
ReentrantReadWriteLock melakukan setidaknya satu 
CAS terbaik.
 4. Hadiah
Ilya sedang mengembangkan showcase hadiah di jejaring sosial. Bantu dia menulis metode 
add untuk struktur yang tidak lebih dari N dari hadiah terbaru. Hadiah tidak boleh ditambahkan jika sudah ada, atau jika itu lebih tua dari sisa N.
 interface Present { long getId(); Date getCreated(); } void add(Present p) {  
SolusiTreeSet atau 
PriorityQueue secara alami cocok sebagai struktur data untuk secara efektif menambahkan hadiah dan menghapus yang terlama tidak lebih buruk daripada untuk O (log N). Semua trik hanya ada di pembanding: tidak cukup membandingkan hadiah hanya dengan 
getCreated() , karena tanggal pembuatan tidak harus unik. Oleh karena itu, Anda perlu membandingkan dulu dengan 
getCreated() , lalu dengan 
getId() . Komparator seperti itu akan memastikan keunikan elemen dan pemesanan berdasarkan tanggal.
 TreeSet<Present> tree = new TreeSet<>( Comparator.comparing(Present::getCreated) .thenComparing(Present::getId)); 
Tetap menjadi masalah kecil: saat menambahkan hadiah, pastikan ukurannya tidak melebihi N, dan jika perlu, hapus elemen koleksi yang pertama, terlama.
 void add(Present p) { if (tree.add(p) && tree.size() > N) { tree.pollFirst(); } } 
 5. Anda tidak akan menunggu
Mengapa Julia tidak akan pernah menunggu akhir dari program ini?
 var executor = Executors.newFixedThreadPool(4); for (File f : File.listRoots()) { executor.submit(() -> f.delete()); } executor.awaitTermination(2, TimeUnit.HOURS);