مهدی عادلی فر
بنیانگذار توسینسو و برنامه نویس

قابلیت های جدید اضافه شده از جاوا 8 تا 16

زبان های برنامه نویسی برای این که از رقابت شدید بین خودشان جا نمانند و برنامه نویسان آنها را کنار نگذارند باید همیشه خود را بروز کنند و قابلیت هایی را برای بهبود استفاده از زبان برنامه نویسی ارائه کنند. زبان برنامه نویسی جاوا|Java که دهه سوم عمر خود را می گذراند نیز سعی کرده است که از این رقابت بین زبان های برنامه نویسی جا نماند و همیشه در بازار حرفی برای گفتن داشته باشد که می توان گفت نسبتا خوب عمل کرده است. از زمانی که توسعه و پشتیبانی این زبان به دست شرکت اوراکل افتاد این زبان پیشرفت های قابل ملاحظه ای داشته است. در این مطلب قابلیت هایی را که از نسخه 8 جاوا تا نسخه 16 را که در سال 2021 ارائه شده است را بررسی می کنیم.

دوره های شبکه، برنامه نویسی، مجازی سازی، امنیت، نفوذ و ... با برترین های ایران

برنامه نویسی تابعی (Functional Programming) Java 8

در نسخه 8 جاوا| Java برنامه نویسی تابعی و عبارات لامبدا Lambda به این زبان اضافه شد. در برنامه نویسی تابعی داده ها از پایپلاین ها عبور می کنند که هرکدام از این مراحل پایپلاین تغییراتی در داده ها به وجود می آورند و سرانجام به صورت یک خروجی نگاشت می شوند. به عبارت ساده تر در برنامه نویسی تابعی شما در مراحل مختلف تغییراتی را روی داده ها انجام می دهید و یک خروجی از آن می سازید. در جاوا با استفاده از Stream ها و Optional ها می توانید از مزایای Functional Programming استفاده کنید. 

استریم | Stream ها Java 8

در بیشتر برنامه های کامپیوتری شما با یک لیست از مقادیر کار می کنید که یک پردازش روی آن انجام می دهید و هرکدام از این مقادیر و یا بعضی از آنها را تغییر می دهید. قبل از نسخه 8 جاوا شما از حلقه هایی مانند for برای این کار استفاده می کردید. اما از نسخه 8 جاوا به بعد و با استفاده از قابلیت برنامه نویسی تابعی و لامبدا و با استفاده از Stream ها این کار را به شکل زیر انجام می دهید.

Stream.of("hello", "great")
    .map(s -> s + " world")
    .forEach(System.out::println);
//output
> hello world
> great world

در کد بالا یک لیست دو تایی رشته ای می سازیم و کلمه world را به انتهای آن اضافه کرده و آن را چاپ می کنیم. تابع map یک عبارت لامبدا را به عنوان ورودی دریافت می کند و آن را بر روی همه ورودی ها اعمال می کند. 
استریم ها را می توان در لیست ها و Set ها و Map ها استفاده کرد. با استفاده از استریم می توانید از دست بسیاری از حلقه های پیچیده و طولانی خلاص شوید.

مفهوم Optional ارائه شده در Java 8

یکی از مشکلات رایج در جاوا خطای Null Pointer Exception بود. این خطا زمانی رخ می داد که شیئی که با آن کار می کردیم در برنامه null بود. برای حل این مشکل مفهوم Optional در جاوا معرفی شد. در استفاده از optional مشخص می کنیم که اگر شی وجود دارد و مقدارش null نیست کار ما ادامه پیدا کند و در صورت null بودن تصمیم مربوط به آن گرفته شود. نحوه استفاده از Optional به این شکل است.

Optional.of(new Random().nextInt(10))
    .filter(i -> i % 2 == 0)
    .map(i -> "number is even: " + i)
    .ifPresent(System.out::println);
// output
> number is even: 6

در کد بالا ما یک عدد تصادفی تولید می کنیم و اگر عدد مورد نظر زوج بود آن را چاپ می کنیم.

ابزار JShell ارائه شده در Java 9

