Чому Java все ще не торт. Yet

Всім привіт. Місяць тому вийшла Java 11. Все круто. 6-місячний реліз працює. Платформа справді почала швидко розвиватися та обростати новими фічами. Ось, наприклад, повний список з 90 фіч, які з'явилися в одинадцатке. В основному це зміни на рівні JVM, але, по суті, це фундамент для майбутніх булочок.

У цьому пості я б хотів показати, чого ще дуже не вистачає пересічному Java-розробнику при щоденній розробці. Це, швидше, просто думки в слух про те, що хотілося б побачити в найближчих релізах, так як особисто я з цими конструкціями працюю досить часто. Поїхали.

Pattern matching

Мабуть, єдина конструкція з усього списку, яку я використовую майже кожен день:

if (obj instanceof Device) {
 Device device = (Device) obj;
...
}

Для нас, як розробників, цілком очевидно, що якщо ми зробили перевірку на тип змінної і вона пройшла, то ми цілком можемо оперувати змінної як об'єктом цього типу. Зараз же ми постійно повинні призводити змінну до потрібного типу явно. Вже навіть з'явився JEP305 для цієї задачі, який пропонує наступний вихід:

if (x matches Device device) {
 // can use device here
}

Але, судячи з усього, в найближчий рік це не потрапить в java. Залишається тільки сподіватися, що фічу не доведеться чекати 10 років.

switch for class

Синтаксис не дуже частий, але іноді просто дратує, що не можна зробити простий:

switch (obj.getClass()) {
 case Integer.class:
...
 case Long.class:
...
}

Особисто мені не зрозуміло, чому така проста, здавалося б, операція все ще не підтримується джавою нативно. Звичайно, цю проблему завжди можна обійти поліморфізмом чи пачкою if else або зробити class.getSimpleName() і світч по рядку, але це не так зручно. Так і по продуктивності явно не кращий варіант.

List<Integer> to int[]

Кожному розробнику відомо відчуття, коли він фокусується, входить у потік і починає ефективно ковбасити. І ось все йде класно, поки не потрібно зробити перетворення List<Integer> int[] або навпаки. Не можна просто так взяти і перетворити лист цілих чисел в масив примітивів. Зараз, щоб це зробити, потрібно або писати цикл перетворення:

int[] integerListToInt(List<Integer> integers) {
 int[] result = new int[integers.size()];
 for (int i = 0; i < result.length; i++) {
 result[i] = integers.get(i);
}
 return result;
}

Ну або через стріми:

int[] array = list.stream().mapToInt(i->i).toArray();

Обидва варіанти, очевидно, не найоптимальніші і зручні. Та й питання З , якому вже 10 років з сотнями голосів і сотнями тисяч переглядів як би натякає нам про актуальність. З перетворенням у зворотний бік — така ж ситуація.

Так, можна обійтися без примітивів і конструкція буде виглядати краще, але все ще не дуже:

list.toArray(new Integer[0])

new ArrayList(array)

Якщо відсутність перетворення List<Integer> -> int[] ще якось можна пояснити різними сутностями int і Integer, то відсутність конструктора з масивом для ArrayList взагалі не вкладається в голові. І чому за 20 років існування мови потрібно використовувати:

new ArrayList<>(Arrays.asList(array))

замість:

new ArrayList<>(array)

для мутабельного листа, досі не розумію. Так, легасі, всі справи, але мова має розвиватися і ставати зручним. Черговий питання З з мільйоном переглядів.

ConcurrentSet

Так, його досі немає у джаві, і судячи з усього ніколи і не буде. На щастя, починаючи з 8-ї джави, є статичний метод для його створення:

ConcurrentHashMap.newKeySet()

Але, по-перше, цей метод потрібно знати, по-друге, знову ж питання зручності, ну і по-третє, це не ConcurrentSet, а просто Set. А сам клас — якийсь KeySetView. Майже в будь-якому великому опенсорс-проект, який я бачив, був свій ConcurrentSet.

Path API

Як тільки з'явилося нове Path API, я відразу на нього перейшов. І от, через 7 років, до цих пір кожен раз, коли мені потрібно використовувати API — страждаю від цього. Ви не можете зробити new Path(), так як це інтерфейс. А статичних фабричних методів у класі Paths цілих 2. І тому часто код з Path виглядає так:

Paths.get(dataDir.toString(), folder);

замість:

Paths.get(dataDir, folder);

Це, звичайно, не так критично, так як у Path є метод resolve(), але в силу його специфіки не завжди підходить.

Висновок

Так, джава все ще далека від досконалості. Але останні релізи дають надію, що в найближчі кілька років це зміниться в кращу сторону і мова отримає нове життя.

А що вам не подобається в сьогоднішній Java?

Опубліковано: 31/10/18 @ 11:00
Розділ Різне

Рекомендуємо:

DOU Hobby: Мотоподорожі — незамінний інструмент для звільнення мозку від зайвого
Скільки можна підняти на пуш підписки? І потім зрости на 50% ;)
Здрастуй, прогер, Новий рік! Микроколонка про неминучих корпоративах з рекомендаціями
Як святкують Хеллоуїн в Америці (30 фото)
Країна стартапів та інтровертних людей. Чому я обрав для життя Естонію