microJUG – Telegram
microJUG
982 subscribers
155 photos
1 video
2 files
237 links
Мысли о Java.
Основной канал: @miniJUG
Буст: https://news.1rj.ru/str/microJUG?boost
Чат: https://news.1rj.ru/str/micro_JUG
Таблица JEP'ов: https://minijug.org/jeps.html
Download Telegram
У шарпистов бомбит, что в Java паттерн-матчинг сделали лучше и гибче, чем в C#.
Например, возможность писать case String s && s.isBlank() — по-моему, это очень круто. Такой и должен быть паттерн-матчинг.
💉 Вы привились от COVID-19?
Final Results
34%
Да, обе дозы
13%
Первую дозу только
53%
Нет
Скомпилируется код или нет?
Final Results
72%
Скомпилируется
28%
Не скомпилируется
Какой способ предпочитаете?
#юмор
Мой топ фишек, ради которых хочется перейти на Java 16 (не язык, только JVM и API). То есть то, что появилось в Java 12-16:

Stream.toList()
Collectors.teeing()
String.formatted()
Аннотация java.io.Serial
Lookup.defineHiddenClass() (но не уверен, что смогу найти реальное применение)
JEP 341: Default CDS Archives (ну типа, всё быстрее будет стартовать)
JEP 346: Promptly Return Unused Committed Memory from G1 (приложение будет кушать меньше памяти)
JEP 358: Helpful NullPointerExceptions
Field layout computation overhaul (более компактные объекты). Ну и вообще подобного рода мелкие оптимизации, которые в целом делают JVM чуть-чуть быстрее.

А ради чего вы хотите перейти с Java 11 на более новую версию?
Тут в соседнем треде бурление по поводу логирования в Java. А какие библиотеки используются у вас для логирования?
Final Results
3%
java.util.logging
5%
Log4J (первая, древняя версия)
27%
Log4J 2
75%
SLF4J / Logback
1%
Apache Commons Logging
0%
tinylog
0%
System.Logger (JEP 264, Java 9+)
7%
Простой println
3%
Другое (напишу в комментариях)
В общем, что и требовалось доказать. Никита наехал на джавистов, что у нас чуть ли не каждый день создаётся по новой библиотеке логирования. А в реальности у нас по факту всего лишь две библиотеки, которыми пользуется подавляющее большинство: SLF4J и Log4J 2. Остальные библиотеки либо уже ископаемые и давно мертвы и забыты (Commons Logging, Log4J 1, JUL), либо слишком маргинальные (tinylog). Так что картина во все не настолько плохая, как это может показаться по началу.

Кстати, я уже далеко не первый раз слышу набросы по поводу логирования Java со стороны всяких людей. "Да зачем у вас так всё сложно", "Зачем вы переизобретаете каждый раз то же самое" — постоянно я вижу то в Твиттере, то где-то ещё. А ответ заключается в том, что у нас: а) несложно и б) немного. Библиотеки просто отделяют интерфейс от реализации. В чём здесь сложность? И никакой горы библиотек нет. В опросе я вспомнил лишь 6 библиотек. Это за всё время существования Джавы (26 лет!).
Всё-таки обратная совместимость в Java это сила! Вот так работаешь с проектом, а там зависимость, скомпилированная под Java 1.2. Джава Один Два, 1998 год! И ничего, всё работает, как часы.
Quiz Time! 👇
Такой код точно компилируется в Java 16, потому что стали разрешены статические декларации во внутренних классах. А скомпилируется ли в Java 15?
Final Results
29%
Не скомпилируется. Ошибка в обеих константах X и Y.
35%
Не скомпилируется. Ошибка только в константе Y. С X всё ОК.
36%
Скомпилируется.
Кто-нибудь может объяснить, почему в Идее отсутствуют кнопки разворачивания окон на весь экран? Неужели никого это не напрягает? 🤔
#IntelliJIDEA
Что объединяет все эти примеры кода?
Универсальные дженерики уже попали в репозиторий Valhalla. И там стоит релиз Java 18! Естественно, preview. Значит по логике мы сможем писать List<int> в Java 20. Поскорей бы.
#Java18 #Java20
Где-то с год назад я делал разбор поста из одного популярного Telegram-канала по Java, где объяснил, почему автор неправ. Решил вот опять заглянуть туда. Ничего не изменилось: автор (точнее авторка) продолжает сбивать с толку своих читателей и вдалбливать в голову совершенно вредные и, в данном случае, неправильные вещи. А количество подписчиков с того момента увеличилось на две тысячи, так что стало всё только хуже.