خیلی از زبان ها دارای یک خط فرمان هستند که دستورات تک خطی را اجرا می کند مانند پایتون و جاوااسکریپت و خیلی از زبان های دیگر. به این ابزار خط فرمان که دستورات زبان برنامه نویسی را اجرا  می کنند REPL می نامند. زبان جاوا نیز از نسخه 9 به بعد ابزاری به نام JShell معرفی کرده است. با استفاده از JShell شما می توانید کدهای خود را بدون آن که در کلاس بنویسید و کامپایل کنید اجرا کنید و نتیجه آن را ببینید. فقط یک خط کد جاوا را بنویسید و اینتر را بزنید آن کد اجرا خواهد شد. با این ابزار شما می توانید متغیر معرفی کنیدو کلاس تعریف کنید و از آن استفاده کنید و از قابلیت های دیگر جاوا استفاده کنید. یکی از قابلیت های جالب این ابزار امکان auto-completion است که خود کد شما را تکمیل می کند فقط کافیست چند حرف اول دستور را بنویسید و کلید تب را بزنید. کد زیر نمونه ای از این ابزار است.

jshell> System.out.println("Hello Tosinso users")
Hello Tosinso users

jshell> var a=15
a ==> 15

jshell> System.out.println(a)
15

ارائه Factory method هایی برای مجموعه ها در Java 9

مقداردهی اولی لیست ها قبلا به شکل زیر بود 

jshell> List<Integer> list = Arrays.asList(1, 2, 3, 4)
list ==> [1, 2, 3, 4]

اما این روش تغییر کرده و از ورژن 9 جاوا به شکل زیر نوشته می شود

jshell> List<Integer> list = List.of(1, 2, 3, 4)
b ==> [1, 2, 3, 4]

شما از متد جالب of می توانید برای لیست ها و set ها و Map ها استفاده کنید. به همین راحتی!

تشخیص نوع با استفاده از var در Java 10

برای ساخت متغیر یا شی جدید دیگر لازم نیست که که نوع متغیر را قبل از آن بیاوریم و می توانیم به جای آن از کلمه کلیدی var استفاده کنیم. این قابلیت در زبان هایی مانند سی شارپ از قبل وجود داشت ولی جاوا آن را از نسخه 10 به بعد اضافه کرده است. در این روش خود کامپایلر با توجه به مقدار اولیه ای که داخل شی یا متغیر ریخته می شود نوع آن را شناسایی می کند. مانند کد زیر

jshell> var x = new HashSet<String>()
x ==> []

jshell> x.add("apple")
$1 ==> true

دقت کنید که از کلمه کلیدی var فقط می توان داخل بدنه متد استفاده کرد و بقیه جاها باید از روش قبلی استفاده نمود.

اجرای برنامه های جاوای تک فایلی با یک خط کد Java 11

اگر برنامه جاوا ما در یک فایل جاوا جا داده شده باشد. قبلا برای اجرای آن توسط خط فرمان باید اول آن را کامپایل می کردیم واز داخل آن فایل class می ساختیم که حاوی بایت کد بود و سپس آن را اجرا می کردیم. ولی از جاوا ۱۱ به بعد با یک خط می توان برنامه را کامپایل و اجرا نمود برای مثال اگر برنامه ای به شکل زیر در یک فایل به نام Main.java داشته باشیم.

public class Main {
  public static void main(String[] args) {
    System.out.println("hello world");
  }
}

می توانیم با دستور زیر آن را اجرا کنیم.

$ java ./Main.java
hello world

عبارت switch در Java 12

عبارت switch در جاوا 12 اضافه شده است که به شکل زیر کار می کند. اگر قبلا می خواستیم با استفاده از switch تصمیم بگیریم که چه مقداری به یک متغیر بدهیم به روش زیر عمل می کردیم.

jshell> var i = 3
jshell> String s;
jshell> switch(i) {
   ...>     case 1: s = "one"; break;
   ...>     case 2: s = "two"; break;
   ...>     case 3: s = "three"; break;
   ...>     default: s = "unknown number";
   ...> }
jshell> s
s ==> "three"

ولی از نسخه 12 جاوا به بعد می توانیم از روش زیر نیز استفاده کنیم. 

