Java 8: Полное справочное руководство (Quick Reference)
Java 8 — Обзор
Java 8 — мажорный релиз языка Java, вышедший 18 марта 2014 года. Он принес поддержку функционального программирования, новый движок JavaScript (Nashorn), новые API для работы с датой/временем, Stream API и многое другое.
Ключевые новые возможности
Lambda-выражения — функциональная обработка данных.
Ссылки на методы — ссылка на метод по имени вместо прямого вызова.
Методы по умолчанию (default methods) — реализация методов в интерфейсах.
Новые инструменты — например,
jdepsдля анализа зависимостей.Stream API — конвейерная обработка коллекций.
Date/Time API — улучшенная работа с датой и временем.
Optional — лучшие практики работы с null.
Nashorn, JavaScript Engine — движок для выполнения JS-кода на JVM.
Пример: Сортировка в Java 7 vs Java 8
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
import java.util.Comparator;
public class Java8Tester {
public static void main(String args[]) {
List<String> names1 = new ArrayList<>();
names1.add("Mahesh ");
names1.add("Suresh ");
names1.add("Ramesh ");
names1.add("Naresh ");
names1.add("Kalpesh ");
List<String> names2 = new ArrayList<>();
names2.add("Mahesh ");
names2.add("Suresh ");
names2.add("Ramesh ");
names2.add("Naresh ");
names2.add("Kalpesh ");
Java8Tester tester = new Java8Tester();
System.out.println("Sort using Java 7 syntax: ");
tester.sortUsingJava7(names1);
System.out.println(names1);
System.out.println("Sort using Java 8 syntax: ");
tester.sortUsingJava8(names2);
System.out.println(names2);
}
// Стиль Java 7: анонимный класс
private void sortUsingJava7(List<String> names) {
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.compareTo(s2);
}
});
}
// Стиль Java 8: лямбда-выражение
private void sortUsingJava8(List<String> names) {
Collections.sort(names, (s1, s2) -> s1.compareTo(s2));
}
}
Результат:
Sort using Java 7 syntax: [ Kalpesh Mahesh Naresh Ramesh Suresh ] Sort using Java 8 syntax: [ Kalpesh Mahesh Naresh Ramesh Suresh ]
Метод sortUsingJava8() использует лямбда-выражение для задания критерия сортировки.
Настройка окружения Java 8
Локальная установка
Скачайте Java SE бесплатно с официального сайта Oracle. Выберите версию под вашу ОС, запустите .exe и следуйте инструкциям. После установки настройте переменные окружения.
Windows (настройка PATH)
Предположим, Java установлена в c:\Program Files\java\jdk:
- Правый клик на «Мой компьютер» → «Свойства».
- Вкладка «Дополнительно» → «Переменные среды».
- Найдите переменную
Pathи добавьте путь кbinJDK:C:\WINDOWS\SYSTEM32;c:\Program Files\java\jdk\bin.
Linux/UNIX/Solaris/FreeBSD
Добавьте в .bashrc (или другой shell-конфиг):
export PATH=/path/to/java:$PATH
Популярные редакторы и IDE
- Notepad — простой редактор для Windows.
- NetBeans — бесплатная open-source IDE (netbeans.org).
- Eclipse — популярная open-source IDE (eclipse.org).
Lambda-выражения в Java 8
Лямбда-выражения — главная фича Java 8, позволяющая писать функциональный код.
Синтаксис
parameter -> expression body
Характеристики
- Необязательное объявление типа — компилятор выводит тип из значения.
- Необязательные скобки — для одного параметра скобки не нужны.
- Необязательные фигурные скобки — если тело — одно выражение.
- Необязательное
return— компилятор сам вернет значение однострочного выражения.
Пример лямбд
public class Java8Tester {
public static void main(String args[]) {
Java8Tester tester = new Java8Tester();
// С объявлением типа
MathOperation addition = (int a, int b) -> a + b;
// Без типа
MathOperation subtraction = (a, b) -> a - b;
// С return и скобками
MathOperation multiplication = (int a, int b) -> { return a * b; };
// Без return и скобок
MathOperation division = (int a, int b) -> a / b;
System.out.println("10 + 5 = " + tester.operate(10, 5, addition));
System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction));
System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication));
System.out.println("10 / 5 = " + tester.operate(10, 5, division));
// Без скобок у параметра
GreetingService greetService1 = message -> System.out.println("Hello " + message);
// Со скобками
GreetingService greetService2 = (message) -> System.out.println("Hello " + message);
greetService1.sayMessage("Mahesh");
greetService2.sayMessage("Suresh");
}
interface MathOperation { int operation(int a, int b); }
interface GreetingService { void sayMessage(String message); }
private int operate(int a, int b, MathOperation mathOperation) {
return mathOperation.operation(a, b);
}
}
Результат
10 + 5 = 15 10 - 5 = 5 10 x 5 = 50 10 / 5 = 2 Hello Mahesh Hello Suresh
Важно: Лямбды используются для inline-реализации функциональных интерфейсов (интерфейсов с одним абстрактным методом). Они устраняют необходимость в анонимных классах.
Область видимости (Scope)
Лямбда может ссылаться на final или effectively final переменные (присваиваемые только один раз). При повторном присваивании — ошибка компиляции.
Пример Scope
public class Java8Tester {
final static String salutation = "Hello! ";
public static void main(String args[]) {
GreetingService greetService1 = message -> System.out.println(salutation + message);
greetService1.sayMessage("Mahesh");
}
interface GreetingService { void sayMessage(String message); }
}
Вывод: Hello! Mahesh
Ссылки на методы (Method References)
Ссылки на методы позволяют ссылаться на методы по имени через символ ::. Поддерживаются:
- Статические методы
- Методы экземпляра
- Конструкторы (
TreeSet::new)
Пример
import java.util.List;
import java.util.ArrayList;
public class Java8Tester {
public static void main(String args[]) {
List<String> names = new ArrayList<>();
names.add("Mahesh");
names.add("Suresh");
names.add("Ramesh");
names.add("Naresh");
names.add("Kalpesh");
names.forEach(System.out::println); // Статическая ссылка на метод
}
}
Вывод: каждый элемент списка на новой строке.
Функциональные интерфейсы
Функциональный интерфейс — интерфейс с единственным абстрактным методом. Java 8 определяет множество таких интерфейсов в пакете java.util.function.
Список основных функциональных интерфейсов (нажмите для раскрытия)
| № | Интерфейс и описание |
|---|---|
| 1 | BiConsumer<T,U> — операция с двумя аргументами, без результата. |
| 2 | BiFunction<T,U,R> — функция с двумя аргументами и результатом. |
| 3 | BinaryOperator<T> — операция над двумя операндами одного типа. |
| 4 | BiPredicate<T,U> — предикат с двумя аргументами. |
| 5 | BooleanSupplier — поставщик boolean-значений. |
| 6 | Consumer<T> — операция с одним аргументом, без результата. |
| 7 | DoubleBinaryOperator — операция над двумя double. |
| 8 | DoubleConsumer — операция с одним double. |
| 9 | DoubleFunction<R> — функция от double к R. |
| 10 | DoublePredicate — предикат для double. |
| 11 | DoubleSupplier — поставщик double. |
| 12 | DoubleToIntFunction — double → int. |
| 13 | DoubleToLongFunction — double → long. |
| 14 | DoubleUnaryOperator — унарная операция над double. |
| 15 | Function<T,R> — функция T → R. |
| 16 | IntBinaryOperator — операция над двумя int. |
| 17 | IntConsumer — операция с одним int. |
| 18 | IntFunction<R> — функция int → R. |
| 19 | IntPredicate — предикат для int. |
| 20 | IntSupplier — поставщик int. |
| 21 | IntToDoubleFunction — int → double. |
| 22 | IntToLongFunction — int → long. |
| 23 | IntUnaryOperator — унарная операция над int. |
| 24 | LongBinaryOperator — операция над двумя long. |
| 25 | LongConsumer — операция с одним long. |
| 26 | LongFunction<R> — функция long → R. |
| 27 | LongPredicate — предикат для long. |
| 28 | LongSupplier — поставщик long. |
| 29 | LongToDoubleFunction — long → double. |
| 30 | LongToIntFunction — long → int. |
| 31 | LongUnaryOperator — унарная операция над long. |
| 32 | ObjDoubleConsumer<T> — операция над объектом и double. |
| 33 | ObjIntConsumer<T> — операция над объектом и int. |
| 34 | ObjLongConsumer<T> — операция над объектом и long. |
| 35 | Predicate<T> — предикат с одним аргументом. |
| 36 | Supplier<T> — поставщик результатов. |
| 37 | ToDoubleBiFunction<T,U> — (T,U) → double. |
| 38 | ToDoubleFunction<T> — T → double. |
| 39 | ToIntBiFunction<T,U> — (T,U) → int. |
| 40 | ToIntFunction<T> — T → int. |
| 41 | ToLongBiFunction<T,U> — (T,U) → long. |
| 42 | ToLongFunction<T> — T → long. |
| 43 | UnaryOperator<T> — унарная операция T → T. |
Пример с Predicate
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class Java8Tester {
public static void main(String args[]) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
System.out.println("Print all numbers:");
eval(list, n -> true);
System.out.println("Print even numbers:");
eval(list, n -> n % 2 == 0);
System.out.println("Print numbers greater than 3:");
eval(list, n -> n > 3);
}
public static void eval(List<Integer> list, Predicate<Integer> predicate) {
for (Integer n : list) {
if (predicate.test(n)) {
System.out.println(n + " ");
}
}
}
}
Результат
Print all numbers: 1 2 3 4 5 6 7 8 9 Print even numbers: 2 4 6 8 Print numbers greater than 3: 4 5 6 7 8 9
Методы по умолчанию (Default Methods)
Java 8 позволяет добавлять реализацию методов в интерфейсы через ключевое слово default. Это сделано для обратной совместимости: старые интерфейсы (например, Collection) могут получить новые методы (forEach) без нарушения существующих реализаций.
Синтаксис
public interface Vehicle {
default void print() {
System.out.println("I am a vehicle!");
}
}
Решение конфликтов множественных default-методов
Если класс реализует два интерфейса с одинаковым default-методом, нужно разрешить неоднозначность:
Вариант 1: Переопределить метод
public class Car implements Vehicle, FourWheeler {
public void print() {
System.out.println("I am a four wheeler car vehicle!");
}
}
Вариант 2: Явный вызов через super
public class Car implements Vehicle, FourWheeler {
public void print() {
Vehicle.super.print();
}
}
Статические методы в интерфейсах
С Java 8 интерфейсы могут иметь статические helper-методы:
public interface Vehicle {
default void print() { System.out.println("I am a vehicle!"); }
static void blowHorn() { System.out.println("Blowing horn!!!"); }
}
Полный пример
public class Java8Tester {
public static void main(String args[]) {
Vehicle vehicle = new Car();
vehicle.print();
}
}
interface Vehicle {
default void print() { System.out.println("I am a vehicle!"); }
static void blowHorn() { System.out.println("Blowing horn!!!"); }
}
interface FourWheeler {
default void print() { System.out.println("I am a four wheeler!"); }
}
class Car implements Vehicle, FourWheeler {
public void print() {
Vehicle.super.print();
FourWheeler.super.print();
Vehicle.blowHorn();
System.out.println("I am a car!");
}
}
Результат
I am a vehicle! I am a four wheeler! Blowing horn!!! I am a car!
Stream API
Stream — новый абстрактный слой в Java 8 для декларативной обработки данных (как SQL). Позволяет использовать многоядерные процессоры без явного параллельного кода.
Что такое Stream?
- Последовательность элементов — элементы вычисляются по требованию, не хранятся.
- Источник — коллекции, массивы, I/O ресурсы.
- Агрегатные операции — filter, map, limit, reduce, find, match и др.
- Пайплайнинг — большинство операций возвращают Stream для цепочки вызовов.
collect()— терминальная операция. - Автоматическая итерация — не нужен явный цикл.
Создание стримов
stream()— последовательный стрим.parallelStream()— параллельный стрим.
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd", "", "jkl");
List<String> filtered = strings.stream()
.filter(s -> !s.isEmpty())
.collect(Collectors.toList());
Основные операции
forEach
Random random = new Random(); random.ints().limit(10).forEach(System.out::println);
map
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
List<Integer> squaresList = numbers.stream()
.map(i -> i * i)
.distinct()
.collect(Collectors.toList());
filter
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd", "", "jkl");
long count = strings.stream().filter(String::isEmpty).count();
limit
random.ints().limit(10).forEach(System.out::println);
sorted
random.ints().limit(10).sorted().forEach(System.out::println);
Parallel Processing
long count = strings.parallelStream().filter(String::isEmpty).count();
Collectors
List<String> filtered = strings.stream()
.filter(s -> !s.isEmpty())
.collect(Collectors.toList());
String mergedString = strings.stream()
.filter(s -> !s.isEmpty())
.collect(Collectors.joining(", "));
Statistics
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
IntSummaryStatistics stats = numbers.stream()
.mapToInt(x -> x)
.summaryStatistics();
System.out.println("Max: " + stats.getMax());
System.out.println("Min: " + stats.getMin());
System.out.println("Sum: " + stats.getSum());
System.out.println("Average: " + stats.getAverage());
Полный пример Stream API
import java.util.*;
import java.util.stream.Collectors;
import java.util.IntSummaryStatistics;
public class Java8Tester {
public static void main(String args[]) {
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd", "", "jkl");
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
List<Integer> integers = Arrays.asList(1,2,13,4,15,6,17,8,19);
// Java 7 style (omitted for brevity)
System.out.println("Using Java 8:");
long count = strings.stream().filter(String::isEmpty).count();
System.out.println("Empty Strings: " + count);
count = strings.stream().filter(s -> s.length() == 3).count();
System.out.println("Strings of length 3: " + count);
List<String> filtered = strings.stream()
.filter(s -> !s.isEmpty())
.collect(Collectors.toList());
System.out.println("Filtered List: " + filtered);
String merged = strings.stream()
.filter(s -> !s.isEmpty())
.collect(Collectors.joining(", "));
System.out.println("Merged String: " + merged);
List<Integer> squares = numbers.stream()
.map(i -> i * i)
.distinct()
.collect(Collectors.toList());
System.out.println("Squares List: " + squares);
IntSummaryStatistics stats = integers.stream()
.mapToInt(x -> x)
.summaryStatistics();
System.out.println("Max: " + stats.getMax());
System.out.println("Min: " + stats.getMin());
System.out.println("Sum: " + stats.getSum());
System.out.println("Average: " + stats.getAverage());
new Random().ints().limit(10).sorted().forEach(System.out::println);
// Параллельная обработка
count = strings.parallelStream().filter(String::isEmpty).count();
System.out.println("Empty Strings (parallel): " + count);
}
}
Результат показывает идентичные результаты для Java 7 и Java 8, но код Java 8 лаконичнее и декларативнее.
Optional Class (повторно)
Описание класса Optional дублируется из предыдущей статьи. См. статью Mastering Java 8 Optional.
Nashorn JavaScript (повторно)
Описание Nashorn дублируется из статьи Java 8 Nashorn.
New Date/Time API (повторно)
Описание нового Date/Time API дублируется из статьи Java 8 Date/Time API.
Base64 (повторно)
Описание Base64 дублируется из статьи Java 8 Base64.
java
- Понимание Java Vector: использование, особенности и сравнение с ArrayList
- Основы ЧПУ-фрезерования: краткий справочник профессионального оператора
- Мастерство профилактического и состояния-ориентированного обслуживания: практическое руководство по разра…
- Защитите свою цепь поставок: комплексные страховые стратегии
- Станки для гибки профильных труб: экспертное руководство
- Холодные прессы: полное руководство по эффективной металлоформовке
- Планетарный редуктор: компактность, высокий крутящий момент и снижение оборотов
- Сверлильно-фрезерный станок Jet: полное профессиональное руководство
- Сервопрессовые станки: принцип работы и преимущества над механическими прессами
- Профессиональное руководство по пневматическим цилиндрам: быстро и надежно