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

Похожие статьи:
Южнокорейская компания LG Electronics объявила о том, что её новые смартфоны K-серии, оснащенные передовыми технологиями камеры и удобными...
[Об авторе: Николай Лотоцкий — более 15 лет занимается разработкой программного обеспечения. Знаком со всеми этапами работы...
За окном карантин, и многие сейчас пытаются придумать решение для помощи в борьбе с COVID-19. Мы в VITEch Lab Healthcare также работаем...
Volunteering abroad is an excellent idea for spreading your wings, whilst helping others less fortunate than you in the process. There are so many opportunities for volunteering abroad in nowadays. Sure, everyone likes going...
Всем привет, меня зовут Саша Емельянов, я Chief Product Officer в лондонском biotech-стартапе Bioniq (ex Badoo, ex MacPaw). В этом выпуске: история...
Яндекс.Метрика