JavaRush /Java блог /Random UA /Java 8. Все, що вам буде потрібно
Roman Beekeeper
35 рівень

Java 8. Все, що вам буде потрібно

Стаття з групи Random UA

Java 8 Tutorial

"Java поки що жива, та люди починають розуміти це."
Ласкаво просимо в моє представлення Java 8. Ця стаття проведе тебе крок за кроком двох всіх новий фіч з Java 7 в Java 8. За допомогою швидких і простих прикладів коду, ми зможемо вивчити Default Interfaces , Method references і Repeatable annotations . Наприкінці статті ми познайомимося із Stream API.
Java 8. Все, що вам буде потрібно - 1
Без зайвої балаканини — лише код та коментарі до нього! Уперед!

Default Methods for Interfaces

Java 8 дозволяє нам додавати не абстрактні методи (які реалізовані) в інтерфейси шляхом додавання ключового слова default. Ця можливість так само відома як Extention Methods . Нижче наведено перший приклад:
interface Formula {
    double calculate(int a);

    default double sqrt(int a) {
        return Math.sqrt(a);
    }
}
Крім абстрактного методу calculate, в інтерфейсі Formulaтак само визначено дефолтний метод sqrt. Класи, які реалізують цей інтерфейс, повинні лише реалізувати метод calculate. Дефолтний метод sqrtможе бути використаний "з коробки".
Formula formula = new Formula() {
    @Override
    public double calculate(int a) {
        return sqrt(a * 100);
    }
};

formula.calculate(100);     // 100.0
formula.sqrt(16);           // 4.0
Інтерфейс Formulaреалізований як анонімний клас. Код надлишковий: 6 рядків для реалізації sqrt(a * 100). Як ми побачимо в наступній секції, є більш красивий спосіб реалізації одиночного методу в Java 8.

Lambda expressions

Почнемо з простого прикладу сортування списку рядків у попередніх версіях Java:
List<String> names = Arrays.asList("peter", "anna", "mike", "xenia");

Collections.sort(names, new Comparator<String>() {
    @Override
    public int compare(String a, String b) {
        return b.compareTo(a);
    }
});
Статичний метод Collections.sortприймає список та сомпаратор у тому порядку, в якому потрібно сортувати список. Завжди можна створити анонімний клас компаратора та передати його. Замість створення анонімного класу, в Java 8 можна зробити коротший запис, лямбда висловлювання.
Collections.sort(names, (String a, String b) -> {
    return b.compareTo(a);
});
Як ви бачите код набагато коротший і простий для читання. Але це можна зробити ще коротшим:
Collections.sort(names, (String a, String b) -> b.compareTo(a));
Для тіла з одним рядком можна пропустити {}і слово return. Але можна зробити це ще коротшим:
Collections.sort(names, (a, b) -> b.compareTo(a));
Java компілятор знає про типи аргументів, тому їх можна пропустити також. Давайте копію глибше в лямбда вирази і зрозуміємо як їх можна використовувати.

Functional Interfaces

Як лямбда вирази вписуються в систему Java типів? Кожна лямбда відповідає типу, що описується в інтерфейсі. Тому функціональний інтерфейс повинен містити лише один абстрактний метод. Кожне лямбда вираз цього буде відповідати цьому абстрактному методу. З моменту того, що дефолтні методи не абстрактні, тому ви можете створити дефолтні методи в функціональні інтерфейси скільки потрібно. Ми також можемо використовувати довільні інтерфейси як лямбда виразу, якщо в цьому інтерфейсі тільки один абстрактний метод. Щоб відповідати цим вимогам, потрібно додати @FucntionalInterfaceанотацію. Компілятор знає про неї і викине виняток, якщо захочете поставити більше одного абстрактного методу. Приклад:
@FunctionalInterface
interface Converter<F, T> {
    T convert(F from);
}
Converter<String, Integer> converter = (from) -> Integer.valueOf(from);
Integer converted = converter.convert("123");
System.out.println(converted);    // 123
Зауважте, що код буде також скомпільований, якщо @FunctionalInterfaceанотація буде пропущена.

Method and Constructor References

Приклад вище може бути також зроблено ще менше шляхом використання method references:
Converter<String, Integer> converter = Integer::valueOf;
Integer converted = converter.convert("123");
System.out.println(converted);   // 123
Java 8 дозволяє вам передавати посилання на метод або конструктор шляхом додавання ::. Приклад вище показує, як можна посилатися на статичний метод, не дивлячись на це, ми також можемо посилатися на нестатичні методи:
class Something {
    String startsWith(String s) {
        return String.valueOf(s.charAt(0));
    }
}
Something something = new Something();
Converter<String, String> converter = something::startsWith;
String converted = converter.convert("Java");
System.out.println(converted);    // "J"
Погляньмо, як ::працює з конструкторами. Для початку ми визначимо як приклад клас із різними конструкторами:
class Person {
    String firstName;
    String lastName;

    Person() {}

    Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}
Далі визначимо інтерфейс для створення нових об'єктів:
interface PersonFactory<P extends Person> {
    P create(String firstName, String lastName);
}
Замість того, щоб реалізовувати фабрику по створенню, ми поєднаємо разом це за допомогою ::для конструкторів:
PersonFactory<Person> personFactory = Person::new;
Person person = personFactory.create("Peter", "Parker");
Ми створабо посилання на конструктор через Person::new. Java компілятор автоматично вибере правильний конструктор, який відповідає методу сигнатури PersonFactory.create. ... Далі буде. На жаль я не знайшов, як можна зберегти чернетку статті, а це реально дивно, а сеанс часу на переклад закінчено - тому дороблю пізніше. Всім, хто знає і розуміє англійську - Оринігала Стаття . Якщо є пропозиції щодо виправлення перекладу — пишіть будь-яким доступним вам способом. Мій Github аккаунт
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