Java 14: تسجيل ، ومثال أكثر إيجازاً ، ومغلف العبوة ، والتبديل لامداس وكتل النص

UPD. اليوم سيكون الإصدار الذي طال انتظاره من Java 14 - وحتى إذا لم يكن LTS - هناك ميزات جديدة كافية فيه. ستكون Java 14 متاحة في غضون بضع ساعات - ولكن يمكنك التعرف عليها الآن.



في Java 14 ، هناك تغييرات كافية ، سواء على مستوى كتابة التعليمات البرمجية أو على مستوى API و GC والعديد من أغطية المحرك الأخرى. يمكننا أن نقول ببعض اليقين أنه إذا كنت تعرف بعض رقائق Kotlin أو Python الفائقة - فلا تقلق ، مع وجود درجة عالية من الاحتمالية ستظهر قريبًا في Java. على أي حال ، يحتوي إصدار اليوم على بعض منها. لكن أول الأشياء أولاً.

في Java 14 ، تنتظرنا الابتكارات التالية:

  • JEP 305. تعيين مرجع لكائن يتم فحصه من خلال سبيل المثال.
  • JEP 343. عبوة تعبئة (حاضنة).
  • JEP 345. تخصيص الذاكرة المستندة إلى NUMA لـ G1.
  • JEP 349. تدفق الأحداث من خلال JFR.
  • JEP 352. مخازن بايت بايت غير قابلة للتغيير.
  • JEP 358. نصائح حول NullPointerException.
  • 359 جيب.
  • JEP 361. تبديل لامداس.
  • JEP 362. يتم الآن إيقاف العمل بمنافذ Solaris و SPARC.
  • JEP 363. إزالة جامع القمامة Concurent Mark Sweep الذي تم وضع علامة عليه مسبقًا على أنه موقوف.
  • JEP 364. Porting ZGC على نظام macOS.
  • JEP 365. نقل ZGC إلى Windows.
  • JEP 366. الآن تم إيقاف تركيبة ParallelScavenge + SerialOld GC.
  • JEP 367. إزالة الأدوات وواجهات برمجة التطبيقات من Pack200 (التي تم تمييزها على أنها موقوفة في Java 11).
  • JEP 368. كتل نصية.
  • JEP 370. واجهة برمجة تطبيقات الوصول إلى الذاكرة الخارجية (الحاضنة).

دعنا نتحدث عن كل تحسن ، سيتم مناقشة بعضها بمزيد من التفصيل.

JEP 305. تعيين مرجع لكائن محدد من خلال المثيل




النظر في حالة التحقق من نوع كائن من خلال المثيل. إذا أردنا تخصيص كائن بشكل صريح للنوع المطلوب دون المخاطرة بـ ClassCastException ، نحتاج أولاً إلى التأكد من أن الكائن هو النوع الذي نحتاجه.

    private static void showNameIfToy(Object o) {
        if (o instanceof Toy) {  //,    -  Toy
            Toy t = (Toy) o;  //  
            System.out.println("Toy's name: " + t.getName());  //-   
        }
    }

في هذا المثال ، الذي يحدث ، بالمناسبة ، طوال الوقت ، نحن أ) نتأكد من أن لدينا كائنًا من النوع المطلوب ، ب) نعين رابطًا إليه ، ج) نفعل شيئًا معه ، بناءً على منطقنا. في Oracle ، على ما يبدو ، رأوا روعة معينة من التعليمات البرمجية في هذا البناء بالذات ، وقرروا تقليله بخطوة واحدة بالضبط. الآن يمكنك الكتابة هكذا:

    private static void showNameIfToy(Object o) {
        if (o instanceof Toy t) {  //      
            System.out.println("Toy's name: " + t.getName());  //     
        }
    }

كيف كل هذا مريح ومفيد حقا ، أترك للحكم عليك ، القارئ. نعم ، في الواقع ، يحدث هذا البناء في هذا الشكل ، على الأرجح ، في 99 ٪ من الحالات المرتبطة بمثيل ، وربما ، سوف يتجذر التبسيط (أو ربما لا). سيخبرنا الوقت.

JEP 343. الحزم (الحاضنة)