jshell> var i = 3;
jshell> var x = switch(i) {
   ...>     case 1 -> "one";
   ...>     case 2 -> "two";
   ...>     case 3 -> "three";
   ...>     default -> "unknown number";
   ...> };
x ==> "three"

فقط در استفاده از این روش به نکات زیر دقت کنید.

  • به جای علامت دو نقطه از علامت فلش <- استفاده می شود.
  • نیازی به استفاده از break نیست.

مقادیر رشته ای چند خطی Java 13

اگر با مقادیر رشته ای طولانی مانند عبارات json کار کرده باشید در جاوا یا مجبور بودیم که کل رشته را در یک خط قرار بدهیم یا در انتهای خط رشته را می بستیم و بقیه را با علامت + در خط بعدی می نوشتیم. اما در جاوا 13 می توانید به شکل زیر رشته های چند خطی داشته باشید و از آنها استفاده کنید.

public class Main { 
  public static void main(String [] args) {
    var s = """
        {
            "recipe": "watermelon smoothie",
            "duration": "10 mins",
            "items": ["watermelon", "lemon", "parsley"]
        }""";


    System.out.println(s);
  }
}

کلاس های داده های (record) در جاوا 14

برخی اوقات کلاس هایی را تعریف می کنیم که متدی ندارند و فقط کلاس مربوطه برای نگهداری داده ها است. خب برای آنها باید فیلد ها تعریف می شد و getter , setter تعریف می شود و متد equals هم گاهی لازم بود تا override شود. اما در جاوا 14 قابلیت جدیدی به نام record ارائه شده است که دیگر نیازی به خیلی از کارهایی که گفتیم نیست و شما فقط نوع فیلد ها را مشخص می کنید.  کد زیر مثالی از این قابلیت است.

jshell> record Employee (String name, int age, String department) {}
|  created record Employee

jshell> var x = new Employee("Anne", 25, "Legal");
x ==> Employee[name=Anne, age=25, department=Legal]

jshell> x.name()
$2 ==> "Anne"

قابلیت instanceof در Java 14

قبلا هم در جاوا قابلیت instanceof وجود داشت ولی به شکل زیر استفاده می شد.

Object obj = new String("hello");
if (obj instanceof String) {
  System.out.println("String length: " + ((String)obj).length());
}

مشکلی که این روش داشت این بود که ابتدا چک می کردیم که s از نوع String هست یا خیر سپس دوباره آن را cast می کردیم که بتوانیم مقادیر رشته ای آن را دریافت کنیم
اما از جاوا 14 به بعد می توانیم از این روش استفاده کنیم.

Object obj = new String("hello");
if (obj instanceof String mystr) {
  System.out.println("String length: " + mystr.length());
}

کلاس های sealed در Java 15

با استفاده از کلمه کلیدی sealed می توانید مشخص کنید که کدام کلاس ها می توانند از کلاس یا اینترفیس شما ارث بری داشته باشند به نوعی کلاس هایی را که از کلاس یا اینترفیس شما ارث بری دارند را محدود می کنید. مانند کد زیر

public sealed interface Fruit permits Apple, Pear {
    String getName();
}
public final class Apple implements Fruit {
    public String getName() { return "Apple"; }
}

public final class Pear implements Fruit {
    public String getName() { return "Pear"; }
}

بهبود های Java 16

در جاوا 16 سعی شده است که قابلیت های record, sealed class, instanceof بهبود داده شود و بهینه سازی هایی در این موارد انجام شده است. زیرا که این قابلیت ها حالت preview در نسخه های قبلی داشتند که بسیاری در نسخه 16 نهایی شده اند و مشکلات آنها برطرف شده است.
با وب سایت Tosinso همراه باشید.



مهدی عادلی فر
مهدی عادلی فر

بنیانگذار توسینسو و برنامه نویس

مهدی عادلی، بنیان گذار TOSINSO. کارشناس ارشد نرم افزار کامپیوتر از دانشگاه صنعتی امیرکبیر و #C و جاوا و اندروید کار می کنم. در زمینه های موبایل و وب و ویندوز فعالیت دارم و به طراحی نرم افزار و اصول مهندسی نرم افزار علاقه مندم.

نظرات