# Cобеседование по Java. Разбор вопросов и ответов.


<a href="https://mc.yandex.ru/pixel/8711235002931986822?rnd=%aw_random%">
    <img src="https://mc.yandex.ru/pixel/8711235002931986822?rnd=%aw_random%" />        
  </a>&nbsp;&nbsp;
<a href="https://mc.yandex.ru/watch/92801430">
    <img src="https://mc.yandex.ru/watch/92801430" />        
  </a>&nbsp;&nbsp;


Нажмите ★, если вам нравится проект. Ваш вклад сердечно ♡ приветствуется.

Если вам интересно мое резюме: https://github.com/DEBAGanov


# Java 8
- [Cобеседование по Java. Разбор вопросов и ответов.](#cобеседование-по-java-разбор-вопросов-и-ответов)
- [Java 8](#java-8)
  - [Какие нововведения, появились в Java 8 и JDK 8?](#какие-нововведения-появились-в-java-8-и-jdk-8)
  - [Что такое _«лямбда»_? Какова структура и особенности использования лямбда-выражения?](#что-такое-лямбда-какова-структура-и-особенности-использования-лямбда-выражения)
  - [К каким переменным есть доступ у лямбда-выражений?](#к-каким-переменным-есть-доступ-у-лямбда-выражений)
  - [Как отсортировать список строк с помощью лямбда-выражения?](#как-отсортировать-список-строк-с-помощью-лямбда-выражения)
  - [Что такое «ссылка на метод»?](#что-такое-ссылка-на-метод)
  - [Какие виды ссылок на методы вы знаете?](#какие-виды-ссылок-на-методы-вы-знаете)
  - [Объясните выражение `System.out::println`.](#объясните-выражение-systemoutprintln)
  - [Что такое «функциональные интерфейсы»?](#что-такое-функциональные-интерфейсы)
  - [Для чего нужны функциональные интерфейсы `Function<T,R>`, `DoubleFunction<R>`, `IntFunction<R>` и `LongFunction<R>`?](#для-чего-нужны-функциональные-интерфейсы-functiontr-doublefunctionr-intfunctionr-и-longfunctionr)
  - [Для чего нужны функциональные интерфейсы `UnaryOperator<T>`, `DoubleUnaryOperator`, `IntUnaryOperator` и `LongUnaryOperator`?](#для-чего-нужны-функциональные-интерфейсы-unaryoperatort-doubleunaryoperator-intunaryoperator-и-longunaryoperator)
  - [Для чего нужны функциональные интерфейсы `BinaryOperator<T>`, `DoubleBinaryOperator`, `IntBinaryOperator` и `LongBinaryOperator`?](#для-чего-нужны-функциональные-интерфейсы-binaryoperatort-doublebinaryoperator-intbinaryoperator-и-longbinaryoperator)
  - [Для чего нужны функциональные интерфейсы `Predicate<T>`, `DoublePredicate`, `IntPredicate` и `LongPredicate`?](#для-чего-нужны-функциональные-интерфейсы-predicatet-doublepredicate-intpredicate-и-longpredicate)
  - [Для чего нужны функциональные интерфейсы `Consumer<T>`, `DoubleConsumer`, `IntConsumer` и `LongConsumer`?](#для-чего-нужны-функциональные-интерфейсы-consumert-doubleconsumer-intconsumer-и-longconsumer)
  - [Для чего нужны функциональные интерфейсы `Supplier<T>`,  `BooleanSupplier`, `DoubleSupplier`, `IntSupplier` и `LongSupplier`?](#для-чего-нужны-функциональные-интерфейсы-suppliert--booleansupplier-doublesupplier-intsupplier-и-longsupplier)
  - [Для чего нужен функциональный интерфейс `BiConsumer<T,U>`?](#для-чего-нужен-функциональный-интерфейс-biconsumertu)
  - [Для чего нужен функциональный интерфейс `BiFunction<T,U,R>`?](#для-чего-нужен-функциональный-интерфейс-bifunctiontur)
  - [Для чего нужен функциональный интерфейс `BiPredicate<T,U>`?](#для-чего-нужен-функциональный-интерфейс-bipredicatetu)
  - [Для чего нужны функциональные интерфейсы вида `_To_Function`?](#для-чего-нужны-функциональные-интерфейсы-вида-_to_function)
  - [Для чего нужны функциональные интерфейсы `ToDoubleBiFunction<T,U>`, `ToIntBiFunction<T,U>` и `ToLongBiFunction<T,U>`?](#для-чего-нужны-функциональные-интерфейсы-todoublebifunctiontu-tointbifunctiontu-и-tolongbifunctiontu)
  - [Для чего нужны функциональные интерфейсы `ToDoubleFunction<T>`, `ToIntFunction<T>` и `ToLongFunction<T>`?](#для-чего-нужны-функциональные-интерфейсы-todoublefunctiont-tointfunctiont-и-tolongfunctiont)
  - [Для чего нужны функциональные интерфейсы `ObjDoubleConsumer<T>`, `ObjIntConsumer<T>` и `ObjLongConsumer<T>`?](#для-чего-нужны-функциональные-интерфейсы-objdoubleconsumert-objintconsumert-и-objlongconsumert)
  - [Что такое `StringJoiner`?](#что-такое-stringjoiner)
  - [Что такое `default` методы интрефейса?](#что-такое-default-методы-интрефейса)
  - [Как вызывать `default` метод интерфейса в реализующем этот интерфейс классе?](#как-вызывать-default-метод-интерфейса-в-реализующем-этот-интерфейс-классе)
  - [Что такое `static` метод интерфейса?](#что-такое-static-метод-интерфейса)
  - [Как вызывать `static` метод интерфейса?](#как-вызывать-static-метод-интерфейса)
  - [Что такое `Optional`?](#что-такое-optional)
  - [Что такое `Stream`?](#что-такое-stream)
  - [Какие существуют способы создания стрима?](#какие-существуют-способы-создания-стрима)
  - [В чем разница между `Collection` и `Stream`?](#в-чем-разница-между-collection-и-stream)
  - [Для чего нужен метод `collect()` в стримах?](#для-чего-нужен-метод-collect-в-стримах)
  - [Для чего в стримах применяются методы `forEach()` и `forEachOrdered()`?](#для-чего-в-стримах-применяются-методы-foreach-и-foreachordered)
  - [Для чего в стримах предназначены методы `map()` и `mapToInt()`, `mapToDouble()`, `mapToLong()`?](#для-чего-в-стримах-предназначены-методы-map-и-maptoint-maptodouble-maptolong)
  - [Какова цель метода `filter()` в стримах?](#какова-цель-метода-filter-в-стримах)
  - [Для чего в стримах предназначен метод `limit()`?](#для-чего-в-стримах-предназначен-метод-limit)
  - [Для чего в стримах предназначен метод `sorted()`?](#для-чего-в-стримах-предназначен-метод-sorted)
  - [Для чего в стримах предназначены методы `flatMap()`, `flatMapToInt()`, `flatMapToDouble()`, `flatMapToLong()`?](#для-чего-в-стримах-предназначены-методы-flatmap-flatmaptoint-flatmaptodouble-flatmaptolong)
  - [Расскажите о параллельной обработке в Java 8.](#расскажите-о-параллельной-обработке-в-java-8)
  - [Какие конечные методы работы со стримами вы знаете?](#какие-конечные-методы-работы-со-стримами-вы-знаете)
  - [Какие промежуточные методы работы со стримами вы знаете?](#какие-промежуточные-методы-работы-со-стримами-вы-знаете)
  - [Как вывести на экран 10 случайных чисел, используя `forEach()`?](#как-вывести-на-экран-10-случайных-чисел-используя-foreach)
  - [Как можно вывести на экран уникальные квадраты чисел используя метод `map()`?](#как-можно-вывести-на-экран-уникальные-квадраты-чисел-используя-метод-map)
  - [Как вывести на экран количество пустых строк с помощью метода `filter()`?](#как-вывести-на-экран-количество-пустых-строк-с-помощью-метода-filter)
  - [Как вывести на экран 10 случайных чисел в порядке возрастания?](#как-вывести-на-экран-10-случайных-чисел-в-порядке-возрастания)
  - [Как найти максимальное число в наборе?](#как-найти-максимальное-число-в-наборе)
  - [Как найти минимальное число в наборе?](#как-найти-минимальное-число-в-наборе)
  - [Как получить сумму всех чисел в наборе?](#как-получить-сумму-всех-чисел-в-наборе)
  - [Как получить среднее значение всех чисел?](#как-получить-среднее-значение-всех-чисел)
  - [Какие дополнительные методы для работы с ассоциативными массивами (maps) появились в Java 8?](#какие-дополнительные-методы-для-работы-с-ассоциативными-массивами-maps-появились-в-java-8)
  - [Что такое `LocalDateTime`?](#что-такое-localdatetime)
  - [Что такое `ZonedDateTime`?](#что-такое-zoneddatetime)
  - [Как получить текущую дату с использованием Date Time API из Java 8?](#как-получить-текущую-дату-с-использованием-date-time-api-из-java-8)
  - [Как добавить 1 неделю, 1 месяц, 1 год, 10 лет к текущей дате с использованием Date Time API?](#как-добавить-1-неделю-1-месяц-1-год-10-лет-к-текущей-дате-с-использованием-date-time-api)
  - [Как получить следующий вторник используя Date Time API?](#как-получить-следующий-вторник-используя-date-time-api)
  - [Как получить вторую субботу текущего месяца используя Date Time API?](#как-получить-вторую-субботу-текущего-месяца-используя-date-time-api)
  - [Как получить текущее время с точностью до миллисекунд используя Date Time API?](#как-получить-текущее-время-с-точностью-до-миллисекунд-используя-date-time-api)
  - [Как получить текущее время по местному времени с точностью до миллисекунд используя Date Time API?](#как-получить-текущее-время-по-местному-времени-с-точностью-до-миллисекунд-используя-date-time-api)
  - [Как определить повторяемую аннотацию?](#как-определить-повторяемую-аннотацию)
  - [Что такое `Nashorn`?](#что-такое-nashorn)
  - [Что такое `jjs`?](#что-такое-jjs)
  - [Какой класс появился в Java 8 для кодирования/декодирования данных?](#какой-класс-появился-в-java-8-для-кодированиядекодирования-данных)
  - [Как создать Base64 кодировщик и декодировщик?](#как-создать-base64-кодировщик-и-декодировщик)
- [Источники](#источники)

## Какие нововведения, появились в Java 8 и JDK 8?
+ Методы интерфейсов по умолчанию;
+ Лямбда-выражения;
+ Функциональные интерфейсы;
+ Ссылки на методы и конструкторы;
+ Повторяемые аннотации;
+ Аннотации на типы данных;
+ Рефлексия для параметров методов;
+ _Stream API_ для работы с коллекциями;
+ Параллельная сортировка массивов;
+ Новое API для работы с датами и временем;
+ Новый движок JavaScript _Nashorn_;
+ Добавлено несколько новых классов для потокобезопасной работы;
+ Добавлен новый API для `Calendar` и `Locale`;
+ Добавлена поддержка _Unicode 6.2.0_;
+ Добавлен стандартный класс для работы с _Base64_;
+ Добавлена поддержка беззнаковой арифметики;
+ Улучшена производительность конструктора `java.lang.String(byte[], *)` и метода `java.lang.String.getBytes()`;
+ Новая реализация `AccessController.doPrivileged`, позволяющая устанавливать подмножество привилегий без необходимости проверки всех остальных уровней доступа;
+ _Password-based_ алгоритмы стали более устойчивыми;
+ Добавлена поддержка _SSL/TLS Server Name Indication (NSI)_ в _JSSE Server_;
+ Улучшено хранилище ключей (KeyStore);
+ Добавлен алгоритм _SHA-224_;
+ Удален мост _JDBC - ODBC_;
+ Удален _PermGen_, изменен способ хранения мета-данных классов;
+ Возможность создания профилей для платформы Java SE, которые включают в себя не всю платформу целиком, а некоторую ее часть;
+ Инструментарий
    + Добавлена утилита `jjs` для использования _JavaScript Nashorn_;
    + Команда `java` может запускать _JavaFX_ приложения;
    + Добавлена утилита `jdeps` для анализа _.class_-файлов.

[к оглавлению](#java-8)

## Что такое _«лямбда»_? Какова структура и особенности использования лямбда-выражения?
__Лямбда__ представляет собой набор инструкций, которые можно выделить в отдельную переменную и затем многократно вызвать в различных местах программы.

Основу лямбда-выражения составляет _лямбда-оператор_, который представляет стрелку `->`. Этот оператор разделяет лямбда-выражение на две части: левая часть содержит список параметров выражения, а правая собственно представляет тело лямбда-выражения, где выполняются все действия.

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

```java
interface Operationable {
    int calculate(int x, int y);
}

public static void main(String[] args) {
    Operationable operation = (x, y) -> x + y;     
    int result = operation.calculate(10, 20);
    System.out.println(result); //30
}
```

По факту лямбда-выражения являются в некотором роде сокращенной формой внутренних анонимных классов, которые ранее применялись в Java.

+ _Отложенное выполнение (deferred execution) лямбда-выражения_- определяется один раз в одном месте программы, вызываются при необходимости, любое количество раз и в произвольном месте программы.

+ _Параметры лямбда-выражения_ должны соответствовать по типу параметрам метода функционального интерфейса:

```java
operation = (int x, int y) -> x + y;
//При написании самого лямбда-выражения тип параметров разрешается не указывать:
(x, y) -> x + y;
//Если метод не принимает никаких параметров, то пишутся пустые скобки, например:
() -> 30 + 20;
//Если метод принимает только один параметр, то скобки можно опустить:
n -> n * n;
```

+ _Конечные лямбда-выражения_ не обязаны возвращать какое-либо значение.

```java
interface Printable {
    void print(String s);
}
 
public static void main(String[] args) {
    Printable printer = s -> System.out.println(s);
    printer.print("Hello, world");
}
```

+ _Блочные лямбда-выражения_ обрамляются фигурными скобками. В блочных лямбда-выражениях можно использовать внутренние вложенные блоки, циклы, конструкции `if`, `switch`, создавать переменные и т.д. Если блочное лямбда-выражение должно возвращать значение, то явным образом применяется оператор `return`:

```java
Operationable operation = (int x, int y) -> {       
    if (y == 0) {
        return 0;
    }
    else {
        return x / y;
    }
};
```

+ _Передача лямбда-выражения в качестве параметра метода_:

```java
interface Condition {
    boolean isAppropriate(int n);
}

private static int sum(int[] numbers, Condition condition) {
    int result = 0;
    for (int i : numbers) {
        if (condition.isAppropriate(i)) {
            result += i;
        }
    }
    return result;
}

public static void main(String[] args) {
    System.out.println(sum(new int[] {0, 1, 0, 3, 0, 5, 0, 7, 0, 9}, (n) -> n != 0));
} 
```

[к оглавлению](#java-8)

## К каким переменным есть доступ у лямбда-выражений?
Доступ к переменным внешней области действия из лямбда-выражения очень схож к доступу из анонимных объектов. Можно ссылаться на:

+ неизменяемые (_effectively final_ - не обязательно помеченные как `final`) локальные переменные;
+ поля класса;
+ статические переменные.

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

[к оглавлению](#java-8)

## Как отсортировать список строк с помощью лямбда-выражения?
```java
public static List<String> sort(List<String> list){
    Collections.sort(list, (a, b) -> a.compareTo(b));
    return list;
}
```

[к оглавлению](#java-8)

## Что такое «ссылка на метод»?
Если существующий в классе метод уже делает все, что необходимо, то можно воспользоваться механизмом __method reference (ссылка на метод)__ для непосредственной передачи этого метода. Такая ссылка передается в виде:

+ `имя_класса::имя_статического_метода` для статического метода;
+ `объект_класса::имя_метода` для метода экземпляра;
+ `название_класса::new` для конструктора.

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

```java
private interface Measurable {
    public int length(String string);
}

public static void main(String[] args) {
    Measurable a = String::length;
    System.out.println(a.length("abc"));
}
```

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

https://www.examclouds.com/ru/java/java-core-russian/method-references-russian

[к оглавлению](#java-8)

## Какие виды ссылок на методы вы знаете?
+ на статический метод;
+ на метод экземпляра;
+ на конструктор.

[к оглавлению](#java-8)

## Объясните выражение `System.out::println`.
Данное выражение иллюстрирует механизм _instance method reference_: передачи ссылки на метод `println()` статического поля `out` класса `System`.

[к оглавлению](#java-8)

## Что такое «функциональные интерфейсы»?
__Функциональный интерфейс__ - это интерфейс, который определяет только один абстрактный метод. 

Чтобы точно определить интерфейс как функциональный, добавлена аннотация `@FunctionalInterface`, работающая по принципу `@Override`. Она обозначит замысел и не даст определить второй абстрактный метод в интерфейсе.

Интерфейс может включать сколько угодно `default` методов и при этом оставаться функциональным, потому что `default` методы - не абстрактные.

[к оглавлению](#java-8)

## Для чего нужны функциональные интерфейсы `Function<T,R>`, `DoubleFunction<R>`, `IntFunction<R>` и `LongFunction<R>`?
__`Function<T, R>`__ - интерфейс, с помощью которого реализуется функция, получающая на вход экземпляр класса `T` и возвращающая на выходе экземпляр класса `R`.

Методы по умолчанию могут использоваться для построения цепочек вызовов (`compose`, `andThen`).

```java
Function<String, Integer> toInteger = Integer::valueOf;
Function<String, String> backToString = toInteger.andThen(String::valueOf);
backToString.apply("123");     // "123"
```

+ `DoubleFunction<R>` - функция получающая на вход `Double` и возвращающая на выходе экземпляр класса `R`;
+ `IntFunction<R>` - функция получающая на вход `Integer` и возвращающая на выходе экземпляр класса `R`;
+ `LongFunction<R>` - функция получающая на вход `Long` и возвращающая на выходе экземпляр класса `R`.

[к оглавлению](#java-8)

## Для чего нужны функциональные интерфейсы `UnaryOperator<T>`, `DoubleUnaryOperator`, `IntUnaryOperator` и `LongUnaryOperator`?
__`UnaryOperator<T>` (унарный оператор)__ принимает в качестве параметра объект типа `T`, выполняет над ними операции и возвращает результат операций в виде объекта типа `T`:

```java
UnaryOperator<Integer> operator = x -> x * x;
System.out.println(operator.apply(5)); // 25
```

+ `DoubleUnaryOperator` - унарный оператор получающий на вход `Double`;
+ `IntUnaryOperator` - унарный оператор получающий на вход `Integer`;
+ `LongUnaryOperator` - унарный оператор получающий на вход `Long`.

[к оглавлению](#java-8)

## Для чего нужны функциональные интерфейсы `BinaryOperator<T>`, `DoubleBinaryOperator`, `IntBinaryOperator` и `LongBinaryOperator`?
__`BinaryOperator<T>` (бинарный оператор)__ - интерфейс, с помощью которого реализуется функция, получающая на вход два экземпляра класса `T` и возвращающая на выходе экземпляр класса `T`.
```java
BinaryOperator<Integer> operator = (a, b) -> a + b;
System.out.println(operator.apply(1, 2)); // 3
```

+ `DoubleBinaryOperator` - бинарный оператор получающий на вход `Double`;
+ `IntBinaryOperator` - бинарный оператор получающий на вход `Integer`;
+ `LongBinaryOperator` - бинарный оператор получающий на вход `Long`.

[к оглавлению](#java-8)

## Для чего нужны функциональные интерфейсы `Predicate<T>`, `DoublePredicate`, `IntPredicate` и `LongPredicate`?
__`Predicate<T>` (предикат)__ - интерфейс, с помощью которого реализуется функция, получающая на вход экземпляр класса `T` и возвращающая на выходе значение типа `boolean`. 

Интерфейс содержит различные методы по умолчанию, позволяющие строить сложные условия (`and`, `or`, `negate`).

```java
Predicate<String> predicate = (s) -> s.length() > 0;
predicate.test("foo"); // true
predicate.negate().test("foo"); // false
```

+ `DoublePredicate` - предикат получающий на вход `Double`;
+ `IntPredicate` - предикат получающий на вход `Integer`;
+ `LongPredicate` - предикат получающий на вход `Long`.

[к оглавлению](#java-8)

## Для чего нужны функциональные интерфейсы `Consumer<T>`, `DoubleConsumer`, `IntConsumer` и `LongConsumer`?
__`Consumer<T>` (потребитель)__ - интерфейс, с помощью которого реализуется функция, которая получает на вход экземпляр класса `T`, производит с ним некоторое действие и ничего не возвращает.

```java
Consumer<String> hello = (name) -> System.out.println("Hello, " + name);
hello.accept("world");
```

+ `DoubleConsumer` - потребитель получающий на вход `Double`;
+ `IntConsumer` - потребитель получающий на вход `Integer`;
+ `LongConsumer` - потребитель получающий на вход `Long`.

[к оглавлению](#java-8)

## Для чего нужны функциональные интерфейсы `Supplier<T>`,  `BooleanSupplier`, `DoubleSupplier`, `IntSupplier` и `LongSupplier`?
__`Supplier<T>` (поставщик)__ - интерфейс, с помощью которого реализуется функция, ничего не принимающая на вход, но возвращающая на выход результат класса `T`;

```java
Supplier<LocalDateTime> now = LocalDateTime::now;
now.get();
```

+ `DoubleSupplier` - поставщик возвращающий `Double`;
+ `IntSupplier` - поставщик возвращающий `Integer`;
+ `LongSupplier` - поставщик возвращающий `Long`.

[к оглавлению](#java-8)

## Для чего нужен функциональный интерфейс `BiConsumer<T,U>`?
__`BiConsumer<T,U>`__ представляет собой операцию, которая принимает два аргумента классов `T` и `U` производит с ними некоторое действие и ничего не возвращает.

[к оглавлению](#java-8)

## Для чего нужен функциональный интерфейс `BiFunction<T,U,R>`?
__`BiFunction<T,U,R>`__ представляет собой операцию, которая принимает два аргумента классов `T` и `U` и возвращающая результат класса `R`.

[к оглавлению](#java-8)

## Для чего нужен функциональный интерфейс `BiPredicate<T,U>`?
__`BiPredicate<T,U>`__ представляет собой операцию, которая принимает два аргумента классов `T` и `U` и возвращающая результат типа `boolean`. 

[к оглавлению](#java-8)

## Для чего нужны функциональные интерфейсы вида `_To_Function`?
+ `DoubleToIntFunction` - операция принимающая аргумент класса `Double` и возвращающая результат типа `Integer`;
+ `DoubleToLongFunction` - операция принимающая аргумент класса `Double` и возвращающая результат типа `Long`;
+ `IntToDoubleFunction` - операция принимающая аргумент класса `Integer` и возвращающая результат типа `Double`; 
+ `IntToLongFunction` - операция принимающая аргумент класса `Integer` и возвращающая результат типа `Long`;
+ `LongToDoubleFunction` - операция принимающая аргумент класса `Long` и возвращающая результат типа `Double`;
+ `LongToIntFunction` - операция принимающая аргумент класса `Long` и возвращающая результат типа `Integer`.

[к оглавлению](#java-8)

## Для чего нужны функциональные интерфейсы `ToDoubleBiFunction<T,U>`, `ToIntBiFunction<T,U>` и `ToLongBiFunction<T,U>`?
+ `ToDoubleBiFunction<T,U>` - операция принимающая два аргумента классов `T` и `U` и возвращающая результат типа `Double`;
+ `ToLongBiFunction<T,U>` - операция принимающая два аргумента классов `T` и `U` и возвращающая результат типа `Long`;
+ `ToIntBiFunction<T,U>`  - операция принимающая два аргумента классов `T` и `U` и возвращающая результат типа `Integer`.

[к оглавлению](#java-8)

## Для чего нужны функциональные интерфейсы `ToDoubleFunction<T>`, `ToIntFunction<T>` и `ToLongFunction<T>`?
+ `ToDoubleFunction<T>` - операция принимающая аргумент класса `T` и возвращающая результат типа `Double`;
+ `ToLongFunction<T>` - операция принимающая аргумент класса `T` и возвращающая результат типа `Long`;
+ `ToIntFunction<T>` - операция принимающая аргумент класса `T` и возвращающая результат типа `Integer`.

[к оглавлению](#java-8)

## Для чего нужны функциональные интерфейсы `ObjDoubleConsumer<T>`, `ObjIntConsumer<T>` и `ObjLongConsumer<T>`?
+ `ObjDoubleConsumer<T>` - операция, которая принимает два аргумента классов `T` и `Double`, производит с ними некоторое действие и ничего не возвращает;
+ `ObjLongConsumer<T>` - операция, которая принимает два аргумента классов `T` и `Long`, производит с ними некоторое действие и ничего не возвращает;
+ `ObjIntConsumer<T>` - операция, которая принимает два аргумента классов `T` и `Integer`, производит с ними некоторое действие и ничего не возвращает.

[к оглавлению](#java-8)

## Что такое `StringJoiner`?
Класс `StringJoiner` используется, чтобы создать последовательность строк, разделенных разделителем с возможностью присоединить к полученной строке префикс и суффикс:

```java
StringJoiner joiner = new StringJoiner(".", "prefix-", "-suffix");
for (String s : "Hello the brave world".split(" ")) {
    joiner.add(s);
}
System.out.println(joiner); //prefix-Hello.the.brave.world-suffix
```

[к оглавлению](#java-8)

## Что такое `default` методы интрефейса?
Java 8 позволяет добавлять неабстрактные реализации методов в интерфейс, используя ключевое слово `default`:

```java
interface Example {
    int process(int a);
    default void show() {
        System.out.println("default show()");
    }
}
```

+ Если класс реализует интерфейс, он может, но не обязан, реализовать методы по-умолчанию, уже реализованные в интерфейсе. Класс наследует реализацию по умолчанию.
+ Если некий класс реализует несколько интерфейсов, которые имеют одинаковый метод по умолчанию, то класс должен реализовать метод с совпадающей сигнатурой самостоятельно. Ситуация аналогична, если один интерфейс имеет метод по умолчанию, а в другом этот же метод является абстрактным - никакой реализации по умолчанию классом не наследуется.
+ Метод по умолчанию не может переопределить метод класса `java.lang.Object`.
+ Помогают реализовывать интерфейсы без страха нарушить работу других классов.
+ Позволяют избежать создания служебных классов, так как все необходимые методы могут быть представлены в самих интерфейсах.
+ Дают свободу классам выбрать метод, который нужно переопределить.
+ Одной из основных причин внедрения методов по умолчанию является возможность коллекций в Java 8 использовать лямбда-выражения.

[к оглавлению](#java-8)

## Как вызывать `default` метод интерфейса в реализующем этот интерфейс классе?
Используя ключевое слово `super` вместе с именем интерфейса:

```java
interface Paper {
    default void show() {
        System.out.println("default show()");
    }
}

class Licence implements Paper {
    public void show() {
        Paper.super.show();
    }
}
```

[к оглавлению](#java-8)

## Что такое `static` метод интерфейса?
Статические методы интерфейса похожи на методы по умолчанию, за исключением того, что для них отсутствует возможность переопределения в классах, реализующих интерфейс.

+ Статические методы в интерфейсе являются частью интерфейса без возможности использовать их для объектов класса реализации;
+ Методы класса `java.lang.Object` нельзя переопределить как статические;
+ Статические методы в интерфейсе используются для обеспечения вспомогательных методов, например, проверки на null, сортировки коллекций и т.д.

[к оглавлению](#java-8)

## Как вызывать `static` метод интерфейса?
Используя имя интерфейса:

```java
interface Paper {
    static void show() {
        System.out.println("static show()");
    }
}

class Licence {
    public void showPaper() {
        Paper.show();
    }
}
```

[к оглавлению](#java-8)

## Что такое `Optional`?
Опциональное значение `Optional` — это контейнер для объекта, который может содержать или не содержать значение `null`. Такая обёртка является удобным средством предотвращения `NullPointerException`, т.к.
имеет некоторые функции высшего порядка, избавляющие от добавления повторяющихся `if null/notNull` проверок:

```java
Optional<String> optional = Optional.of("hello");

optional.isPresent(); // true
optional.ifPresent(s -> System.out.println(s.length())); // 5
optional.get(); // "hello"
optional.orElse("ops..."); // "hello"
```

[к оглавлению](#java-8)

## Что такое `Stream`?
Интерфейс `java.util.Stream` представляет собой последовательность элементов, над которой можно производить различные операции.

Операции над стримами бывают или _промежуточными (intermediate)_ или _конечными (terminal)_. Конечные операции возвращают результат определенного типа, а промежуточные операции возвращают тот же стрим. Таким образом вы можете строить цепочки из несколько операций над одним и тем же стримом. 

У стрима может быть сколько угодно вызовов промежуточных операций и последним вызов конечной операции. При этом все промежуточные операции выполняются лениво и пока не будет вызвана конечная операция никаких действий на самом деле не происходит (похоже на создание объекта `Thread` или `Runnable`, без вызова `start()`).

Стримы создаются на основе источников каких-либо, например классов из `java.util.Collection`. 

Ассоциативные массивы (maps), например `HashMap`, не поддерживаются.

Операции над стримами могут выполняться как последовательно, так и параллельно.

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

Кроме универсальных объектных существуют особые виды стримов для работы с примитивными типами данных `int`, `long` и `double`: `IntStream`, `LongStream` и `DoubleStream`. Эти примитивные стримы работают так же, как и обычные объектные, но со следующими отличиями: 

+ используют специализированные лямбда-выражения, например `IntFunction` или `IntPredicate` вместо `Function` и `Predicate`; 
+ поддерживают дополнительные конечные операции `sum()`, `average()`, `mapToObj()`.

[к оглавлению](#java-8)

## Какие существуют способы создания стрима?
1. Из коллекции:
```java 
Stream<String> fromCollection = Arrays.asList("x", "y", "z").stream();
```
2. Из набора значений:
```java 
Stream<String> fromValues = Stream.of("x", "y", "z");
```
3. Из массива:
```java 
Stream<String> fromArray = Arrays.stream(new String[]{"x", "y", "z"});
```
4. Из файла (каждая строка в файле будет отдельным элементом в стриме):
```java 
Stream<String> fromFile = Files.lines(Paths.get("input.txt"));
```
5. Из строки:
```java 
IntStream fromString = "0123456789".chars();
```
6. С помощью `Stream.builder()`:
```java 
Stream<String> fromBuilder = Stream.builder().add("z").add("y").add("z").build();
```
7. С помощью `Stream.iterate()` (бесконечный):
```java 
Stream<Integer> fromIterate = Stream.iterate(1, n -> n + 1);
```
8. С помощью `Stream.generate()` (бесконечный):
```java 
Stream<String> fromGenerate = Stream.generate(() -> "0");
```

[к оглавлению](#java-8)

## В чем разница между `Collection` и `Stream`?
Коллекции позволяют работать с элементами по-отдельности, тогда как стримы так делать не позволяют, но вместо этого предоставляют возможность выполнять функции над данными как над одним целым.

Также стоит отметить важность самой концепции сущностей: `Collection` - это прежде всего воплощение _Структуры Данных_. Например `Set` не просто хранит в себе элементы, он реализует идею множества с уникальными элементами,
тогда как `Stream`, это прежде всего абстракция необходимая для реализации _конвеера вычислений_, собственно поэтому, результатом работы конвеера являются те или иные _Структуры Данных_ или же результаты проверок/поиска и т.п. 

[к оглавлению](#java-8)

## Для чего нужен метод `collect()` в стримах?
Метод `collect()` является конечной операцией, которая используется для представление результата в виде коллекции или какой-либо другой структуры данных.

`collect()` принимает на вход `Collector<Тип_источника, Тип_аккумулятора, Тип_результата>`, который содержит четыре этапа: _supplier_ - инициализация аккумулятора, _accumulator_ - обработка каждого элемента, _combiner_ - соединение двух аккумуляторов при параллельном выполнении, _[finisher]_ - необязательный метод последней обработки аккумулятора. В Java 8 в классе `Collectors` реализовано несколько распространённых коллекторов:

+ `toList()`, `toCollection()`, `toSet()` - представляют стрим в виде списка, коллекции или множества;
+ `toConcurrentMap()`, `toMap()` - позволяют преобразовать стрим в `Map`;
+ `averagingInt()`, `averagingDouble()`, `averagingLong()` - возвращают среднее значение;
+ `summingInt()`, `summingDouble()`, `summingLong()` - возвращает сумму;
+ `summarizingInt()`, `summarizingDouble()`, `summarizingLong()` - возвращают `SummaryStatistics` с разными агрегатными значениями;
+ `partitioningBy()` - разделяет коллекцию на две части по соответствию условию и возвращает их как `Map<Boolean, List>`;
+ `groupingBy()` - разделяет коллекцию на несколько частей и возвращает `Map<N, List<T>>`;
+ `mapping()` - дополнительные преобразования значений для сложных `Collector`-ов.

Так же существует возможность создания собственного коллектора через `Collector.of()`:

```java
Collector<String, List<String>, List<String>> toList = Collector.of(
    ArrayList::new,
    List::add,
    (l1, l2) -> { l1.addAll(l2); return l1; }
);
```

[к оглавлению](#java-8)

## Для чего в стримах применяются методы `forEach()` и `forEachOrdered()`?
+ `forEach()` применяет функцию к каждому объекту стрима, порядок при параллельном выполнении не гарантируется;
+ `forEachOrdered()` применяет функцию к каждому объекту стрима с сохранением порядка элементов.

[к оглавлению](#java-8)

## Для чего в стримах предназначены методы `map()` и `mapToInt()`, `mapToDouble()`, `mapToLong()`?
Метод `map()` является промежуточной операцией, которая заданным образом преобразует каждый элемент стрима.

`mapToInt()`, `mapToDouble()`, `mapToLong()` - аналоги `map()`, возвращающие соответствующий числовой стрим (то есть стрим из числовых примитивов):

```java
Stream
    .of("12", "22", "4", "444", "123")
    .mapToInt(Integer::parseInt)
    .toArray(); //[12, 22, 4, 444, 123]
```
Кроме того, `map()` может принимать в себя функциональный интерфейс Functional.
[к оглавлению](#java-8)

## Какова цель метода `filter()` в стримах?
Метод `filter()` является промежуточной операцией принимающей предикат, который фильтрует все элементы, возвращая только те, что соответствуют условию.

[к оглавлению](#java-8)

## Для чего в стримах предназначен метод `limit()`?
Метод `limit()` является промежуточной операцией, которая позволяет ограничить выборку определенным количеством первых элементов.

[к оглавлению](#java-8)

## Для чего в стримах предназначен метод `sorted()`?
Метод `sorted()` является промежуточной операцией, которая позволяет сортировать значения либо в натуральном порядке, либо задавая `Comparator`.

Порядок элементов в исходной коллекции остается нетронутым - `sorted()` всего лишь создает его отсортированное представление.

[к оглавлению](#java-8)

## Для чего в стримах предназначены методы `flatMap()`, `flatMapToInt()`, `flatMapToDouble()`, `flatMapToLong()`?
Метод `flatMap()` похож на map, но может преобразовывать из нескольких элементов (стримов, массивов, коллекций) один. Например можно преобразовать двумерный массив в одномерный:

```java
int[][] arr = {{1,2}, {5,6}, {3,4}};
Arrays.stream(arr).flatMapToInt(x -> Arrays.stream(x)).forEach(System.out::println);
```

Или из стрима листов получить один стрим:
```java
public static void main(String[] args) {
    List<Human> humans = asList(
            new Human("Sam", asList("Buddy", "Lucy")),
            new Human("Bob", asList("Frankie", "Rosie")),
            new Human("Marta", asList("Simba", "Tilly")));
 
    List<String> petNames = humans.stream()
            .map(human -> human.getPets()) //преобразовываем Stream<Human> в Stream<List<Pet>>
            .flatMap(pets -> pets.stream())//"разворачиваем" Stream<List<Pet>> в Stream<Pet>
            .collect(Collectors.toList());
 
    System.out.println(petNames); // output [Buddy, Lucy, Frankie, Rosie, Simba, Tilly]
}
```
Или разбить строку по буквам:
```java
Stream
    .of("H e l l o", "w o r l d !")
    .flatMap((p) -> Arrays.stream(p.split(" ")))
    .toArray(String[]::new);//["H", "e", "l", "l", "o", "w", "o", "r", "l", "d", "!"]
```
`flatMapToInt()`, `flatMapToDouble()`, `flatMapToLong()` - это аналоги `flatMap()`, возвращающие соответствующий числовой стрим.

[к оглавлению](#java-8)

## Расскажите о параллельной обработке в Java 8.
Стримы могут быть последовательными и параллельными. Операции над последовательными стримами выполняются в одном потоке процессора, над параллельными — используя несколько потоков процессора. Параллельные стримы используют общий `ForkJoinPool` доступный через статический `ForkJoinPool.commonPool()` метод. При этом, если окружение не является многоядерным, то поток будет выполняться как последовательный. Фактически применение параллельных стримов сводится к тому, что данные в стримах будут разделены на части, каждая часть обрабатывается на отдельном ядре процессора, и в конце эти части соединяются, и над ними выполняются конечные операции.

Для создания параллельного потока из коллекции можно также использовать метод `parallelStream()` интерфейса `Collection`. 

Чтобы сделать обычный последовательный стрим параллельным, надо вызвать у объекта `Stream` метод `parallel()`. Метод `isParallel()` позволяет узнать является ли стрим параллельным. 

С помощью, методов `parallel()` и `sequential()` можно определять какие операции могут быть параллельными, а какие только последовательными. Так же из любого последовательного стрима можно сделать параллельный и наоборот: 

```java
collection
.stream()
.peek(...) // операция последовательна
.parallel()
.map(...) // операция может выполняться параллельно,
.sequential()
.reduce(...) // операция снова последовательна 
```

Как правило, элементы передаются в стрим в том же порядке, в котором они определены в источнике данных. При работе с параллельными стримами система сохраняет порядок следования элементов. Исключение составляет метод `forEach()`, который может выводить элементы в произвольном порядке. И чтобы сохранить порядок следования, необходимо применять метод `forEachOrdered()`.

Критерии, которые могут повлиять на производительность в параллельных стримах:

+ Размер данных - чем больше данных, тем сложнее сначала разделять данные, а потом их соединять.
+ Количество ядер процессора. Теоретически, чем больше ядер в компьютере, тем быстрее программа будет работать. Если на машине одно ядро, нет смысла применять параллельные потоки.
+ Чем проще структура данных, с которой работает поток, тем быстрее будут происходить операции. Например, данные из `ArrayList` легко использовать, так как структура данной коллекции предполагает последовательность несвязанных данных. А вот коллекция типа `LinkedList` - не лучший вариант, так как в последовательном списке все элементы связаны с предыдущими/последующими. И такие данные трудно распараллелить.
+ Над данными примитивных типов операции будут производиться быстрее, чем над объектами классов.
+ Крайне не рекомендуется использовать параллельные стримы для сколько-нибудь долгих операций (например сетевых соединений), так как все параллельные стримы работают c одним `ForkJoinPool`, то такие долгие операции могут остановить работу всех параллельных стримов в JVM из-за отсутствия доступных потоков в пуле, т.е. параллельные стримы стоит использовать лишь для коротких операций, где счет идет на миллисекунды, но не для тех где счет может идти на секунды и минуты;
+ Сохранение порядка в параллельных стримах увеличивает издержки при выполнении и если порядок не важен, то имеется возможность отключить его сохранение и тем самым увеличить производительность, использовав промежуточную операцию `unordered()`:

```java
collection.parallelStream()
    .sorted()
    .unordered()
    .collect(Collectors.toList());
```

[к оглавлению](#java-8)

## Какие конечные методы работы со стримами вы знаете?
+ `findFirst()` возвращает первый элемент;
+ `findAny()` возвращает любой подходящий элемент;
+ `collect()` представление результатов в виде коллекций и других структур данных;
+ `count()` возвращает количество элементов;
+ `anyMatch()` возвращает `true`, если условие выполняется хотя бы для одного элемента;
+ `noneMatch()` возвращает `true`, если условие не выполняется ни для одного элемента;
+ `allMatch()` возвращает `true`, если условие выполняется для всех элементов;
+ `min()` возвращает минимальный элемент, используя в качестве условия `Comparator`;
+ `max()` возвращает максимальный элемент, используя в качестве условия `Comparator`;
+ `forEach()` применяет функцию к каждому объекту (порядок при параллельном выполнении не гарантируется);
+ `forEachOrdered()` применяет функцию к каждому объекту с сохранением порядка элементов;
+ `toArray()` возвращает массив значений;
+ `reduce()`позволяет выполнять агрегатные функции и возвращать один результат.

Для числовых стримов дополнительно доступны:

+ `sum()` возвращает сумму всех чисел;
+ `average()` возвращает среднее арифметическое всех чисел.

[к оглавлению](#java-8)

## Какие промежуточные методы работы со стримами вы знаете?
+ `filter()` отфильтровывает записи, возвращая только записи, соответствующие условию;
+ `skip()` позволяет пропустить определённое количество элементов в начале;
+ `distinct()` возвращает стрим без дубликатов (для метода `equals()`);
+ `map()` преобразует каждый элемент;
+ `peek()` возвращает тот же стрим, применяя к каждому элементу функцию;
+ `limit()` позволяет ограничить выборку определенным количеством первых элементов;
+ `sorted()` позволяет сортировать значения либо в натуральном порядке, либо задавая `Comparator`;
+ `mapToInt()`, `mapToDouble()`, `mapToLong()` - аналоги `map()` возвращающие стрим числовых примитивов;
+ `flatMap()`, `flatMapToInt()`, `flatMapToDouble()`, `flatMapToLong()` - похожи на `map()`, но могут создавать из одного элемента несколько.

Для числовых стримов дополнительно доступен метод `mapToObj()`, который преобразует числовой стрим обратно в объектный.

[к оглавлению](#java-8)

## Как вывести на экран 10 случайных чисел, используя `forEach()`?
```java
(new Random())
    .ints()
    .limit(10)
    .forEach(System.out::println);
```

[к оглавлению](#java-8)

## Как можно вывести на экран уникальные квадраты чисел используя метод `map()`?
```java
Stream
    .of(1, 2, 3, 2, 1)
    .map(s -> s * s)
    .distinct()
    .collect(Collectors.toList())
    .forEach(System.out::println);
```

[к оглавлению](#java-8)

## Как вывести на экран количество пустых строк с помощью метода `filter()`?
```java
System.out.println(
    Stream
        .of("Hello", "", ", ", "world", "!")
        .filter(String::isEmpty)
        .count());
```

[к оглавлению](#java-8)

## Как вывести на экран 10 случайных чисел в порядке возрастания?
```java
(new Random())
    .ints()
    .limit(10)
    .sorted()
    .forEach(System.out::println);
```

[к оглавлению](#java-8)

## Как найти максимальное число в наборе?
```java
Stream
    .of(5, 3, 4, 55, 2)
    .mapToInt(a -> a)
    .max()
    .getAsInt(); //55
```

[к оглавлению](#java-8)

## Как найти минимальное число в наборе?
```java
Stream
    .of(5, 3, 4, 55, 2)
    .mapToInt(a -> a)
    .min()
    .getAsInt(); //2
```
[к оглавлению](#java-8)

## Как получить сумму всех чисел в наборе?
```java
Stream
    .of(5, 3, 4, 55, 2)
    .mapToInt()
    .sum(); //69
```
[к оглавлению](#java-8)

## Как получить среднее значение всех чисел?
```java
Stream
    .of(5, 3, 4, 55, 2)
    .mapToInt(a -> a)
    .average()
    .getAsDouble(); //13.8
```
[к оглавлению](#java-8)

## Какие дополнительные методы для работы с ассоциативными массивами (maps) появились в Java 8?
+ `putIfAbsent()` добавляет пару «ключ-значение», только если ключ отсутствовал:

`map.putIfAbsent("a", "Aa");`

+ `forEach()` принимает функцию, которая производит операцию над каждым элементом:

`map.forEach((k, v) -> System.out.println(v));`

+ `compute()` создаёт или обновляет текущее значение на полученное в результате вычисления (возможно использовать ключ и текущее значение):

`map.compute("a", (k, v) -> String.valueOf(k).concat(v)); //["a", "aAa"]`

+ `computeIfPresent()` если ключ существует, обновляет текущее значение на полученное в результате вычисления (возможно использовать ключ и текущее значение):

`map.computeIfPresent("a", (k, v) -> k.concat(v));`

+ `computeIfAbsent()` если ключ отсутствует, создаёт его со значением, которое вычисляется (возможно использовать ключ):

`map.computeIfAbsent("a", k -> "A".concat(k)); //["a","Aa"]`

+ `getOrDefault()` в случае отсутствия ключа, возвращает переданное значение по-умолчанию:

`map.getOrDefault("a", "not found");`

+ `merge()` принимает ключ, значение и функцию, которая объединяет передаваемое и текущее значения. Если под заданным ключем значение отсутствует, то записывает туда передаваемое значение. 

`map.merge("a", "z", (value, newValue) -> value.concat(newValue)); //["a","Aaz"]`

[к оглавлению](#java-8)

## Что такое `LocalDateTime`?
`LocalDateTime` объединяет вместе `LocaleDate` и `LocalTime`, содержит дату и время в календарной системе ISO-8601 без привязки к часовому поясу. Время хранится с точностью до наносекунды. Содержит множество удобных методов, таких как plusMinutes, plusHours, isAfter, toSecondOfDay и т.д.

[к оглавлению](#java-8)

## Что такое `ZonedDateTime`?
`java.time.ZonedDateTime` — аналог `java.util.Calendar`, класс с самым полным объемом информации о временном контексте в календарной системе ISO-8601. Включает временную зону, поэтому все операции с временными сдвигами этот класс проводит с её учётом.

[к оглавлению](#java-8)

## Как получить текущую дату с использованием Date Time API из Java 8?
```java
LocalDate.now();
```

[к оглавлению](#java-8)

## Как добавить 1 неделю, 1 месяц, 1 год, 10 лет к текущей дате с использованием Date Time API?
```java
LocalDate.now().plusWeeks(1);
LocalDate.now().plusMonths(1);
LocalDate.now().plusYears(1);
LocalDate.now().plus(1, ChronoUnit.DECADES);
```

[к оглавлению](#java-8)

## Как получить следующий вторник используя Date Time API?
```java
LocalDate.now().with(TemporalAdjusters.next(DayOfWeek.TUESDAY));
```

[к оглавлению](#java-8)

## Как получить вторую субботу текущего месяца используя Date Time API?
```java
LocalDate
    .of(LocalDate.now().getYear(), LocalDate.now().getMonth(), 1)
    .with(TemporalAdjusters.nextOrSame(DayOfWeek.SATURDAY))
    .with(TemporalAdjusters.next(DayOfWeek.SATURDAY));
```

[к оглавлению](#java-8)

## Как получить текущее время с точностью до миллисекунд используя Date Time API?
```java
new Date().toInstant();
```

[к оглавлению](#java-8)

## Как получить текущее время по местному времени с точностью до миллисекунд используя Date Time API?
```java
LocalDateTime.ofInstant(new Date().toInstant(), ZoneId.systemDefault());
```

[к оглавлению](#java-8)

## Как определить повторяемую аннотацию?
Чтобы определить повторяемую аннотацию, необходимо создать аннотацию-контейнер для списка повторяемых аннотаций и обозначить повторяемую мета-аннотацией `@Repeatable`:

```java
@interface Schedulers
{
    Scheduler[] value();
}

@Repeatable(Schedulers.class)
@interface Scheduler
{
    String birthday() default "Jan 8 1935";
}
```

[к оглавлению](#java-8)

## Что такое `Nashorn`?
__Nashorn__ - это движок JavaScript, разрабатываемый на Java компанией Oracle. Призван дать возможность встраивать код JavaScript в приложения Java. В сравнении с _Rhino_, который поддерживается Mozilla Foundation, Nashorn обеспечивает от 2 до 10 раз более высокую производительность, так как он компилирует код и передает байт-код виртуальной машине Java непосредственно в памяти. Nashorn умеет компилировать код JavaScript и генерировать классы Java, которые загружаются специальным загрузчиком. Так же возможен вызов кода Java прямо из JavaScript.

[к оглавлению](#java-8)

## Что такое `jjs`?
`jjs` это утилита командной строки, которая позволяет исполнять программы на языке JavaScript прямо в консоли.

[к оглавлению](#java-8)

## Какой класс появился в Java 8 для кодирования/декодирования данных?
`Base64` - потокобезопасный класс, который реализует кодировщик и декодировщик данных, используя схему кодирования base64 согласно _RFC 4648_ и _RFC 2045_.

Base64 содержит 6 основных методов:

`getEncoder()`/`getDecoder()` - возвращает кодировщик/декодировщик base64, соответствующий стандарту _RFC 4648_;
`getUrlEncoder()`/`getUrlDecoder()` - возвращает URL-safe кодировщик/декодировщик base64, соответствующий стандарту _RFC 4648_;
`getMimeEncoder()`/`getMimeDecoder()` - возвращает MIME кодировщик/декодировщик, соответствующий стандарту _RFC 2045_.

[к оглавлению](#java-8)

## Как создать Base64 кодировщик и декодировщик?
```java
// Encode
String b64 = Base64.getEncoder().encodeToString("input".getBytes("utf-8")); //aW5wdXQ==
// Decode
new String(Base64.getDecoder().decode("aW5wdXQ=="), "utf-8"); //input
```

[к оглавлению](#java-8)

# Источники
+ [Хабрахабр - Новое в Java 8](https://habrahabr.ru/post/216431/)
+ [Хабрахабр - Шпаргалка Java программиста 4. Java Stream API](https://habrahabr.ru/company/luxoft/blog/270383/)
+ [METANIT.COM](http://metanit.com/java/tutorial/9.1.php)
+ [javadevblog.com](http://javadevblog.com/interfejsy-v-java-8-staticheskie-metody-metody-po-umolchaniyu-funktsional-ny-e-interfejsy.html)

[Вопросы для собеседования](README.md)