نحن ، المطورين ، رجال تم إطلاق النار عليهم ، لن تخيفنا من تثبيت dzharnik ، ولكن ماذا عن مستخدم بسيط لا يريد أن يعرف عند تثبيت JVM أنه مثبت على 3 مليار جهاز آخر ، لا يريد أن يعرف عن Java عبر النظام الأساسي ، ولكن فقط يريد أن يكرز 2 مرات ملف exe. إذا كان به Windows ، أو فقط اسحب تطبيق app. إلى مجلد التطبيقات ، إذا كان يحتوي على خشخاش ، ولا تبخره؟ كيفية تهيئة جميع الشروط للمبرمجين بحيث يحزمون تطبيقاتهم في "ملفات تنفيذية" مألوفة للمستخدم النهائي؟

يبدو أن أوراكل أدركت المشكلة وقررت كتابة باكر يقوم على الفور بتعبئة التطبيقات بتنسيق مناسب للمنصة:

  • نظام التشغيل Linux: deb و rpm
  • macOS: pkg و dmg
  • Windows: msi و exe

يبدو شيء من هذا القبيل:

$ jpackage --name myapp --input lib --main-jar main.jar --type exe

- اسم myapp - الاسم المستقبلي للتطبيق
- lib الإدخال - مصدر أرشيف الجرة
- main-jar main.jar - اسم الأرشيف الذي يحتوي على الفئة الرئيسية
- نوع exe - النوع الذي سيتم حزم التطبيق فيه.

بعد الحزم ، يمكنك النقر نقرًا مزدوجًا فوق myapp.exe (إذا كان لديك Windows) وتثبيته كتطبيق عادي للنوافذ. يتم توفير الواجهة الرسومية بواسطة JavaFX.

دعونا نحاول إنشاء مثل هذا التطبيق باستخدام نظام Windows الأساسي.

لذلك ، لنأخذ المشروع من هنا:
https://github.com/promoscow/bouncer
عند إرسال طلب GET ، نحصل على الرسالة: "Bounce Successfull" والطابع الزمني.

وضع dzharnik. نظرًا لأن لدينا gradle ، فإنه موجود في المجلد build / libs.



انتقل إلى مجلد البناء ، وأدخل الحد الأدنى المطلوب من الأوامر:

jpackage --name bouncer --input libs --main-jar bouncer.jar --type exe

نحصل حقا على exe-shnik.



نضغط مرتين في الملف التنفيذي ، يحدث التثبيت المعتاد للتطبيق.
رائع!



تم تثبيت التطبيق وينتظر في الأجنحة.
في ملفات البرنامج ، في مجلد الحارس ، يمكنك تشغيل bouncer.exe.



JEP 345. تخصيص ذاكرة NUMA المخصصة لـ G1


هناك مثل هذه المشكلة - NUMA ، والوصول إلى ذاكرة غير موحدة ، والوصول إلى ذاكرة غير متكافئة. بمعنى آخر ، يمكن أن يستغرق الوصول إلى المقابس البعيدة في الأجهزة متعددة الأقسام وقتًا طويلاً ، خاصة بالنسبة لمجمع القمامة G1. في Java 14 ، حاولوا حل هذه المشكلة على النحو التالي:

تم تنظيم كومة G1 كمجموعة من المساحات ذات الحجم الثابت. عادة ما تكون المنطقة عبارة عن مجموعة من الصفحات المادية ، على الرغم من أنه عند استخدام صفحات كبيرة (عبر -XX: + UseLargePages) ، يمكن أن تشكل عدة مناطق صفحة فعلية واحدة.

إذا قمت بإضافة المعلمة + XX: + UseNUMA أثناء تهيئة JVM ، فسيتم توزيع المناطق بالتساوي على إجمالي عدد العقد المتوفرة.

تعد أوراكل بأنه على الرغم من أن هذا النهج ليس مرنًا بالكامل ، إلا أنه سيحسنه في المستقبل.

JEP 349. تدفق الأحداث من خلال JFR


هناك شيء من هذا القبيل في Java مثل JFR - Java Flight Recording - تسجيل الأحداث بسرعة ، مما يسمح لك بمراقبة حوالي 500 نوع من الأحداث أثناء تشغيل التطبيق. المشكلة هي أنه لا يمكن عرض معظمها إلا في السجلات. التحسين الذي تقدمه أوراكل هو تنفيذ معالج ، على سبيل المثال ، وظيفة لامدا التي سيتم استدعاؤها استجابة لحدث.

إليك ما يبدو عليه:

try (var rs = new RecordingStream()) {
  rs.enable("jdk.CPULoad").withPeriod(Duration.ofSeconds(1));
  rs.onEvent("jdk.CPULoad", event -> System.out.println(event.getFloat("machineTotal")));
  rs.start();
}

