
في الفترة من 28 إلى 29 أكتوبر ، عُقد
Joker 2019 في سان بطرسبرغ - وهو المؤتمر الأكبر والأكثر المتشددين في اتساع روسيا المخصصة لتطوير جافا. أقيم الحدث للمرة السابعة ، وكما هو الحال دائمًا ، حطم الرقم القياسي للحضور ، استقطب هذا الحدث أكثر من 2000 متخصص.
يشارك زملاء الدراسة تقليديا في جوكر كشركاء في الحدث. هذا العام ، في جناحنا ، يمكن للمرء أن يحاول التعامل مع المهام "غير القابلة للحل" الشهيرة من كبار مهندسي OK.RU. حصل المشاركون في المؤتمر الذين أجابوا على الأسئلة بشكل صحيح على جوائز.
في الإنصاف ، يجب أن أقول أنه من بين 1000 منشور مع المهام التي قمنا بتسليمها ، تم إرجاع أقل من 100 منشور ، وكان الأفضل هو الحل الذي سجل 4.5 نقطة من أصل 5.
ننشر المهام وحلولها حتى تتمكن من اختبار قوتك.
1. التعداد البطولية
كود المصدر للعبة غير معروفة كشفت هذه الشفرة. ما هو التنفيذ السيئ لـ
Group.of
، وكيفية إصلاحه؟
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(); } }
قرارإذا كنت لا تتحدث عن أنماط الترميز ، فإن هذه الشريحة لها عيب موضوعي - مشكلة محتملة في الأداء. على الرغم من أن البحث الخطي غالبًا ما يكون عنق الزجاجة ، إلا أن الأمر ليس كذلك في هذه الحالة ، لأن هذا التعداد يحتوي على خمسة عناصر فقط. وما يمكن أن يؤثر سلبًا على الأداء هو التخصيص المفرط للذاكرة عند استدعاء
Group.values()
. المشكلة هي أن طريقة
values()
التعداد في كل مرة تقوم بإرجاع نسخة جديدة من المصفوفة ، وأن HotSpot غير قادر حتى الآن على تحسينه. أحد الحلول البسيطة هو إنشاء نسختك الخاصة من مجموعة
values()
وتكرارها:
private static final Group[] ALL_GROUPS = Group.values(); public static Group of(int count) { for (Group group : ALL_GROUPS) { .... }
2. الأحلام
تم إصدار Java 13 بالفعل ، ولا يزال Nikolai يفهم التدفقات فقط. حدد الأخطاء في الطريقة التي تحسب الفرق بين الحد الأقصى والحد الأدنى لعناصر الدفق.
int getDiameter(Stream<Integer> stream) { int min = stream.min(Integer::compare).get(); int max = stream.max(Integer::compare).get(); return max - min; }
قرارتكون التدفقات في Java عادةً لمرة واحدة: سيفشل استدعاء العملية الطرفية الثانية (في هذه الحالة ،
max
):
java.lang.IllegalStateException: stream has already been operated upon or closed
بالإضافة إلى ذلك ،
min
و
max
return
Optional
، فإن عملية
get()
التي ستلقي عليها
NoSuchElementException
لدفق فارغ. لذلك ، من الأصح التحقق من
isPresent()
قبل استدعاء
get()
أو استخدام طرق
Optional
أخرى:
orElse ،
orElseThrow ، إلخ.
أخيرًا ، لن يفلت الفرق بين
int
من
int
ولن يفلت من المطور الدقيق ، ومن المفيد تغيير نوع القيمة المرجعة إلى القيمة
long
.
3. عازلة آمنة
ByteBuffer
مزامنة جافا البدائية التي يمكن أن تجعل
put
get
عمليات موضوع آمن على
ByteBuffer
عام؟
final ByteBuffer buf = ByteBuffer.allocate(SIZE); int get(int offset) { return buf.get(offset); } void put(int offset, int value) { buf.putInt(offset, value); }
اختر الخيار الأكثر فاعلية إذا كنت تعلم أن هناك العديد من مؤشرات الترابط ، ثم يتم تشغيلها كثيرًا أكثر من وضع.
- تزامن
- ReentrantLock
- ReentrantReadWriteLock
- StampedLock
- الملوحة جهاز
- القراءة والكتابة int في جاوة دائماً الذرية
قراريطالب
ReentrantReadWriteLock
القارئ والكاتب ، وغالبًا ما يكون هذا حلاً فعالًا. لكن لاحظ أنه في هذه الحالة ، تكون عمليات get and put بسيطة للغاية - إن احتمال أن يتعارض مع وضع منافس مع أمر صغير ، علاوة على ذلك ، من غير المرجح أن تحدث شروط وضع مع عمليات put. لذلك ، يمكنك تطبيق آلية
القفل المتفائلة التي
توفرها StampedLock .
سيكون
StampedLock
أكثر كفاءة من
ReentrantReadWriteLock
نظرًا لحقيقة أنه في حالة نجاح المسار السريع المتفائل ، لا يتم تحديث المتغيرات المشتركة على الإطلاق ، في حين تنفذ
ReentrantReadWriteLock
CAS واحدة على الأقل في أفضل الأحوال.
4. الهدايا
تقوم ايليا بتطوير عرض للهدايا على شبكة اجتماعية. ساعده في كتابة طريقة
add
للهيكل الذي لا يحمل أكثر من N من أحدث الهدايا. لا يجب إضافة هدية إذا كانت موجودة بالفعل ، أو إذا كانت أقدم من بقية المنطقة الشمالية.
interface Present { long getId(); Date getCreated(); } void add(Present p) {
قرارTreeSet
أو
PriorityQueue
مناسبًا بشكل طبيعي كهيكل بيانات من أجل إضافة الهدايا بشكل فعال وحذف الأقدم وليس أسوأ من O (سجل N). كل الحيلة موجودة فقط في المقارنة: لا يكفي مقارنة الهدايا فقط مع
getCreated()
، لأن تاريخ الإنشاء لا يجب أن يكون فريدًا. لذلك ، تحتاج إلى مقارنة أولاً بواسطة
getCreated()
، ثم عن طريق
getId()
. سيضمن هذا المقارنة كلاً من تفرد العناصر والطلب حسب التاريخ.
TreeSet<Present> tree = new TreeSet<>( Comparator.comparing(Present::getCreated) .thenComparing(Present::getId));
تظل مسألة صغيرة: عند إضافة هدية ، تحقق من أن الحجم لا يتجاوز N ، وإذا لزم الأمر ، احذف العنصر الأول والأقدم من المجموعة.
void add(Present p) { if (tree.add(p) && tree.size() > N) { tree.pollFirst(); } }
5. لن تنتظر
لماذا جوليا لن تنتظر نهاية هذا البرنامج؟
var executor = Executors.newFixedThreadPool(4); for (File f : File.listRoots()) { executor.submit(() -> f.delete()); } executor.awaitTermination(2, TimeUnit.HOURS);