JavaRush /وبلاگ جاوا /Random-FA /از 8 تا 13: مروری کامل بر نسخه های جاوا. قسمت 1

از 8 تا 13: مروری کامل بر نسخه های جاوا. قسمت 1

در گروه منتشر شد
بچه گربه ها، سلام به همه)) بنابراین، امروز در سال 2020 هستیم و تا انتشار جاوا 14 بسیار کمی باقی مانده است. شما باید منتظر نسخه نهایی در 17 مارس باشید، ما بعد از این واقعیت چیزهای تازه و جالب را در آنجا تجزیه و تحلیل خواهیم کرد، اما امروز می خواهم حافظه خود را در نسخه های قبلی جاوا تازه کنم. چه چیز جدیدی برای ما آوردند؟ بیایید نگاهی بیندازیم. بیایید بررسی را با جاوا 8 شروع کنیم، زیرا هنوز کاملاً مرتبط است و در اکثر پروژه ها استفاده می شود. از 8 تا 13: مروری کامل بر نسخه های جاوا.  قسمت 1 - 1پیش از این، نسخه های جدید هر 3-5 سال منتشر می شد، اما اخیراً اوراکل رویکرد متفاوتی را در پیش گرفته است - "جاوای جدید هر شش ماه". و بنابراین، هر شش ماه شاهد انتشار ویژگی‌ها هستیم. چه خوب باشد چه بد، همه آن را متفاوت می بینند. به عنوان مثال، من این را خیلی دوست ندارم، زیرا نسخه های جدید ویژگی های جدید زیادی ندارند، اما در عین حال، نسخه ها مانند قارچ پس از باران رشد می کنند. من چند بار در پروژه ای با جاوا 8 پلک زدم و جاوا 16 قبلاً منتشر شده بود (اما وقتی به ندرت منتشر می شود، ویژگی های جدید جمع می شود و در نهایت این رویداد مدت هاست مانند تعطیلات: همه در حال بحث هستند. چیزهای جدید و شما نمی توانید از کنار آن بگذرید) . پس بیایید شروع کنیم!

جاوا 8

رابط کاربردی

این چیه؟ یک رابط کاربردی، رابطی است که شامل یک روش (انتزاعی) اجرا نشده است. @FunctionalInterface یک حاشیه نویسی اختیاری است که در بالای چنین رابطی قرار می گیرد. برای بررسی اینکه آیا الزامات یک رابط کاربردی را برآورده می کند (فقط یک روش انتزاعی) لازم است. اما مانند همیشه، ما چند هشدار داریم: روش های پیش فرض و استاتیک تحت این الزامات قرار نمی گیرند. بنابراین، می تواند چندین روش از این قبیل + یک روش انتزاعی وجود داشته باشد و رابط کاربردی خواهد بود. همچنین ممکن است شامل متدهایی از کلاس Object باشد که بر تعریف اینترفیس به عنوان عملکردی تأثیری ندارد. من چند کلمه در مورد روش های پیش فرض و استاتیک اضافه می کنم:
  1. متدهایی با اصلاح‌کننده پیش‌فرض به شما این امکان را می‌دهند که روش‌های جدیدی را به اینترفیس‌ها اضافه کنید بدون اینکه پیاده‌سازی موجود آن‌ها را خراب کنید.

    public interface Something {
      default void someMethod {
          System.out.println("Some text......");
      }
    }

    بله، بله، ما متد پیاده‌سازی شده را به اینترفیس اضافه می‌کنیم و هنگام پیاده‌سازی این متد، نمی‌توانید آن را override کنید، بلکه از آن به عنوان یک ارثی استفاده کنید. اما اگر یک کلاس دو اینترفیس را با یک متد معین پیاده سازی کند، خطای کامپایل خواهیم داشت و اگر اینترفیس ها را پیاده سازی کند و کلاسی را با یک متد یکسان خاص به ارث ببرد، متد کلاس والد با متدهای اینترفیس همپوشانی پیدا می کند و استثنا کار نمی کند.

  2. متدهای استاتیک در یک رابط همانند متدهای استاتیک در یک کلاس عمل می کنند. فراموش نکنید: شما نمی توانید متدهای ایستا را به ارث ببرید ، همانطور که نمی توانید یک متد استاتیک را از یک کلاس فرعی فراخوانی کنید.

