11 полезных фишек для Java

🔥 🚀 Важно для всех, кто работает с Java! 🔥
На JavaRocks ты найдешь уникальные туториалы, практические задачи и редкие книги, которых не найти в свободном доступе. Присоединяйся к нашему Telegram-каналу JavaRocks — стань частью профессионального сообщества!

В этой статье вы найдёте 11 трюков для Java: от записей (Records) и паттернов до дженериков, лямбда-выражений, jpackage и jshell.

Трюк №1: Компактные конструкторы записей (Records)

Обычно в record-классах используется конструктор, который принимает все компоненты в качестве аргументов. В таком конструкторе можно проверять входные данные перед их сохранением в полях.

Но есть способ сделать код короче. Компактный конструктор позволяет опустить список параметров — они автоматически передаются. Внутри конструктора можно проверять и изменять эти параметры, но нельзя напрямую присваивать значения полям, так как это делает компилятор.

public record Range(int start, int end) {

    public Range {
        if (end <= start) {
            throw new IllegalArgumentException();
        }
    }
}
Run Code

Трюк №2: Сериализация записей (Records)

В Java можно сериализовать любой объект — иногда с применением магии. Но с Records всё проще!

Наличие конструктора и геттеров позволяет сериализовать их без лишних ухищрений. Это значит, что создать надёжный сериализуемый Record — проще простого.

Трюк №3: jpackage — не только для модулей

jpackage — это инструмент командной строки, который может взять Java-приложение и превратить его в полностью автономный пакет, включающий всё: код, зависимости и даже Java-рантайм. Для формирования этого рантайма jpackage использует jlink, который можно настроить прямо в jpackage, либо передать ему уже созданный runtime-образ.

Кроме того, jpackage позволяет задать метаданные приложения (иконку, лицензию), параметры установки, конфигурацию лаунчеров, а также передать опции для JVM и самого приложения.

На выходе jpackage генерирует установочные пакеты в нативных форматах — deb/rpm для Linux, exe/msi для Windows.

И самое интересное: jpackage работает не только с модульными приложениями, но и с обычными!

# generate an application image for a modular application:
jpackage --type app-image -n name -p modulePath -m moduleName/className
# for a nonmodular application:
jpackage --type app-image -i inputDir -n name --main-class className --main-jar myJar.jar

Трюк №4: Кросс-платформенные runtime-образы

С помощью jlink можно создавать runtime-образы для разных операционных систем.

Допустим, билд-сервер работает на Linux, но нужен runtime-образ для Windows. Нужно просто скачать Windows JDK той же версии, добавить его jmods в module-path jlink-а на Linux — и готово.

# download JDK for Windows and unpack into jdk-win
# create the image with the jlink binary from the system's JDK
# (in this example, Linux)
$ jlink
  --module-path jdk-win/jmods:mods
  --add-modules com.example.main
  --output app-image

Трюк №5: Метки для break и continue

Известно, что break позволяет выйти из внутреннего цикла. Но знали ли вы, что можно присвоить break метку, чтобы выйти сразу из внешнего цикла?

Тот же трюк работает с continue: без метки он перескакивает остаток текущей итерации внутреннего цикла, но с меткой — делает это для внешнего.

Однако то, что этот трюк работает, не значит, что его стоит применять повсюду. Используйте это осторожно, чтобы код не превратился в лабиринт.

class ContinueWithLabelDemo {
    public static void main(String[] args) {

        String searchMe = "Look for a substring in me";
        String substring = "sub";
        boolean foundIt = false;

        int max = searchMe.length() -
                  substring.length();

    test:
        for (int i = 0; i <= max; i++) {
            int n = substring.length();
            int j = i;
            int k = 0;
            while (n-- != 0) {
                if (searchMe.charAt(j++) != substring.charAt(k++)) {
                    continue test;
                }
            }
            foundIt = true;
                break test;
        }
        System.out.println(foundIt ? "Found it" : "Didn't find it");
    }
}
Run Code

Трюк №6: Используем переменную из pattern matching сразу

Можно сразу использовать переменную, которую объявляет pattern matching, в том же булевом выражении.

