Нововведения Java 8
Java 8 изменила повседневный стиль Java-кода: функции стало возможно передавать как значения, коллекции получили потоковые конвейеры, интерфейсы — эволюционировать без обязательного изменения каждой реализации, а работа с датой и асинхронностью получила новые API.
Лямбды, SAM и ссылки на методы
List<String> normalized = names.stream()
.filter(name -> !name.trim().isEmpty())
.map(String::trim)
.collect(Collectors.toList());Лямбда реализует Функциональные интерфейсы, а ссылка String::trim — более короткая запись совместимого поведения. Тип лямбды определяется контекстом.
Java 8 добавила java.util.function: Predicate, Function, Consumer, Supplier, операторы и primitive-specializations.
Stream API
Stream описывает одноразовый ленивый конвейер:
long count = orders.stream()
.filter(Order::paid)
.map(Order::customerId)
.distinct()
.count();Промежуточные операции ленивы; терминальная запускает обработку. Stream не является коллекцией и сам по себе не хранит элементы. Parallel stream использует инфраструктуру Fork/Join и требует ассоциативных, независимых операций — он не гарантирует ускорение.
Default и static-методы интерфейсов
interface Identified {
long id();
default String externalId() {
return "id-" + id();
}
static boolean valid(long id) {
return id > 0;
}
}Default-методы позволили добавлять поведение в интерфейс, не ломая все существующие реализации. При конфликте:
- метод класса имеет приоритет над default интерфейса;
- более специфичный интерфейс имеет приоритет;
- иначе класс должен явно разрешить конфликт и может вызвать
InterfaceName.super.method().
Optional
Optional<T> выражает возможное отсутствие результата:
Optional<User> user = repository.findById(id);
String name = user
.filter(User::active)
.map(User::name)
.orElse("unknown");Это прежде всего тип результата API, а не замена каждой nullable-переменной.
java.time
Новый date/time API разделяет разные понятия:
Instant— точка на UTC-временной шкале;LocalDate— дата без времени и зоны;LocalDateTime— дата и время без зоны;ZonedDateTime— дата-время с часовым поясом;Duration— длительность по секундам/наносекундам;Period— календарный период;DateTimeFormatter— неизменяемое потокобезопасное форматирование.
Instant expiresAt = clock.instant().plus(Duration.ofMinutes(15));Выбор типа должен отражать смысл данных; LocalDateTime не является моментом времени без зоны/offset.
CompletableFuture
CompletableFuture<User> userFuture =
CompletableFuture.supplyAsync(() -> loadUser(id), executor);
CompletableFuture<Profile> profileFuture =
userFuture.thenCompose(user -> loadProfile(user.id()));thenApplyпреобразует готовое значение;thenComposeразворачивает вложенную асинхронную операцию;thenCombineобъединяет независимые результаты;exceptionally,handle,whenCompleteпо-разному работают с ошибкой.
Без явного executor async-методы часто используют общий пул; для блокирующего I/O это может быть неподходящим решением.
Изменения библиотек
Java 8 также принесла:
Map.computeIfAbsent,compute,merge,replaceAll;Collection.removeIf,forEach,spliterator;Arrays.parallelSort;- стандартный
Base64; - повторяемые аннотации и аннотации применительно к использованию типов;
LongAdderи другие concurrent-инструменты;- параметры методов в reflection при компиляции с
-parameters.
В HotSpot постоянное поколение PermGen было удалено; метаданные классов переместились в Metaspace, управляемый иначе. Это изменение JVM, а не новая возможность языка.
Ловушки
- Считать Stream хранилищем и пытаться использовать его повторно.
- Включать
parallel()без измерения и проверки безопасности операций. - Путать
thenApplyиthenCompose. - Использовать
LocalDateTimeкак абсолютный момент. - Выполнять блокирующую работу в общем async-пуле без контроля.
- Считать default-метод полноценным множественным наследованием состояния.
Вопросы на собеседовании
- Какие возможности Java 8 сильнее всего изменили стиль кода?
- Чем Stream отличается от коллекции?
- Как разрешается конфликт default-методов?
- Чем
thenApplyотличается отthenCompose? - Почему
LocalDateTimeне определяет момент времени? - Что произошло с PermGen?
Связанные заметки
Лямбда выражения · Функциональные интерфейсы · ФИ стандартной библиотеки Java · Stream API · Класс Optional · Интерфейсы Java