Почему Java все еще не торт. Yet
Всем привет. Месяц назад вышла Java 11. Все круто.
В этом посте я бы хотел показать, чего еще очень не хватает рядовому 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
Да, его до сих пор нету в джаве, и судя по всему никогда и не будет. К счастью, начиная с
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?