Например, object instanceof String s не просто проверяет тип, но и создаёт переменную s, которую можно тут же использовать, например, для проверки && !s.isEmpty().

Работает в if-выражениях с Java 16 и в switch (пока в режиме preview) с Java 17.

Object object = // ...
if (object instanceof String s && !s.isEmpty())
    System.out.println("Non-empty string");
else
    System.out.println("No string or empty.");
Run Code

Трюк №7: Wildcard’ы в дженериках и подтипы

Вы знаете, как работают дженерики, и то, что List<Integer> — это не List<Number>. (См. рис. 1)

Наследование в дженериках
Рисунок 1. Наследование в дженериках

Но знали ли вы, что, используя wildcard’ы, можно построить иерархию типов? (См. рис. 2)

Например, List<? extends Integer> действительно является подтипом List<? extends Number>. И наоборот: List<? super Number> является суперклассом List<? super Integer>.

Наследование в дженериках с wildcard'ами
Рисунок 2. Наследование в дженериках с wildcard’ами

Трюк №8: Создание и объединение предикатов

Вам известно, как создавать предикаты с помощью лямбд, но интерфейс предоставляет кучу других методов для их создания и комбинирования. Например, для работы с булевыми выражениями можно использовать методы and, or и negate.

Статический метод not поможет инвертировать ссылку на метод. А если передать объект в isEqual, он создаст предикат для проверки равенства экземпляров с этим объектом.

Predicate<String> isEqualToDuke = Predicate.isEqual("Duke");
Predicate<Collection<String>> isEmpty = Collection::isEmpty;
Predicate<Collection<String>> isNotEmpty = Predicate.not(isEmpty);
Run Code

Трюк №9: Создание и комбинирование компараторов

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

Для сравнения значений типа long, double, float и других используйте ссылку на метод их статического метода compare.

Comparator<Integer> comparator = Integer::compare;

Если тебе нужно сравнить объекты по одному из их атрибутов, передайте функцию, которая его извлекает, в Comparator.comparing. Чтобы сначала отсортировать по одному атрибуту, а потом по другому, создайте два компаратора и комбинируйте их с помощью thenComparing.

Comparator<User> byFirstName = Comparator.comparing(User::getFirstName);
Comparator<User> byLastName = Comparator.comparing(User::getLastName);
Comparator<User> byName = byFirstName.thenComparing(byLastName);
Run Code

Если нужен компаратор, который использует метод compareTo объекта, реализующего Comparable, воспользуйтесь статическим методом naturalOrder. Если нужно инвертировать порядок, просто вызовите reversed.

А что насчёт null? Не переживайте: передайте компаратор в методы nullsFirst или nullsLast, чтобы создать компаратор, и он будет правильно обрабатывать null.

Comparator<Integer> natural = Comparator.naturalOrder();
Comparator<Integer> naturalNullsLast = Comparator.nullsLast(natural);
Run Code

Трюк №10: Запуск исходных файлов как скриптов

Вам известно, что с помощью команды java можно запустить исходный файл без предварительной компиляции. Но знаете ли вы, что это можно использовать для написания полноценного скрипта на Java всего в три простых шага?

Первое: добавьте строку shebang в исходный файл, указав путь к исполняемому файлу java, а затем --source и версию Java, для которой написан код.

#!/path/to/your/bin/java --source 16

public class HelloJava {

    public static void main(String[] args) {
        System.out.println("Hello " + args[0]);
    }
}
Run Code

Второе: переименуйте файл, чтобы он не заканчивался на .java. Так будет удобнее для командной строки.

Третье: сделайте файл исполнимым через chmod +x. Вот и всё: скрипты на Java готовы!

Трюк №11: Запуск jshell с импортами

Вы знаете, как запустить jshell для быстрых экспериментов, но не обязательно импортировать всё вручную. Просто запустите jshell с опцией JAVASE, и все пакеты Java SE будут автоматически импортированы, так что можно будет сразу начинать работу.

jshell JAVASE

Перевод статьи «11 great Java tricks from dev.java».

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Прокрутить вверх