Перед началом чтения моего разбора поста можете прочитать оригинальный пост, хотя это необязательно (и может быть даже опасно 🤡).

Итак, автор начинает с двух тестов. В первом приводится кусок кода и спрашивается, сколько элементов он выведет:

Map<Integer, Integer> map = new ConcurrentHashMap<>();
map.put(20, 0);
map.put(30, 0);

for (Integer key : map.keySet()) {
System.out.println(key);
map.put(40, 0);
}

Во втором тесте цикл for заменён на метод forEach и задаётся тот же самый вопрос:

map.keySet().forEach(key -> {
System.out.println(key);
map.put(40, 0);
});

Без чтения дальнейшего поста уже стоило бы напрячься. Во-первых, модифицировать мапу во время итерации в этом же самом потоке уже немного странно. Ну хорошо, бывает, что иногда приводится не очень практичный пример чисто ради педагогических целей. Есть ли какая-то педагогическая ценность в данном вопросе? Я бы сказал, да, если бы среди ответов был вариант: «чувак, поведение не определено и может произойти что угодно». Ведь для ConcurrentHashMap гарантируется только отсутствие вылета ConcurrentModificationException, а будет ли там подхватываться или не подхватываться элемент – это уже деталь реализации. Среди ответов же есть только два варианта «выведется 2 элемента» и «выведется 3 элемента». На самом деле контракт нам про 2 или 3 сказать ничего не может. Гипотетически может произойти любая комбинация:

1. for выведет 2 элемента, forEach выведет 2
2. for выведет 2 элемента, forEach выведет 3
3. for выведет 3 элемента, forEach выведет 2
4. for выведет 3 элемента, forEach выведет 3

Комбинации 2 и 4, например, можно вполне себе легко воспроизвести: на Java 11.0.12 for выведет 20, 30, а forEach 20, 40, 30. Но если взять другие числа, например, 10, 20, 30 вместо 20, 30, 40, то оба выведут одно и то же: 20, 10, 30.

Таким образом, автор, пытаясь объяснить различия между устройством for и forEach, выбрала крайне неудачный (и некорректный пример).

Теперь давайте перейдём к самому посту. Пойдём прямо по тексту:

for использует для обхода итератор, а forEach - траверс.

Не очень понятно, что автор хочет нам этим сказать. И for и forEach оба делают обход. Правильнее было бы сказать: for использует pull-based обход, а forEach – push-based. Отсюда и возможные различия в поведении.

Сразу скажу: всё это имеет смысл только для обхода многопоточных структур данных

Не только. Различия между for и forEach порой существенны и для однопоточных структур. Например, те же стримы могут в некоторых случаях вести себя немного по-разному, если использовать iterator вместо forEach. Кроме того, forEach работает, как правило, быстрее, так как push-based реализация чаще намного проще и эффективнее. Посмотрите, например, как просто реализован ArrayList.forEach и насколько сложнее ArrayList.Itr.

Почему нельзя использовать траверс по умолчанию?
— Итератор проще и работает быстрее, а условия для пропуска элемента при обходе встречаются редко.

Не проще и не быстрее (см. выше). Итератор может быть либо медленнее и сложнее, либо как минимум одинаков по скорости и сложности с forEach (ну если говорить о разумных реализациях, можно конечно специально сделать forEach медленнее).
Итого: при выводе элементов ConcurrentHashMap через for и forEach используются разные алгоритмы обхода, поэтому результат вывода тоже разный.

Как раз-таки для ConcurrentHashMap используется один и тот же алгоритм обхода. Это тот случай, когда for и forEach совпадают. forEach использует вложенный класс Traverser, а for – класс BaseIterator, который наследуется от Traverser. А различия в поведении (for выводит 20, 30, а forEach 20, 40, 30) наблюдаются из-за того, что Traverser более ленив, чем BaseIterator. BaseIterator следующий элемент вычисляет раньше, чем он реально нужен.

Для однопоточных коллекций между for и forEach нет никакой разницы, в обоих случаях используется итератор.
Нет, разница между ними есть. И нет, в обоих случаях не используется итератор. Да, реализация forEach в Iterable по умолчанию делегирует обход к итератору. Но почти все коллекции эту реализацию переопределяют на более эффективную.