بنابراین، چند کلمه بیشتر در مورد رابط های کاربردی و بیایید ادامه دهیم. در اینجا لیست های اصلی FI ها وجود دارد (بقیه انواع آنها هستند):

    محمول - مقداری T را به عنوان آرگومان می گیرد، بولی را برمی گرداند.

    مثال:boolean someMethod(T t);

  • Consumer - یک آرگومان از نوع T را می گیرد، چیزی را برمی گرداند (void).

    مثال:void someMethod(T t);

  • تامین کننده - هیچ چیزی را به عنوان ورودی نمی گیرد، اما مقداری T را برمی گرداند.

    مثال:T someMethod();

  • تابع - پارامتری از نوع T را به عنوان ورودی می گیرد، مقداری از نوع R را برمی گرداند.

    مثال:R someMethod(T t);

  • UnaryOperator - آرگومان T را می گیرد و مقداری از نوع T را برمی گرداند.

    مثال:T someMethod(T t);

جریان

استریم ها راهی برای مدیریت ساختارهای داده به سبک عملکردی هستند. معمولاً اینها مجموعه هستند (اما می توانید از آنها در موقعیت های دیگر و کمتر رایج استفاده کنید). به زبانی قابل فهم تر، Stream یک جریان داده است که ما آن را طوری پردازش می کنیم که گویی با همه داده ها به طور همزمان کار می کنیم، و نه نیروی بی رحمانه، مانند هر کدام. بیایید به یک مثال کوچک نگاه کنیم. فرض کنید مجموعه‌ای از اعداد داریم که می‌خواهیم آن‌ها را فیلتر کنیم (کمتر از 50)، 5 عدد افزایش دهیم و 4 عدد اول را از بقیه به کنسول خروجی دهیم. چگونه این کار را قبلا انجام می دادیم:
List<Integer> list = Arrays.asList(46, 34, 24, 93, 91, 1, 34, 94);

int count = 0;

for (int x : list) {

  if (x >= 50) continue;

  x += 5;

  count++;

  if (count > 4) break;

  System.out.print(x);

}
به نظر می رسد کد زیادی وجود ندارد، و منطق از قبل کمی گیج کننده است. بیایید ببینیم با استفاده از جریان چگونه به نظر می رسد:
Stream.of(46, 34, 24, 93, 91, 1, 34, 94)

      .filter(x -> x < 50)

      .map(x -> x + 5)

      .limit(4)

      .forEach(System.out::print);
استریم ها با کاهش مقدار کد و خوانایی بیشتر، زندگی را بسیار ساده می کنند. برای کسانی که می خواهند با جزئیات بیشتر به این موضوع بپردازند، در اینجا یک مقاله خوب (حتی می توانم بگویم عالی) در مورد این موضوع وجود دارد .

لامبدا

شاید مهمترین و مورد انتظارترین ویژگی ظاهر لامبدا باشد. لامبدا چیست؟ این یک بلوک از کد است که می تواند به مکان های مختلف منتقل شود تا بتوان آن را بعداً هر چند بار که لازم است اجرا کرد. خیلی گیج کننده به نظر می رسد، اینطور نیست؟ به زبان ساده، با استفاده از لامبدا، می‌توانید روشی از یک رابط کاربردی (نوعی پیاده‌سازی یک کلاس ناشناس) پیاده‌سازی کنید:
Runnable runnable = () -> { System.out.println("I'm running !");};