يعرض هذا الحدث كل ثانية حمل المعالج على وحدة التحكم.



JEP 358. نصائح حول NullPointerException


راحة أخرى واضحة ، مصممة لتبسيط البحث عن الأخطاء في التعليمات البرمجية. تخيل بناء - كوكب ، هناك العديد من البلدان على كوكب الأرض ، في كل بلد هناك العديد من المدن.

public class Planet {

    private List<Country> countries;
    //...
}

public class Country {

    private List<City> cities;
    //...
}

public class City {

    private String name;
    //...
}

قررنا عرض رموز التجزئة لجميع مدن العالم:

planet.getCountries().forEach(c -> c.getCities().forEach(city -> city.hashCode()));

لكنهم لم يفكروا في التهيئة الإلزامية للحقول. وعند نقطة ما حصلوا على استثناء NullPointerException:

Exception in thread "main" java.lang.NullPointerException
	at ru.xpendence.jep_358_nullpointerexception.Main.main(Main.java:19)

أي مجال لدينا فارغة؟ كوكب؟ بلد؟ المدينة ؟؟؟ نحن لا نعلم. نضع نقطة التوقف على الخط الصحيح ، مع التنهد ، ننطلق.

في Java 14 ، يعد NullPointerException أكثر إفادة:

Exception in thread "main" java.lang.NullPointerException: Cannot assign field "cities" because "countries" is null
     at Main.main(Main.java:21)
     ...

وعلى الفور كل شيء واضح. البلدان لاغية.

JEP 359. سجل




لا عجب في أن أوراكل غيرت دورة الإصدار إلى ستة أشهر. التحولات التكتونية في صناعة تكنولوجيا المعلومات تجعل حتى هؤلاء القادة يتحركون بشكل أسرع. وإذا ، على سبيل المثال ، تأثر Kotlin و Python في وقت ظهورهما بـ Java (هذا ما تقوله ويكيبيديا عن Python ، على أي حال) ، فإن Java تنظر الآن إلى متابعيها ، إذا جاز التعبير. حول Python ، سيكون أقل ، ولكن تم فحص الميزة التالية لـ Oracle بدقة في Kotlin. يتعلق الأمر بفئات البيانات ، والتي تسمى الآن Java.

ما هي فئة البيانات؟ لنكتب POJO عادية:

public class Station {

    private String name;
    private Coordinates coordinates;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Coordinates getCoordinates() {
        return coordinates;
    }

    public void setCoordinates(Coordinates coordinates) {
        this.coordinates = coordinates;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        PlainStation that = (PlainStation) o;
        return Objects.equals(name, that.name) &&
                Objects.equals(coordinates, that.coordinates);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, coordinates);
    }

    @Override
    public String toString() {
        return "PlainStation{" +
                "name='" + name + '\'' +
                ", coordinates=" + coordinates +
                '}';
    }
}

هنا لدينا كل شيء في صف واحد - المتسللون ، المستوطنون ، المتساويون ، رمز التجزئة ، toString ... من أجل التخلص بطريقة ما من هذا الخزي ، أتى الناس الطيبون مع لومبوك.

في Jetbrains ، تم حل المشكلة في وقت واحد بطريقة أكثر جذرية - من خلال اختراع فئات البيانات لكوتلن. تبدو مثل هذه الفئة بجميع الطرق القياسية كما يلي:

data class Station(val name: String, val coordinates: Coordinates)

وهذا كل شيء. في أوراكل ، على ما يبدو ، نظرت إلى هذا التصميم وفعلت الشيء نفسه تمامًا ، وسجل فقط:

public record RecordStation(String name, List<Coordinates> coordinates) {}

يحتوي على أحرف قياسية ، واعدادات ، يساوي ، رمز التجزئة و toString.
يمكن بالفعل إنشاء فئة من هذا النوع في IDEA 2020.1.

ما هي الاختلافات عن POJO؟


  • لا يمكن توريث السجل من أي فئة.
  • لا يمكن أن يحتوي السجل على أي حقول أخرى للكائن ، باستثناء تلك المعلنة في المُنشئ عند وصف الفئة (نعم ، هذا هو المُنشئ الافتراضي ، بالمناسبة). ثابت - يمكنك.
  • الحقول نهائية بشكل ضمني. الكائنات نهائية بشكل ضمني. مع كل العواقب ، مثل استحالة كونها مجردة.

اتضح أن هذا هو فئة بيانات غير قابلة للتغيير ، غير مخصصة لبعض الإجراءات المنطقية المعقدة معها ، ولكنها مخصصة لنقل البيانات ، وهذا كل شيء.

