Почему 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
}

Но, судя по всему, в ближайший год это не попадет в джаву. Остается только надеяться, что фичу не придется ждать 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?

Похожие статьи:
У випуску: Django 2.0 без підтримки Python 2.7, PyTorch виходить в open-source, нові версії PonyORM та Matplotlib. Новини: Django 2.0 не буде підтримувати Python 2.7....
В мире много информации. Без графиков и других методов визуализации она просто не влезла бы в наши головы. Визуализация...
Цель данной статьи — уменьшить объем заблуждений и синхронизировать понимание основных принципов REST с сообществом....
Андрій Сердега — киянин, але вже майже чотири роки живе в Південній Кореї. Він закінчив магістратуру в одному...
Співзасновник Petcube Ярослав Ажнюк покидає посаду CEO, і переходить на посаду президента компанії. Новою CEO стала...
Яндекс.Метрика