new Thread(runnable).start();
ما متد run() را به سرعت و بدون نوار قرمز غیر ضروری پیاده سازی کردیم. و بله: Runnable یک رابط کاربردی است. من همچنین هنگام کار با استریم ها از لامبدا استفاده می کنم (همانطور که در مثال های استریم های بالا). ما خیلی عمیق نمی‌رویم، از آنجایی که می‌توانید کاملاً عمیق شیرجه بزنید، من چند پیوند می‌گذارم تا بچه‌هایی که هنوز در دل هستند بتوانند عمیق‌تر کاوش کنند:

برای هر

جاوا 8 دارای یک foreach جدید است که با یک جریان داده مانند یک جریان کار می کند. در اینجا یک مثال است:
List<Integer> someList = Arrays.asList(1, 3, 5, 7, 9);

someList.forEach(x -> System.out.println(x));
(مشابه SomeList.stream().foreach(…))

مرجع روش

متدهای مرجع یک نحو جدید و مفید هستند که برای ارجاع به روش‌های موجود یا سازنده کلاس‌ها یا اشیاء جاوا از طریق :: طراحی شده‌اند. مراجع روش در چهار نوع هستند:
  1. لینک به طراح:

    SomeObject obj = SomeObject::new

  2. مرجع روش استاتیک:

    SomeObject::someStaticMethod

  3. ارجاع به روش غیر ایستا یک شی از نوع خاصی:

    SomeObject::someMethod

  4. ارجاع به یک روش منظم (غیر ایستا) یک شی خاص

    obj::someMethod

اغلب، منابع روش در استریم ها به جای لامبدا استفاده می شود (روش های مرجع سریعتر از لامبدا هستند، اما از نظر خوانایی پایین تر هستند).
someList.stream()

        .map(String::toUpperCase)

      .forEach(System.out::println);
برای کسانی که اطلاعات بیشتری در مورد روش های مرجع می خواهند:

زمان API

یک کتابخانه جدید برای کار با تاریخ و زمان وجود دارد - java.time. از 8 تا 13: مروری کامل بر نسخه های جاوا.  قسمت 1 - 2API جدید مشابه هر Joda-Time است. مهمترین بخش های این API عبارتند از:
  • LocalDate یک تاریخ خاص است، به عنوان مثال - 2010-01-09.
  • LocalTime - زمان با در نظر گرفتن منطقه زمانی - 19:45:55 (مشابه با LocalDate)؛
  • LocalDateTime - ترکیبی LocalDate + LocalTime - 04-01-2020 15:37:47؛
  • ZoneId - نشان دهنده مناطق زمانی است.
  • ساعت - با استفاده از این نوع می توانید به زمان و تاریخ فعلی دسترسی داشته باشید.
در اینجا چند مقاله واقعا جالب در مورد این موضوع وجود دارد:

اختیاری

این یک کلاس جدید در بسته java.util است ، یک بسته بندی ارزش که ترفند آن این است که می تواند با خیال راحت حاوی null نیز باشد . دریافت اختیاری: اگر Optional<String> someOptional = Optional.of("Something"); در Optional.of null را پاس کنیم ، NullPointerException مورد علاقه خود را دریافت خواهیم کرد . برای چنین مواردی استفاده می کنند: Optional<String> someOptional = Optional.ofNullable("Something"); - در این روش نباید از null ترسید. در مرحله بعد، یک ابتدا خالی اختیاری ایجاد کنید: Optional<String> someOptional = Optional.empty(); برای بررسی خالی بودن آن، استفاده از: someOptional.isPresent(); true یا false را به ما برمی گرداند. اگر مقداری وجود داشت، عمل خاصی را انجام دهید، و اگر مقداری وجود نداشت، هیچ کاری انجام ندهید: someOptional.ifPresent(System.out::println); یک روش معکوس که مقدار ارسال شده را در صورت خالی بودن اختیاری برمی‌گرداند (نوعی طرح پشتیبان): System.out.println(someOptional.orElse("Some default content")); می‌توانید برای مدت بسیار بسیار طولانی ادامه دهید ( خوشبختانه، Optional روش‌هایی را با هر دو دست سخاوتمندانه اضافه کرده است)، اما ما به این موضوع نمی‌پردازیم. برای شروع بهتر است چند لینک بگذارم: ما به معروف ترین نوآوری ها در جاوا 8 پرداختیم - این همه چیز نیست. اگر می خواهید بیشتر بدانید، این را برای شما گذاشتم:

