Перейти к основному содержимому

Новые функции в Java 12

· 7 мин. чтения

1. Введение

В этом руководстве у нас будет краткий общий обзор некоторых новых функций, появившихся в Java 12. Полный список всех новых функций доступен в официальной документации .

2. Изменения и особенности языка

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

2.1. Новые методы класса String

Java 12 поставляется с двумя новыми методами в классе String .

Первый — indent регулирует отступ каждой строки на основе целочисленного параметра. Если параметр больше нуля, в начале каждой строки будут вставлены новые пробелы. С другой стороны, если параметр меньше нуля, он удаляет пробелы из начала каждой строки. Если заданная строка не содержит достаточного количества пробелов, все начальные пробелы удаляются.

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

String text = "Hello ForEach!\nThis is Java 12 article.";

text = text.indent(4);
System.out.println(text);

text = text.indent(-10);
System.out.println(text);

Вывод выглядит следующим образом:

Hello ForEach!
This is Java 12 article.

Hello ForEach!
This is Java 12 article.

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

Второй новый метод — преобразование . Он принимает функцию с одним аргументом в качестве параметра, который будет применяться к строке.

В качестве примера, давайте воспользуемся методом преобразования для возврата строки:

@Test
public void givenString_thenRevertValue() {
String text = "ForEach";
String transformed = text.transform(value ->
new StringBuilder(value).reverse().toString()
);

assertEquals("gnudleaB", transformed);
}

2.2. Файл:: Метод несоответствия

В Java 12 появился новый метод несоответствия в служебном классе nio.file.Files :

public static long mismatch(Path path, Path path2) throws IOException

Метод используется для сравнения двух файлов и поиска позиции первого несовпадающего байта в их содержимом.

Возвращаемое значение будет находиться в диапазоне от 0L до размера меньшего файла в байтах или -1L, если файлы идентичны.

Теперь давайте рассмотрим два примера. В первом мы создадим два одинаковых файла и попытаемся найти несоответствие. Возвращаемое значение должно быть -1L:

@Test
public void givenIdenticalFiles_thenShouldNotFindMismatch() {
Path filePath1 = Files.createTempFile("file1", ".txt");
Path filePath2 = Files.createTempFile("file2", ".txt");
Files.writeString(filePath1, "Java 12 Article");
Files.writeString(filePath2, "Java 12 Article");

long mismatch = Files.mismatch(filePath1, filePath2);
assertEquals(-1, mismatch);
}

Во втором примере мы создадим два файла с содержимым «Java 12 Article» и «Java 12 Tutorial». Метод несоответствия должен возвращать 8L, так как это первый другой байт:

@Test
public void givenDifferentFiles_thenShouldFindMismatch() {
Path filePath3 = Files.createTempFile("file3", ".txt");
Path filePath4 = Files.createTempFile("file4", ".txt");
Files.writeString(filePath3, "Java 12 Article");
Files.writeString(filePath4, "Java 12 Tutorial");

long mismatch = Files.mismatch(filePath3, filePath4);
assertEquals(8, mismatch);
}

2.3. Коллектор тройников

В Java 12 в качестве дополнения к классу Collectors был введен новый сборщик teeing : ``

Collector<T, ?, R> teeing(Collector<? super T, ?, R1> downstream1,
Collector<? super T, ?, R2> downstream2, BiFunction<? super R1, ? super R2, R> merger)

Он представляет собой комбинацию двух коллекторов, расположенных ниже по течению. Каждый элемент обрабатывается обоими нижестоящими коллекторами. Затем их результаты передаются функции слияния и преобразуются в окончательный результат.

Пример использования коллектора teeing — это подсчет среднего значения из набора чисел. Первый параметр коллектора будет суммировать значения, а второй даст нам количество всех чисел. Функция слияния возьмет эти результаты и подсчитает среднее значение:

@Test
public void givenSetOfNumbers_thenCalculateAverage() {
double mean = Stream.of(1, 2, 3, 4, 5)
.collect(Collectors.teeing(Collectors.summingDouble(i -> i),
Collectors.counting(), (sum, count) -> sum / count));
assertEquals(3.0, mean);
}

2.4. Компактное форматирование чисел

Java 12 поставляется с новым средством форматирования чиселCompactNumberFormat . Он предназначен для представления числа в более короткой форме на основе шаблонов, предоставляемых данной локалью.

Мы можем получить его экземпляр с помощью метода getCompactNumberInstance в классе NumberFormat :

public static NumberFormat getCompactNumberInstance(Locale locale, NumberFormat.Style formatStyle)

Как упоминалось ранее, параметр локали отвечает за предоставление правильных шаблонов формата. Стиль формата может быть SHORT или LONG. Для лучшего понимания стилей формата давайте рассмотрим число 1000 в локали США. КОРОТКИЙ стиль отформатирует его как «10K», а ДЛИННЫЙ — как «10 тысяч».