JEP 361. سويتش لامداس




يبدو أن أوراكل قد تناولت التبديل بإحكام. قبل الإصدار الحالي ، كان تصميمًا ضخمًا إلى حد ما ، وبدا كما يلي:

    public static void translateDayOfWeekOld(String dayOfWeek) {
        switch (dayOfWeek) {
            case "MONDAY":
                System.out.println("");
                break;
            case "TUESDAY":
                System.out.println("");
                break;
            case "WEDNESDAY":
                System.out.println("");
                break;
            case "THURSDAY":
                System.out.println("");
                break;
            case "FRIDAY":
                System.out.println("");
                break;
            case "SATURDAY":
                System.out.println("");
                break;
            case "SUNDAY":
                System.out.println("");
                break;
            default:
                System.out.println("Day of week not found, try again with today day of week");
                String displayName = LocalDate.now().getDayOfWeek().name();
                translateDayOfWeek(displayName);
        }
    }

تستغرق معالجة شرط واحد على الأقل ثلاثة أسطر - الحالة ، الإجراء ، الانقطاع. الآن ، مع الوظيفة المحسنة للمفتاح ، يمكننا تقصير البناء أعلاه إلى هذا:

    public static void translateDayOfWeek(String dayOfWeek) {
        switch (dayOfWeek) {
            case "MONDAY" -> System.out.println("");
            case "TUESDAY" -> System.out.println("");
            case "WEDNESDAY" -> System.out.println("");
            case "THURSDAY" -> System.out.println("");
            case "FRIDAY" -> System.out.println("");
            case "SATURDAY" -> System.out.println("");
            case "SUNDAY" -> System.out.println("");
            default -> {
                System.out.println("Day of week not found, try again with today day of week");
                String displayName = LocalDate.now().getDayOfWeek().name();
                translateDayOfWeek(displayName);
            }
        }
    }

موافق ، مضغوط للغاية وعصري ومع lambdas. هل يستحق ذلك ، تقرر.

بالمناسبة ، يقترح تبديل IDEA 2020.1 ، المكتوب وفقًا للقواعد القديمة ، إعادة الكتابة بطريقة جديدة.



JEP 362. موانئ سولاريس وسبارك متوقفة الآن


كل شيء بسيط هنا. قررت أوراكل أنه لا يستحق إنفاق الموارد على دعم منافذ Solaris و SPARC ، ويجب على الموظفين المفرج عنهم التحول إلى تطوير ميزات جديدة.

JEP 363. إزالة جامع القمامة Concurent Mark Sweep الذي تم وضع علامة عليه مسبقًا على أنه موقوف


تمت مناقشة إزالة جامع القمامة CMS قبل عامين ، في الإصدار التاسع. خلال هذا الوقت ، خرج اثنان من جامعي القمامة - ZGC و Shenandoah. في الوقت نفسه ، لم يبد أحد المساهمين الموثوقين في Oracle اهتمامًا بدعم CMS.

بشكل عام ، قال الطبيب للمشرحة - ثم للمشرحة.

JEP 364 ، 365. Porting ZGC على نظامي macOS و Windows


ننشر عادةً التطبيقات على أنظمة Linux الأساسية ، ولكن بالنسبة للتطوير المحلي ، غالبًا ما نستخدم Windows و Mac. لهذه الاحتياجات ، قامت Java 14 بنقل جامع القمامة ZGC إلى هاتين المنصتين.

JEP 366. ParallelScavenge + SerialOld GC تركيبة موقوفة الآن


هناك تكوين جامع للقمامة نادرًا ما يستخدم - عندما يتم دمج ParallelScavenge الصغير مع SerialOld. سبب ذلك غير واضح ، لأن ParallelScavenge متوازي ، و SerialOld ، على العكس من ذلك ، ليس كذلك. يتطلب تضمين هذا المزيج رقصات خاصة مع الدف ويتطلب الكثير من مطوري الدم. "تهتم أوراكل بك" ، لذا فهي تميز هذا التكوين على أنه قديم ، ويأمل في إرساله قريبًا إلى جامع القمامة CMS.

دعونا نفرح أيها الإخوة.

JEP 367. إزالة أدوات Pack200 وواجهات برمجة التطبيقات (التي تم وضع علامة عليها على أنها موقوفة في Java 11)