جاوا 9

بنابراین، در 21 سپتامبر 2017، جهان JDK 9 را دید. این جاوا 9 دارای مجموعه ای از ویژگی های غنی است. در حالی که مفاهیم زبان جدیدی وجود ندارد، APIهای جدید و دستورات تشخیصی قطعا مورد توجه توسعه دهندگان خواهند بود. از 8 تا 13: مروری کامل بر نسخه های جاوا.  قسمت 1 - 4

JShell (REPL - حلقه خواندن-ارزیابی-چاپ)

این یک پیاده‌سازی جاوا از یک کنسول تعاملی است که برای آزمایش عملکرد و استفاده از ساختارهای مختلف در کنسول مانند رابط‌ها، کلاس‌ها، enums، عملگرها و غیره استفاده می‌شود. برای راه اندازی JShell، فقط باید jshell را در ترمینال بنویسید. سپس می‌توانیم هر چیزی که تخیلمان اجازه می‌دهد بنویسیم: از 8 تا 13: مروری کامل بر نسخه های جاوا.  قسمت 1 - 5با استفاده از JShell، می‌توانید متدهای سطح بالا ایجاد کنید و در همان جلسه از آنها استفاده کنید. روش‌ها درست مانند روش‌های استاتیک کار می‌کنند، با این تفاوت که کلمه کلیدی استاتیک را می‌توان حذف کرد. در کتابچه راهنمای Java 9 REPL (JShell) بیشتر بخوانید .

خصوصی

با شروع نسخه 9 جاوا، ما این فرصت را داریم که از روش های خصوصی در رابط ها استفاده کنیم (روش های پیش فرض و ایستا، زیرا به دلیل دسترسی ناکافی به سادگی نمی توانیم دیگران را لغو کنیم). private static void someMethod(){} try-with-resources توانایی رسیدگی به استثناهای Try-With-Resources ارتقا یافته است:
BufferedReader reader = new BufferedReader(new FileReader("....."));
  try (reader2) {
  ....
}

ماژولاریت ( Jigsaw )

ماژول مجموعه ای از بسته ها و منابع مرتبط به همراه یک فایل توصیفگر ماژول جدید است. این رویکرد برای کاهش جفت کد استفاده می شود. کوپلینگ شل یک عامل کلیدی برای نگهداری و گسترش کد است. ماژولاریت در سطوح مختلف اجرا می شود:
  1. زبان برنامه نویسی.
  2. ماشین مجازی.
  3. API استاندارد جاوا.
JDK 9 دارای 92 ماژول است: ما می توانیم از آنها استفاده کنیم یا ماژول خود را ایجاد کنیم. در اینجا چند پیوند برای نگاه عمیق تر وجود دارد:

مجموعه تغییرناپذیر

در جاوا 9 امکان ایجاد و پر کردن یک مجموعه با یک خط فراهم شد، در حالی که آن را غیرقابل تغییر می‌کردیم (قبلاً برای ایجاد یک مجموعه غیرقابل تغییر، نیاز به ایجاد یک مجموعه، پر کردن آن با داده‌ها و فراخوانی یک متد داشتیم، به عنوان مثال، Collections.unmodifiableList). نمونه ای از چنین آفرینشی: List someList = List.of("first","second","third");

