
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);