جاء دور pack200 و unpack200 و API pack200 لراحة مستحقة. والسبب هو تقادم هذا المعبئ. ذات مرة ، عندما كان الإنترنت مودم وكانت سرعته 56 كيلوبايت (تذكر أذرع التطويل) ، كان لا بد من ضخ JDK لساعات. تم اختراع أداة تعبئة من شأنها ضغط JDK بشكل أفضل وتقليل وقت التنزيل. أيضا ، يمكنهم ضغط التطبيقات الصغيرة وتطبيقات العملاء. لكن الوقت يمر ، وبسرعات حالية ، فإن أداة التعبئة ليست ذات صلة.

ستتم إزالة الحزم التالية:

java.util.jar.Pack200
java.util.jar.Pack200.Packer
java.util.jar.Pack200.Unpacker

وكذلك وحدة jdk.pack.

JEP 368. كتل نصية




في وقت من الأوقات ، كان لـ Java (من بين واحد ونصف من اللغات الأخرى) تأثير على Python. نظرًا لأن Python تكتسب شعبية بشكل سريع وتدفع بثقة مع قادة آخرين في مخططات Java و C IT ، فلا حرج في النظر إليها. في وقت ما ، قدمت Java 9 JShell ، تشبه إلى حد بعيد pythonium Jupiter. والآن ، حان الوقت لكتل ​​النص.

عندما نحتاج إلى كتابة خط ، نكتب سطرًا:

String s = "";

عندما نحتاج إلى كتابة سلسلة منسقة ، نكتب شيئًا مثل هذا:
String oldHtml = "<html>\n\t<body>\n\t\t<p>Hi all!</p>\n\t</body>\n</html>";

النص غير قابل للقراءة تماما. وهكذا ، في Java 14 تم حل المشكلة. الآن ، باستخدام علامات الاقتباس الثلاثية ، يمكنك كتابة أي نص:

        String html = """
                      <html>
                          <body>
                              <p>Hi all!</p>
                          </body>
                      </html>
                      """;

إنه أكثر ملاءمة وقراءة. يمكننا ببساطة نسخ أي نص إلى الكود وليس عناء علامات التبويب والواصلات. الجمال! إذا كنا بحاجة فقط إلى نقل النص إلى سطر آخر في مثل هذا النص دون إنشاء واصلة ، فيمكننا استخدام حرف حرفي جديد - الشرطة المائلة للخلف. يعمم هذا الرمز أن التحويل الذي يليه ليس انتقالًا. مثال:

        String text = """
                    \
                 ,  , \
                     \
                   . \
                , ,  ! \
                  ; \
                    \
                   .
                """;

استنتاج:

الآلهة لا تزال تمنحك أيامًا ذهبية وليالي ذهبية وعذارى ضعيفين مثبتين على عينيك اليقظة. العب ، غن يا أصدقاء! تفقد أمسية عابرة. وفرحكم من الإهمال من خلال الدموع أبتسم.


JEP 370. واجهة برمجة تطبيقات الوصول للذاكرة الخارجية (الحاضنة)


يحدث أن يصل أحد التطبيقات إلى ذاكرة خارجية مثل Ignite و mapDB و memcached وما إلى ذلك. إن واجهات برمجة التطبيقات الحالية للوصول إليها تعمل بشكل جيد ، لكن Oracle أرادت شيئًا عالميًا. لذلك ظهرت ملخصات MemorySegment و MemoryAddress و MemoryLayout. أثناء وجود الميزة في الحاضنة ، ولا يزال بإمكان الجميع الاكتفاء بـ ByteBuffer و Unsafe و JNI.

استنتاج


أنا لا أعرف عنك أيها القارئ ، لكني أحب دورة الإصدار التي استمرت ستة أشهر والتي تحولت إليها أوراكل منذ Java 9. الآن لم تحدد أوراكل مهمة إصدار إصدارات مستقرة تمامًا ، ولكن لن يكون من الصعب مواكبة javista المعقد لاستقرار ميزة أو أخرى ، مع ملاحظة لتطويرها واختبار شيء من الحاضنة. أصبحت اللغة أكثر ابتكارا وحيوية وقابلية للتغيير وجريئة جدا من الاقتراضات من لغات أخرى بدأت تظهر فيها. نعم ، شخص لا يتماشى مع وميض الإصدارات ، ولكن مهنتنا هي التي نحتاج إلى مواكبتها ، لذلك سواء أردنا ذلك أم لا نلتقي بـ Java 14.

كالمعتاد ، أرفق مشروعًا على github مع أمثلة التعليمات البرمجية: [انقر هنا]

All Articles