سایر نوآوری ها:

  • گسترش یافته اختیاری (روش های جدید اضافه شده)؛
  • به نظر می رسد که رابط های ProcessHandle و ProcessHandle اعمال سیستم عامل را کنترل می کنند.
  • G1 - جمع آوری زباله پیش فرض؛
  • سرویس گیرنده HTTP با پشتیبانی از پروتکل های HTTP/2 و WebSocket.
  • جریان گسترش یافته؛
  • چارچوب API Reactive Streams اضافه شده (برای برنامه نویسی واکنشی).
برای غوطه وری کامل تر در جاوا 9، به شما توصیه می کنم بخوانید:

جاوا 10

بنابراین، شش ماه پس از انتشار جاوا 9، در مارس 2018 (مثل دیروز به یاد دارم)، جاوا 10 وارد صحنه شد. از 8 تا 13: مروری کامل بر نسخه های جاوا.  قسمت 1 - 6

var

در حال حاضر ما نیازی به ارائه یک نوع داده نداریم. ما پیام را به عنوان var علامت گذاری می کنیم و کامپایلر نوع پیام را با نوع اولیه ساز موجود در سمت راست تعیین می کند. این ویژگی فقط برای متغیرهای محلی با مقدار اولیه در دسترس است: نمی توان از آن برای آرگومان های متد، انواع برگشتی و غیره استفاده کرد، زیرا هیچ اولیه کننده ای وجود ندارد که بتواند نوع را تعریف کند. مثال var (برای نوع String):
var message = "Some message…..";
System.out.println(message);
var یک کلمه کلیدی نیست: در اصل یک نام نوع رزرو شده است، درست مانند int . مزیت var عالی است: اعلان‌های نوع توجه زیادی را به خود اختصاص می‌دهند بدون اینکه هیچ مزیتی به همراه داشته باشند و این ویژگی باعث صرفه‌جویی در زمان می‌شود. اما در عین حال، اگر متغیری از یک زنجیره طولانی از متدها به دست آید، کد کمتر قابل خواندن می شود، زیرا بلافاصله مشخص نیست که چه نوع شی در آنجا قرار دارد. تقدیم به کسانی که می خواهند با این قابلیت بیشتر آشنا شوند:

کامپایلر JIT (GraalVM)

بدون مقدمه، اجازه دهید به شما یادآوری کنم که وقتی دستور javac را اجرا می کنید، برنامه جاوا از کد جاوا به بایت کد JVM، که نمایش باینری برنامه است، کامپایل می شود. اما یک پردازنده کامپیوتر معمولی نمی تواند به سادگی بایت کد JVM را اجرا کند. برای اینکه برنامه JVM شما کار کند، به کامپایلر دیگری برای این بایت کد نیاز دارید که به کد ماشینی تبدیل می شود که پردازنده از قبل قادر به استفاده از آن است. در مقایسه با javac، این کامپایلر بسیار پیچیده‌تر است، اما کد ماشینی با کیفیت بالاتری تولید می‌کند. در حال حاضر، OpenJDK حاوی ماشین مجازی HotSpot است که به نوبه خود دارای دو کامپایلر اصلی JIT است. اولین، C1 ( کامپایلر مشتری )، برای عملیات با سرعت بالاتر طراحی شده است، اما بهینه سازی کد آسیب می بیند. دومی C2 (کامپایلر سرور) است. سرعت اجرا آسیب می بیند، اما کد بهینه تر است. چه زمانی از کدام یک استفاده می شود؟ C1 برای برنامه های دسکتاپ که در آن مکث های طولانی JIT نامطلوب است عالی است، و C2 برای برنامه های سرور طولانی مدت که در آن صرف زمان بیشتر برای کامپایل کردن کاملاً قابل تحمل است عالی است. کامپایل چند سطحی زمانی است که کامپایل ابتدا از C1 عبور می کند و نتیجه از طریق C2 می رود (برای بهینه سازی بیشتر استفاده می شود). GraalVM پروژه ای است که برای جایگزینی کامل HotSpot ایجاد شده است. ما می توانیم Graal را به عنوان چندین پروژه مرتبط در نظر بگیریم: یک کامپایلر جدید JIT برای HotSpot و یک ماشین مجازی چند زبانه جدید. ویژگی این کامپایلر JIT این است که به زبان جاوا نوشته شده است. مزیت کامپایلر Graal ایمنی است، یعنی خرابی نیست، اما استثناها، نه نشت حافظه. ما همچنین پشتیبانی خوبی از IDE خواهیم داشت و می‌توانیم از اشکال‌زداها، پروفایل‌کننده‌ها یا سایر ابزارهای راحت استفاده کنیم. علاوه بر این، کامپایلر ممکن است مستقل از HotSpot باشد و بتواند نسخه کامپایل شده JIT سریعتری از خود ایجاد کند. برای حفارها:

