Джерело: Medium В основному Java критикують за дві речі: багатослівність і кількість шаблонного коду, що генерується в багатьох випадках без потреби. Хоча мені завжди подобалася Java, я не можу сказати, що ці твердження є помилковими. Це справді правда: зайва деталізація в Java може іноді сильно дратувати. Однак ми маємо визнати, що живемо не в ідеальному світі, і в більшості випадків нам доводиться вибирати найменше з двох лих. З часів створення Java не була ідеальною: ми все це знаємо, але головне питання полягає в тому, чому раніше нічого не робабо для вирішення цих проблем. Мені здається, єдина причина, через яку зміни зайняли так багато часу, полягає в тому, що мови Java не вистачало конкуренції, і все було так, як було. Java домінувала на ринку, ймовірно, через відсутність серйозних конкурентів і великих зусиль, зроблених спочатку Sun, а потім Oracle. Високий рівень безпеки типів, що забезпечується Java, і хороша структуризація мови зробабо його дуже популярним для великих проектів. Крім того, це мультиплатформна мова, яка працює на власній віртуальній машині. Якщо ще зважити на автоматичну оптимізацію продуктивності за допомогою JIT-компілятора, все це зводить до мінімуму вплив погано написаного коду. Загалом виходить досить вагомий набір причин для використання Java. Але що сталося потім? Сталося те, що на ринку з'явабося нові мови, здатні працювати в тій же JVM, що й Java. Мови, які усували деякі з найбільших незручностей у Java і в ряді випадків пропонували розробникам більш приємне середовище меншим порогом входження. Перш ніж ми продовжимо, давайте підіб'ємо підсумки і зробимо короткий екскурс в історію мов JVM.
Покращений оператор
Новий оператор
Історія мов JVM
Для початку я хотів би прояснити одну річ: я не згадав деякі з існуючих мов JVM тому, що вони ніколи не мали достатньої підтримки, щоб вважатися кандидатами для широкого використання в нашій галузі. А тепер розпочнемо наш короткий огляд історії мов JVM. Першим у нас буде мова Java - найстаріша і найпопулярніша мова у світі JVM. Офіційно Java випущена в січні 1996 року, тому мова існує вже 24 роки. Непогано, правда? Спочатку Java була суто імперативною мовою, яка слідувала об'єктно-орієнтованому стилю програмування; це також була строго типізована мова. Синтаксис Java певною мірою схожий на мови C++ і C, але він вважається покращеною версією, оскільки Java писати код набагато простіше, ніж C або C++. З іншого боку, ми маємо найбільший аргумент серед його недоброзичливців — багатослівність (verbosity). Другою мовою JVM був Groovy. Він існує з 2003 року, хоча його перша стандартизована версія 1.0 з'явилася лише у січні 2007 року. Перевага Groovy в тому, що його можна використовувати як мову сценаріїв. Groovy – це мова з динамічною типізацією, тому перевірка типів виконується під час виконання. Це одна з причин, чому деяким розробникам не подобається Groovy. Ви пишете свій код на Groovy і під час компіляції він виглядає правильно, але потім під час виконання ви розумієте, що щось не так. Потім з'явилася ще одна популярна мова: ми говоримо про Scala. Його випустабо 2004 року. Він приніс у світ JVM нову модель роботи: функціональне програмування та декларативний підхід. Загалом Scala була першою мовою, де з'явилася концепція незмінності, яка потім використовувалася в удосконаленні Java. З іншого боку, недоброзичливцям Scala не подобається через складну граматику і досить низьку читальність. Наступною мовою, яка з'явилася у світі JVM, була Clojure, чисто функціональна мова. Він став досить популярним останнім часом, хоч з'явився ще 2007 року. Clojure – це мова на основі LISP, що відрізняється простотою та використанням простих функцій. Серед його недоліків можна згадати те, що він динамічно типізований (як і Groovy), а крива навчання набагато крутіше, оскільки його синтаксис повністю відрізняється від інших мов JVM. І, нарешті, у нас є Kotlin. Kotlin вперше з'явився у лютому 2016 року, і з того часу його популярність не переставала зростати. Він розроблений компанією JetBrains з головною метою: усунути найвідоміші проблеми Java. За своїм задумом Kotlin зберіг всі переваги Java, але в той же час вирішив багато проблем. Це найважливіші мови JVM. Як я вже сказав, ми пропустабо деякі інші мови, які не такі популярні: Jython, JRuby, Ceylon, Fantom і т.д. За бажанням, ви можете дізнатися весь список існуючих мов JVMу Вікіпедії. Напевно, ви вже зрозуміли, що Java не мала особливих конкурентів у перші вісім чи десять років після створення, але з того часу все змінилося. Отже, конкуренція – це добре чи погано?Переваги зростаючої конкуренції
Java не сильно змінилася за перші роки свого існування. Мабуть, тому, що цього не було потреби. Ця мова широко використовувалася і завжди була дуже популярна, незважаючи на те, що вона далека від досконалості. Але потім з'явабося конкуренти, сучасніші мови, які пропонували нові функції та вирішували деякі проблеми, від яких Java-розробники страждали довгий час. Наприклад, давайте подивимося на мову Scala. Популярність Scala зростала з 2009 року. Розробники вітали цей новий функціональний стиль, який дав їм більшу гнучкість, а також можливість безпечно та легко писати паралельний код. Як Oracle відреагувала на цю нову тенденцію? У 2014 році з'явабося Java Lambdas та Streams. Я думаю, ми можемо погодитися, що саме тоді Java зробила свій найбільший крок до перемоги над Scala. Наразі будь-який програміст знає, що Scala вже не в тренді. Ще одна перевага більшої кількості конкурентів у світі JVM — постійні покращення, які вносять у компілятор JIT та JVM. Тепер набагато більше людей зацікавлені в оптимізації JVM та покращенні продуктивності. Тож конкуренція – це добре для всіх! Найсвіжішою альтернативою Java стала мова Kotlin. Його поява стала дуже важливою для розвитку Java, оскільки нова мова в певному сенсі вказала Oracle шлях уперед. Приклад Kotlin показав, що можна зберегти плюси Java, але створити більш компактну мову, якою швидше писати код. Якщо подивитися на графік Google Trends, можна побачити, що з 2016 до 2018 року популярність Kotlin стрімко зростала. Але за останні два роки ажіотаж упав. Компанія Oracle уважно вивчила реакцію галузі на Kotlin. Якщо ви побачите примітки до випуску JDK 15 , ви побачите, що деякі з нових функцій Java є копіями того, що з'явилося в Kotlin. Це нові записи Java , нові текстові блоки (багаторядкові рядки з потрійними лапками) і новий операторswitch
, який є копією оператора when
в Kotlin. Все, про що ми говорабо, я називаю "котлінізацією Java". Ставши сильнішим конкурентом, Kotlin вказав Java шлях, яким потрібно йти.
«Котлінізація» Java
Деякі з майбутніх функцій Java стануть значним покращенням з погляду читабельності та усунення однієї з найслабших сторін мови Java – її багатослівності. Можна стверджувати, що багато анонсованих функцій Java підозріло схожі на деякі функції Kotlin. Але врахуйте, що більшість із них є попередніми версіями . Це означає, що якщо ви встановите JDK 14 або JDK 15 (коли його випустять), ви не зможете використовувати їх за промовчанням. Прев'ю функцій Java - це нові функції, які представлені в релізі, але за замовчуванням відключені. Вони включені в нову версію тільки для того, щоб зібрати відгуки спільноти розробників, тому вони ще можуть бути змінені. Ось чому не рекомендується використовувати їх у робочому коді. Щоб увімкнути їх під час компіляції, вам потрібно буде зробити таке:javac --enable-preview --release 14
Якщо ви хочете увімкнути їх під час виконання, вам потрібно буде запустити наступне:
java --enable-preview YourClass
Звичайно, ви також можете включити їх у своєму середовищі IDE, але будьте обережні, щоб не включати попередній перегляд за промовчанням у всіх ваших нових проектах! Давайте подивимося на ті зміни, які вплинуть на наш кодинг у майбутніх версіях Java.
Записи Java
Записи Java - це функція, яку багато хто з нас давно вимагає. Я припускаю, що ви опинабося в ситуації ситуації, коли вам потрібно було реалізувати toString , hashCode , equals , а також гетери для кожного існуючого поля. У Kotlin для вирішення цієї проблеми є класи даних , і Java має намір зробити те ж саме, випускаючи класи записів , які вже є у Scala у вигляді case classes . Основна мета цих класів - зберігати незмінні дані в об'єкті. Давайте на прикладі подивимося, як краще може стати Java. Ось скільки коду нам довелося б написати, щоб створювати та порівнювати наш класEmployee
:
package com.theboreddev.java14;
import java.util.Objects;
public class Employee {
private final String firstName;
private final String surname;
private final int age;
private final Address address;
private final double salary;
public Employee(String firstName, String surname, int age, Address address, double salary) {
this.firstName = firstName;
this.surname = surname;
this.age = age;
this.address = address;
this.salary = salary;
}
public String getFirstName() {
return firstName;
}
public String getSurname() {
return surname;
}
public int getAge() {
return age;
}
public Address getAddress() {
return address;
}
public double getSalary() {
return salary;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
return age == employee.age &&
Double.compare(employee.salary, salary) == 0 &&
Objects.equals(firstName, employee.firstName) &&
Objects.equals(surname, employee.surname) &&
Objects.equals(address, employee.address);
}
@Override
public int hashCode() {
return Objects.hash(firstName, surname, age, address, salary);
}
@Override
public String toString() {
return "Employee{" +
"firstName='" + firstName + '\'' +
", surname='" + surname + '\'' +
", age=" + age +
", address=" + address +
", salary=" + salary +
'}';
}
}
А також об'єкт Address
, який він містить:
import java.util.Objects;
public class Address {
private final String firstLine;
private final String secondLine;
private final String postCode;
public Address(String firstLine, String secondLine, String postCode) {
this.firstLine = firstLine;
this.secondLine = secondLine;
this.postCode = postCode;
}
public String getFirstLine() {
return firstLine;
}
public String getSecondLine() {
return secondLine;
}
public String getPostCode() {
return postCode;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Address address = (Address) o;
return Objects.equals(firstLine, address.firstLine) &&
Objects.equals(secondLine, address.secondLine) &&
Objects.equals(postCode, address.postCode);
}
@Override
public int hashCode() {
return Objects.hash(firstLine, secondLine, postCode);
}
@Override
public String toString() {
return "Address{" +
"firstLine='" + firstLine + '\'' +
", secondLine='" + secondLine + '\'' +
", postCode='" + postCode + '\'' +
'}';
}
}
Напевно, тут занадто багато коду для чогось такого простого, чи не так? Давайте тепер подивимося, як це буде виглядати з новими записами Java:
public record EmployeeRecord(String firstName, String surname, int age, AddressRecord address, double salary) {
}
І ще не забудемо клас Address:
public record AddressRecord(String firstLine, String secondLine, String postCode) {
}
Це те саме, що ми написали раніше з такою великою кількістю коду. Погодьтеся: це чудово. І кількість коду, яку ми збираємось заощадити, і простота написання! Давайте подивимося, в чому відмінності нового оператора switch
.
Покращений операторswitch
Новий оператор switch
Java вирішить частину старих проблем, включаючи деякі помилки і дублювання коду. З новим оператором switch
цю проблему буде вирішено. Щоб пояснити це на прикладі, ми збираємося створити перелік DayOfTheWeek
Java:
public enum DayOfTheWeek {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY
}
Після цього наш switch
повідомить, яка позиція на тижні відповідає цьому дню. Давайте спочатку побачимо, як ми можемо зробити це в даний час, використовуючи Java 11.
final DayOfTheWeek dayOfTheWeek = DayOfTheWeek.THURSDAY;
int position = 0;
switch (dayOfTheWeek) {
case MONDAY:
position = 1;
break;
case TUESDAY:
position = 2;
break;
case WEDNESDAY:
position = 3;
break;
case THURSDAY:
position = 4;
break;
case FRIDAY:
position = 5;
break;
case SATURDAY:
position = 6;
break;
case SUNDAY:
position = 7;
break;
}
System.out.println("Day " + dayOfTheWeek + " is in position " + position + " of the week");
З поточним оператором switch
нам потрібно буде використовувати змінну, і якщо ми пропустимо один із днів тижня, наш код відмінно компілюватиметься. Це одна з проблем операторів switch
: вони занадто схильні до помилок. То як же Java 14 покращує ситуацію? Давайте подивимося:
final DayOfTheWeek dayOfTheWeek = DayOfTheWeek.THURSDAY;
int position = switch (dayOfTheWeek) {
case MONDAY -> 1;
case TUESDAY -> 2;
case WEDNESDAY -> 3;
case THURSDAY -> 4;
case FRIDAY -> 5;
case SATURDAY -> 6;
case SUNDAY -> 7;
};
System.out.println("Day " + dayOfTheWeek + " is in position " + position + " of the week");
Як бачите, нові оператори switch
можуть використовуватися як вираз, а не лише оператор. Результат більш лаконічний та виразний. Цього було б достатньо, щоб переконати багатьох із нас використовувати їх, але одне з основних покращень полягає в тому, що тепер оператори switch
не компілюватимуться, якщо ми не охопимо всі випадки в нашому switch
. Він покаже нам ось таку помилку, наприклад:
Error:(9, 24) java: the switch expression does not cover all possible input values
Відтепер у наших операторах switch
пропустити регістр буде неможливо. Це дуже схоже на оператори when
Kotlin, про які ви можете прочитати в документації . Погляньмо також на нові текстові блоки.
Текстові блоки
Ви коли-небудь скаржабося на те, як важко привласнити великий двійковий об'єкт JSON змінної Java? У Java є багаторядкові послідовності, які ви можете описати, уклавши їх у потрійні лапки. Коли ця функція буде офіційно випущена, стане набагато простіше описувати довгі послідовності кілька рядків. Давайте подивимося на різницю між двома режимами. Якщо ми хочемо використати відформатований JSON у змінній, виходить погано:final String text = "{\"widget\": {\n" +
" \"debug\": \"on\",\n" +
" \"window\": {\n" +
" \"title\": \"Sample Konfabulator Widget\",\n" +
" \"name\": \"main_window\",\n" +
" \"width\": 500,\n" +
" \"height\": 500\n" +
" },\n" +
" \"image\": { \n" +
" \"src\": \"Images/Sun.png\",\n" +
" \"name\": \"sun1\",\n" +
" \"hOffset\": 250,\n" +
" \"vOffset\": 250,\n" +
" \"alignment\": \"center\"\n" +
" },\n" +
" \"text\": {\n" +
" \"data\": \"Click Here\",\n" +
" \"size\": 36,\n" +
" \"style\": \"bold\",\n" +
" \"name\": \"text1\",\n" +
" \"hOffset\": 250,\n" +
" \"vOffset\": 100,\n" +
" \"alignment\": \"center\",\n" +
" \"onMouseUp\": \"sun1.opacity = (sun1.opacity / 100) * 90;\"\n" +
" }\n" +
"}} ";
З іншого боку, коли випустять нові текстові блоки, все стане набагато простіше:
final String multiLineText = """
{"widget": {
"debug": "on",
"window": {
"title": "Sample Konfabulator Widget",
"name": "main_window",
"width": 500,
"height": 500
},
"image": {\s
"src": "Images/Sun.png",
"name": "sun1",
"hOffset": 250,
"vOffset": 250,
"alignment": "center"
},
"text": {
"data": "Click Here",
"size": 36,
"style": "bold",
"name": "text1",
"hOffset": 250,
"vOffset": 100,
"alignment": "center",
"onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
}
}}
""";
Це явно виглядає краще. Все це вже підтримується Kotlin, як ви можете побачити в визначеннях його типів . Отже, ми побачабо, що Java «успадковує» багато вирішення власних проблем від одного зі своїх конкурентів: Kotlin. Ми не знаємо, чи вчасно відреагував Oracle на боротьбу зі зростанням популярності Kotlin чи, можливо, це сталося надто пізно. Особисто я вважаю, що Java робить правильні кроки вперед, навіть якщо ці зміни були ініційовані її конкурентами і можуть статися з деяким запізненням.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