Теперь давайте посмотрим на пример, который возьмет количество лайков под этой статьей и объединит его с двумя разными стилями:

@Test
public void givenNumber_thenCompactValues() {
NumberFormat likesShort =
NumberFormat.getCompactNumberInstance(new Locale("en", "US"), NumberFormat.Style.SHORT);
likesShort.setMaximumFractionDigits(2);
assertEquals("2.59K", likesShort.format(2592));

NumberFormat likesLong =
NumberFormat.getCompactNumberInstance(new Locale("en", "US"), NumberFormat.Style.LONG);
likesLong.setMaximumFractionDigits(2);
assertEquals("2.59 thousand", likesLong.format(2592));
}

3. Предварительный просмотр изменений

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

javac -Xlint:preview --enable-preview -source 12 src/main/java/File.java

3.1. Переключение выражений (предварительная версия)

Самая популярная функция, представленная в Java 12, — это Switch Expressions .

В качестве демонстрации давайте сравним старый и новый операторы switch. Мы будем использовать их, чтобы отличать рабочие дни от выходных на основе перечисления DayOfWeek из экземпляра LocalDate .

Во-первых, давайте посмотрим на старый синтаксис:

DayOfWeek dayOfWeek = LocalDate.now().getDayOfWeek();
String typeOfDay = "";
switch (dayOfWeek) {
case MONDAY:
case TUESDAY:
case WEDNESDAY:
case THURSDAY:
case FRIDAY:
typeOfDay = "Working Day";
break;
case SATURDAY:
case SUNDAY:
typeOfDay = "Day Off";
}

А теперь давайте посмотрим на ту же логику переключения выражений:

typeOfDay = switch (dayOfWeek) {
case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> "Working Day";
case SATURDAY, SUNDAY -> "Day Off";
};

Новые операторы switch не только более компактны и читабельны. Они также устраняют необходимость в операторах break. Выполнение кода не сорвется после первого совпадения.

Еще одно заметное отличие состоит в том, что мы можем присвоить оператору switch непосредственно переменную. Раньше нельзя было.

Также возможно выполнить код в выражениях переключения без возврата какого-либо значения:

switch (dayOfWeek) {
case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> System.out.println("Working Day");
case SATURDAY, SUNDAY -> System.out.println("Day Off");
}

Более сложную логику следует заключать в фигурные скобки:

case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> {
// more logic
System.out.println("Working Day")
}

Обратите внимание, что мы можем выбирать между старым и новым синтаксисом. Выражения переключения Java 12 являются только расширением, а не заменой.

3.2. Сопоставление шаблонов для instanceof (предварительная версия)

Еще одна предварительная функция, представленная в Java 12, — сопоставление с образцом для instanceof .

В предыдущих версиях Java при использовании, например, операторов if вместе с instanceof нам пришлось бы явно приводить объект к типу, чтобы получить доступ к его функциям:

Object obj = "Hello World!";
if (obj instanceof String) {
String s = (String) obj;
int length = s.length();
}

В Java 12 мы можем объявить новую переменную с приведением типов непосредственно в операторе:

if (obj instanceof String s) {
int length = s.length();
}

Компилятор автоматически внедрит для нас переменную типа String s .

4. Изменения JVM

Java 12 поставляется с несколькими улучшениями JVM. В этом разделе мы кратко рассмотрим несколько наиболее важных из них.

4.1. Shenandoah: сборщик мусора с малой паузой

Shenandoah — это экспериментальный алгоритм сборки мусора (GC) , который пока не включен в сборки Java 12 по умолчанию.

Это сокращает время паузы GC, выполняя эвакуацию одновременно с работающими потоками Java. Это означает, что в Shenandoah время паузы не зависит от размера кучи и должно быть постоянным. Мусор, собирающий кучу 200 ГБ или кучу 2 ГБ, должен иметь аналогичное поведение с низкой паузой.

Shenandoah станет частью основных сборок JDK, начиная с версии 15.

4.2. Набор микротестов

Java 12 представляет набор из около 100 микротестов для исходного кода JDK.

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

4.3. Архивы CDS по умолчанию

Функция Class Data Sharing (CDS) помогает сократить время запуска и объем используемой памяти между несколькими виртуальными машинами Java. Он использует встроенный сгенерированный по умолчанию список классов, который содержит выбранные классы базовой библиотеки.

Изменение, появившееся в Java 12, заключается в том, что архив CDS включен по умолчанию. Чтобы запускать программы с выключенным CDS, нам нужно отключить флаг Xshare:

java -Xshare:off HelloWorld.java

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

5. Вывод

В этой статье мы увидели большинство новых функций, реализованных в Java 12. Мы также перечислили некоторые другие заметные добавления и удаления. Как обычно, исходный код доступен на GitHub .