موازی G1

آشغال‌گیر G1 مطمئناً جالب است، بدون شک، اما یک نقطه ضعف نیز دارد: چرخه GC کامل تک رشته‌ای را انجام می‌دهد. در زمانی که به تمام قدرت سخت افزاری که می توانید برای یافتن اشیاء استفاده نشده نیاز دارید، ما به یک رشته محدود می شویم. جاوا 10 این مشکل را برطرف کرد. حالا GC با تمام منابعی که به آن اضافه می کنیم کار می کند (یعنی چند رشته ای می شود). برای دستیابی به این هدف، توسعه دهندگان زبان جداسازی منابع اصلی از GC را بهبود بخشیده اند و یک رابط تمیز خوب برای GC ایجاد کرده اند. توسعه دهندگان این ناز، OpenJDK، مجبور بودند به طور خاص فضای خالی در کد را پاک کنند تا نه تنها ایجاد GC های جدید را تا حد امکان ساده کنند، بلکه امکان غیرفعال کردن سریع GC های غیر ضروری از مونتاژ را نیز فراهم کنند. یکی از معیارهای اصلی موفقیت، عدم کاهش سرعت کار پس از این همه پیشرفت است. بیایید نگاه کنیم: سایر نوآوری ها:
  1. یک واسط جمع‌آوری زباله تمیز معرفی شده است. این امر جداسازی کد منبع از جمع‌آورنده‌های مختلف زباله را بهبود می‌بخشد، و امکان ادغام جمع‌آورنده‌های جایگزین را به سرعت و بدون دردسر فراهم می‌کند.
  2. ترکیب منابع JDK در یک مخزن.
  3. مجموعه ها روش جدیدی دریافت کردند - copyOf (Collection) که یک کپی تغییرناپذیر از این مجموعه را برمی گرداند.
  4. اختیاری (و انواع آن) یک روش جدید دارد .orElseThrow() ;
  5. از این پس، JVM ها می دانند که در یک ظرف Docker در حال اجرا هستند و به جای پرس و جو از خود سیستم عامل، پیکربندی مخصوص کانتینر را واکشی می کنند.
در اینجا مواد بیشتری برای معرفی دقیق تر جاوا 10 وجود دارد: من قبلاً با این واقعیت که برخی از نسخه های جاوا 1.x نامیده می شدند بسیار گیج می شدم. من می خواهم واضح بگویم: نسخه های جاوا قبل از 9 به سادگی طرح نامگذاری متفاوتی داشتند. به عنوان مثال، جاوا 8 را می توان 1.8 ، جاوا 5 - 1.5 و غیره نیز نامید. و اکنون می بینیم که با انتقال به نسخه های منتشر شده از جاوا 9، طرح نام گذاری نیز تغییر کرده است و نسخه های جاوا دیگر با 1.x پیشوند ندارند. . این پایان بخش اول است: ویژگی های جالب جدید جاوا 8-10 را مرور کردیم. بیایید در پست بعدی آشنایی خود را با جدیدترین ها ادامه دهیم .
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION