Недавно состоялся релиз-кандидат Java 10, и на Хабре вышла статья, где перечислены JEP'ы, вошедшие в новый релиз. Однако не все изменения в Java получают свой JEP. В частности, небольшие дополнения стандартной библиотеки практически всегда происходят без JEP'ов. При этом частенько практической пользы от них даже больше, чем от более серьёзных изменений, которые удостоились JEP'а. Давайте посмотрим, что добавилось в стандартную библиотеку Java 10.
Программист
Статический анализ и property-based тестирование: вместе мы сила
Как известно, баги есть во всех программах. Есть множество способов борьбы с ними: юнит-тесты, ревью, статический анализ, динамический анализ, дымовое тестирование и так далее. Иногда для искоренения определённого бага полезно сочетать разные методики.
Я разрабатываю Java-инспекции в IntelliJ IDEA, которая большей частью написана на Java. В некотором смысле я нахожусь в привилегированном положении по сравнению с другими программистами: доработать статический анализатор IDE, чтобы находить новый класс ошибок — это моя прямая рабочая обязанность, которая при этом же позволяет найти и обезвредить баги в этой же самой IDE. Хочу поделиться одной такой историей успеха.
Пылесосим код IDEA Ultimate с помощью анализа потоков данных
- Разыменование ссылки может привести к
NullPointerException
- Условие всегда истинно или ложно
- Индекс массива всегда за пределами допустимых границ
- Приведение типа может привести к
ClassCastException
Используйте Stream API проще (или не используйте вообще)
С появлением Java 8 Stream API позволило программистам писать существенно короче то, что раньше занимало много строк кода. Однако оказалось, что многие даже с использованием Stream API пишут длиннее, чем надо. Причём это не только делает код длиннее и усложняет его понимание, но иногда приводит к существенному провалу производительности. Не всегда понятно, почему люди так пишут. Возможно, они прочитали только небольшой кусок документации, а про другие возможности не слышали. Или вообще документацию не читали, просто видели где-то пример и решили сделать похоже. Иногда это напоминает анекдот про «задача сведена к предыдущей».
В этой статье я собрал те примеры, с которыми столкнулся в практике. Надеюсь, после такого ликбеза код программистов станет чуточку красивее и быстрее. Большинство этих штук хорошая IDE поможет вам исправить, но IDE всё-таки не всесильна и голову не заменяет.
Что там с JEP-303 или изобретаем invokedynamic
Блогеры и авторы, пытающиеся быть на передовой, уже немало писали про проект Amber в Java 10. В этих статьях обязательно упоминается вывод типов локальных переменных, улучшения enum и лямбд, иногда пишут про pattern matching и data-классы. Но при этом незаслуженно обходится стороной JEP 303: Intrinsics for the LDC and INVOKEDYNAMIC Instructions. Возможно, потому что мало кто понимает, к чему это вообще. Хотя любопытно, что именно об этой фиче ребята из NIX_Solutions фантазировали на Хабре год назад.
Широко известно, что в виртуальной машине Java, начиная с версии 7, есть интересная инструкция invokedynamic (она же indy). Про неё многие слышали, однако мало кто знает, что она делает на самом деле. Кто-то знает, что она используется при компиляции лямбда-выражений и ссылок на методы в Java 8. Некоторые слышали, что через неё реализована конкатенация строк в Java 9. Но хотя это полезные применения indy, изначальная цель всё же немного другая: делать динамический вызов, при котором вы можете вызывать разный код в одном и том же месте. Эта возможность не используется ни в лямбдах, ни в конкатенации строк: там поведение всегда генерируется при первом вызове и остаётся постоянным до конца работы программы (всегда используется ConstantCallSite). Давайте посмотрим, что можно сделать ещё.
Статический анализ → уязвимость → профит
В статьях про PVS-Studio всё чаще говорят об уязвимостях и дефектах безопасности, которые можно найти с помощью статического анализа. Авторов этих статей критикуют (и я в том числе), что не каждая ошибка является дефектом безопасности. Возникает однако интересный вопрос, можно ли пройти весь путь от сообщения статического анализатора до эксплуатации найденной проблемы и получения какой-то выгоды. В моём случае выгода всё же осталась теоретической, но эксплуатировать ошибку удалось, не особо вникая в код проекта.
Начинается разработка OpenJDK 10
Сегодня Mark Reinhold объявил об открытии репозиториев mercurial для Java 10, и разработчики, имевшие статус committer и выше в проекте Java 9, получили возможность размещать багфиксы и мелкие улучшения, которые не предполагается вносить в Java 9. Всем разработчикам (например, мне) обновили статус на страничке переписи OpenJDK.
Крупные изменения вносить пока не рекомендуется во избежание конфликтов. Изменения в Java 9 ещё не завершены и некоторое время придётся их переносить в Java 10. При отсутствии конфликтов процедура будет автоматизирована, так что тем, кто продолжает вносить исправления в Java 9, скорее всего не придётся лишний раз беспокоиться.
Вызов методов через reflection
Все программисты на Java явно или неявно пользуются reflection для вызова методов. Даже если вы не делали этого сами, это за вас наверняка делают библиотеки или фреймворки, которые вы используете. Давайте посмотрим, как этот вызов устроен внутри и насколько это быстро. Будем глядеть в OpenJDK 8 с последними обновлениями.
Лямбды и анонимные классы: кто больше жрёт
По мотивам недавних обсуждений здесь захотелось более широко взглянуть на вопрос о том, кто больше кушает — новомодные хипстерские лямбды или старые проверенные анонимные классы. Давайте устроим словесную перепалку между ними и посмотрим, кто выиграет. Как с любым добротным холиваром, даже если не удастся выяснить победителя, можно узнать много нового для себя.
Супермедленный и супербыстрый бенчмарк
В недавней статье про производительность Java разгорелась дискуссия на тему измерения производительности. Глядя на неё, с грустью приходится сознавать, что многие люди до сих пор не понимают, насколько сложно правильно измерить время выполнения того или иного кода. Кроме того, люди вообще не привыкли, что один и тот же код в разных условиях может выполняться существенно разное время. К примеру, вот одно из мнений:
Если мне надо узнать, "какой язык быстрее для меня на моей задаче", то я прогоню самый примитивный бенчмарк в мире. Если разница будет существенной (скажем, на порядок) — то скорее всего и на пользовательской машине все будет примерно также.
К сожалению, самый примитивный бенчмарк в мире — это как правило неправильно написанный бенчмарк. И не следует надеяться, что неправильный бенчмарк измерит результат хотя бы с точностью до порядка. Он может измерить что-нибудь абсолютно другое, что будет совершенно отличаться от реальной производительности программы с аналогичным кодом. Давайте рассмотрим пример.
JIT-компилятор оптимизирует не круто, а очень круто
Недавно Лукас Эдер заинтересовался в своём блоге, способен ли JIT-компилятор Java оптимизировать такой код, чтобы убрать ненужный обход списка из одного элемента:
// ... а тут мы "знаем", что список содержит только одно значение
for (Object object : Collections.singletonList("abc")) {
doSomethingWith(object);
}
Вот мой ответ: JIT может даже больше. Мы будем говорить про HotSpot JVM 64 bit восьмой версии. Давайте рассмотрим вот такой простой метод, который считает суммарную длину строк из переданного списка:
static int testIterator(List<String> list) {
int sum = 0;
for (String s : list) {
sum += s.length();
}
return sum;
}
Статический анализатор HuntBugs: проверяем IntelliJ IDEA
Как многие помнят, некоторое время я развивал статический анализатор Java-байткода FindBugs. Однако проблем в FindBugs накопилось столько, что я решил, что будет проще написать новый анализатор байткода. Я не очень творчески назвал его HuntBugs. Разработка ведётся на GitHub. Он пока в ранней стадии разработки, иногда глючит и покрывает примерно 35% диагностик из FindBugs, но при этом добавляет свои интересные штуки. Попробовать можно на вашем Maven-проекте с помощью команды mvn one.util:huntbugs-maven-plugin:huntbugs
(отчёт пишется в target/huntbugs/report.html
). Альтернативно можно собрать вручную из гита и запустить приложение командной строки one.util.huntbugs.HuntBugs
, которому можно подавать на вход JAR-файлы или каталоги с .class-файлами.
Как-нибудь потом, когда проект несколько повзрослеет, я расскажу о нём более подробно. А в этой статье я покажу, чего интересного нашёл HuntBugs в IntelliJ IDEA Community Edition. Я скачал с официального сайта и поставил последнюю версию этой IDE, а затем натравил HuntBugs на файл lib/idea.jar
, в котором почти всё и лежит. Я люблю тестировать статический анализ на IDEA, потому что это IDE, в которой самой есть очень неплохой статический анализатор и разработчики им явно пользуются. Интересно посмотреть, что остаётся после него.
Как вы можете сделать Java лучше
Многие люди жалуются, что в Java чего-то не хватает, что-то глючит или медленно работает. Хорошая новость: у вас есть возможность не жаловаться, а своими силами сделать Java лучше. Java практически полностью открыта в виде проекта OpenJDK. У этого проекта есть свои особенности, но в целом вам ничего не мешает самим сообщать о проблемах, исправлять их и даже разрабатывать новую функциональность. В этой статье я немного расскажу, как это делать новичку.
Var и val в Java?
Следует ли добавить вывод типов локальных переменных в Java? Как раз сейчас команда разработчиков языка Java задалась этим вопросом.
Вывод типов локальных переменных
JEP-286 предлагает добавить вывод типов локальных переменных, используя новое псевдоключевое слово (интерпретируемое как «зарезервированное наименование типа»):
Явное указание типа локальных переменных зачастую не является необходимым. Разрешив разработчикам опускать его, мы хотим упростить разработку на Java, уменьшив необходимое количество формальностей, но при этом не жертвуя статической типизацией.
Stream API: универсальная промежуточная операция
- Будет ли она действительно промежуточной, то есть не будет трогать источник до выполнения терминальной операции?
- Будет ли она ленивой и вытаскивать из источника не больше данных, чем требуется?
- Сработает ли она на бесконечном стриме? Требует ли она ограниченный объём памяти?
- Будет ли она хорошо параллелиться?
Минусик по любому из этих пунктов заставляет серьёзно задуматься, добавлять ли такую операцию. Минусик по первому — это сразу нет. Например, у конкурентов в jOOλ есть операция shuffle(), которая выглядит как промежуточная, но на самом деле прямо сразу потребляет весь стрим в список, перемешивает его и создаёт новый стрим. Я такое не уважаю.
Минусики по остальными пунктам не означают сразу нет, потому что есть и стандартные операции, которые их нарушают. Второй пункт нарушает
flatMap()
, третий — sorted()
, четвёртый — всякие limit()
и takeWhile()
(в JDK-9). Но всё-таки я стараюсь этого избегать. Однако на днях я открыл для себя операцию, которая плохо параллелится и в зависимости от использования может не сработать на бесконечном стриме, но всё же слишком хороша. Через неё удаётся буквально в несколько строчек выразить как практически любую существующую промежуточную операцию, так и кучу несуществующих. Я назвал операцию headTail().Коллекции в Java: о чём многие забывают
Содержание:
- List.subList
- PriorityQueue
- EnumSet и EnumMap
- Set.add(E) и Set.remove(E) возвращают булево значение
- Map.put(K, V), Map.remove(K), List.set(idx, E), List.remove(idx) возвращают предыдущий элемент
- Map.keySet() и Map.values()
- Arrays.asList может быть ключом
- Collections.max
- LinkedList, Stack, Vector, Hashtable
Пишем свой Spliterator
Вычисление факториала или мощь Stream API
public static BigInteger streamedParallel(int n) {
if(n < 2) return BigInteger.valueOf(1);
return IntStream.rangeClosed(2, n).parallel().mapToObj(BigInteger::valueOf).reduce(BigInteger::multiply).get();
}
Прокачиваем Stream API, или нужно больше сахара
10 вещей, которых вы не знали о Java
Держу пари, что вы не знали как минимум половину из того, что я собираюсь вам рассказать. Давайте откроем для себя несколько удивительных фактов о внутренних особенностях Java.
Information
- Rating
- Does not participate
- Location
- Новосибирск, Новосибирская обл., Россия
- Registered
- Activity