Pascal4eg / Java

 Java | Фишки и трюки

Nashorn

public static void main(String[] args) throws ScriptException, NoSuchMethodException {
    ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
    Invocable invocable = (Invocable) engine;
    engine.eval("var StringBuilder = Java.type('java.lang.StringBuilder')");
    engine.eval("var sb = new StringBuilder();");
    engine.eval("function add(str) { sb.append(str); }");
    engine.eval("function toString() { return sb.toString(); }");

    invocable.invokeFunction("add", "Hello");
    invocable.invokeFunction("add", " scripting!");
    System.out.println(invocable.invokeFunction("toString"));
    // Hello scripting!
}

Nashorn — это движок JavaScript, разработанный на языке программирования Java первоначально Oracle, а затем сообществом OpenJDK. Nashorn был включен в JDK в версии Java 8 и до Java 14. С Java 15 его нужно подключать явно.

Читать дальше

Системы сборки в мире Java

🛠 Системы сборки в мире Java — это незаменимые инструменты, которые делают процесс разработки проще и эффективнее.

Что бы ваш код стал работающим приложением, его нужно собрать в файл который можно запустить. Это может быть .war или .jar файл.

Читать дальше

Weak Reference: Слабая связь с объектами

В мире Java, WeakReference - это мощный инструмент для управления памятью. Он позволяет создавать ссылки на объекты, которые могут быть автоматически удалены сборщиком мусора, если на них больше нет сильных ссылок (обычная ссылка на объект).

Чем это полезно? Это помогает избежать утечек памяти в приложениях, где объекты могут оставаться неиспользуемыми, но все еще иметь сильные ссылки.

Читать дальше

🚀🧵 Гармония в параллельном мире Java: Thread-Safe

В мире Java, параллельное выполнение потоков - это норма. Однако без должных мер предосторожности, оно может привести к состоянию гонки (race condition) и ошибкам. Вот почему важно понимать и применять концепцию Thread-Safe.

Thread-Safe означает, что ваш код или структуры данных могут безопасно использоваться из множества потоков, не вызывая нежелательных конфликтов. Как добиться Thread-Safety:

Читать дальше

Унарный оператор

boolean b = false;
System.out.println(b); // false
System.out.println(!b); // true

int i = -5;
System.out.println(i); // -5
System.out.println(-i); // 5
System.out.println(+i); // -5

int j = 5;
int k = 5;
System.out.println(++j + k++); // 11
System.out.println(j); // 6
System.out.println(k); // 6

Унарный оператор - это оператор, который принимает на вход один аргумент и возвращает некоторое значение.

К унарным операторам относятся: +, -, !
А так же, пре-унарный оператор и пост-унарный оператор.

Читать дальше

Varargs (Variable Arguments List)

public static void main(String[] args) {
    System.out.println(concat("one", 1, BigDecimal.ONE));
    // one,1,1
}

private static String concat(Object... args) {
    return Arrays.stream (args)
            .map (Object::toString)
            .collect(Collectors.joining(","));
}

Varargs (Variable Arguments List, изменяющийся список аргументов) — это способ создания методов, которые могут принимать произвольное количество аргументов одного типа (от нуля и более). Данная возможность появилась в JDK 5.

Запись вида Object... args и есть varargs.

Читать дальше

Бесконечные потоки

Stream<Integer> infiniteStream = Stream.iterate(0, i -> i + 2);
List<Integer> intList = infiniteStream
                        .limit(10)
                        .collect(Collectors.toList());
// 0, 2, 4, 6, 8, 10, 12, 14, 16, 18

Supplier<UUID> randomUUIDSupplier = UUID::randomUUID;
Stream<UUID> infiniteUUIDStream = Stream.generate(randomUUIDSupplier);
List<UUID> uuidList = infiniteUUIDStream
                        .skip(10) // пропустить первые 10
                        .limit(10)
                        .collect(Collectors.toList());

Интерфейс Stream имеет два статических метода для генерации бесконечных потоков: iterate() и generate().

Читать дальше

Stream

Все операции Stream делятся на промежуточные и терминальные и объединяются в потоковые конвейеры.

Потоковый конвейер состоит из источника (например, коллекции, массива, функции-генератора, канала ввода-вывода или генератора бесконечной последовательности) за которым следует ноль или более промежуточных операций и терминальной операции.

Промежуточные операции
📌 Промежуточные операции не выполняются до тех пор, пока не будет вызвана какая-либо терминальная операция.

Они составляют конвейер выполнения Stream. Промежуточную операцию можно добавить в конвейер Stream методами:
filter()
map()
flatMap()
distinct()
sorted()
peek()
limit()
skip()

Читать дальше

Защита от повторного запроса с помощью БД

Если вы разрабатываете Веб-приложение или REST-сервис, то рано или поздно столкнётесь с повторными запросами. Что имеется в виду? Объясню на примере Веб-страницы с кнопкой. По нажатию на кнопку, на бэкенд отправляется запрос. Запрос, соответственно, синхронный и пока серверная часть делает какую-то работу, браузер клиента показывает, что загружает страницу. Если это происходит продолжительное время, клиент может подумать, что его запрос завис и нажать кнопку ещё раз. Также повторное нажатие может произойти случайно.

Какая тут может произойти проблема? Если это, например, какой-то запрос данных, то в общем-то проблемы и нет, но если это действие, которое должно отработать только один раз, то тут могут быть весьма неприятные последствия. Для примера в интернет-магазине собрана корзина и создан заказ на оплату (статус REGISTERED), далее по нажатию кнопки "оплатить" с клиента списывают деньги и переводят заказ в статус оплачен (PAID). И если в этом процессе произойдёт двойной запрос, то с клиента могут списать деньги за заказ два раза.

Читать статью

Читать дальше

Комбинирование предикатов

List<String> fruits = List.of("apple", "orange", "pineapple", "grapefruit", "melon");
Predicate<String> isEqualsOrange = Predicate.isEqual("orange");
Predicate<String> isEqualsGrapefruit = Predicate.isEqual("grapefruit");
Predicate<String> isEqualsCitrus = isEqualsOrange.or(isEqualsGrapefruit);
Predicate<String> isNotEqualsCitrus = isEqualsCitrus.negate();

fruits.stream().filter(isEqualsOrange).forEach(System.out::println);
// orange

fruits.stream().filter(isEqualsCitrus).forEach(System.out::println);
// orange grapefruit

fruits.stream().filter(isNotEqualsCitrus).forEach(System.out::println);
// apple pineapple melon

🧩 Predicate - встроенный функциональный интерфейс, добавленный в Java 8 в пакет java.util.function.

Читать дальше