16. Java 8 Flashcards

1
Q

Что такое реализация по-умолчанию в интерфейсах?

A

В JDK 8 была добавлена такая функциональность как методы по умолчанию. И теперь интерфейсы кроме определения методов могут иметь их реализацию по умолчанию, которая используется, если класс, реализующий данный интерфейс, не реализует метод.

Метод по умолчанию - это обычный метод без модификаторов, который помечается ключевым словом default. Затем в классе нам необязательно этот метод реализовать, хотя мы можем его и переопределить
default void methodName () {/ * body * /}
Важные моменты о методах интерфейса Java по умолчанию:
- Методы интерфейса Java по умолчанию помогут нам в расширении интерфейсов, не боясь нарушать классы реализации.
- Методы по умолчанию для интерфейса Java позволяют устранить различия между интерфейсами и абстрактными классами.
- Методы по умолчанию интерфейса Java 8 помогут нам избежать использования служебных классов, например, все методы класса Collections могут быть предоставлены в самих интерфейсах.
- Методы интерфейса Java по умолчанию помогут нам в удалении базовых классов реализации, мы можем предоставить реализацию по умолчанию, и классы реализации могут выбрать, какой из них переопределить.
- Одной из основных причин введения методов по умолчанию в интерфейсах является усовершенствование API коллекций в Java 8 для поддержки лямбда-выражений.
- Если какой-либо класс в иерархии имеет метод с такой же сигнатурой, то методы по умолчанию становятся неактуальными.
- Метод по умолчанию не может переопределить метод из java.lang.Object. Рассуждения очень просты, потому что Object является базовым классом для всех классов Java. Таким образом, даже если у нас есть методы класса Object, определенные как методы по умолчанию в интерфейсах, это будет бесполезно, потому что метод класса Object всегда будет использоваться. Вот почему во избежание путаницы у нас не может быть методов по умолчанию, которые переопределяют методы класса Object.
- Методы интерфейса Java по умолчанию также называются методами защитника или методами виртуального расширения.

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

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Что такое лямбда-выражения?

A

Смысл - сокращение кода и синтаксического сахара, когда мы уходим от анонимных классов (хотя анонимные классы и лямбды различны).

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

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

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

interface Operationable {
int calculate(int x, int y);
}
Operationable operation = (x, y) -> x + y;

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

Лямбда-выражение может использовать переменные, которые объявлены во вне в более общей области видимости - на уровне класса или метода, в котором лямбда-выражение определено. Однако в зависимости от того, как и где определены переменные, могут различаться способы их использования в лямбдах.
Переменные объявленные на уровне класса, мы можем получить и даже изменить. в лямбда-выражении.
Локальные переменные уровня метода мы также может использовать в лямбдах, но изменять их значение мы уже не сможем. Если мы попробуем это сделать, то среда разработки может нам высветить ошибку и то, что такую переменную надо пометить с помощью ключевого слова final, то есть сделать константой: final int n=70;. Однако это необязательно. (должно быть файнел или эффективели файнел)

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

(арг1, арг2…) -> { тело }
(тип1 арг1, тип2 арг2…) -> { тело }

List arr = asList(1, 32, 6, 10, -1, -12);
arr.sort((o1, o2) -> Integer.compare(o1, o2));

Thread t = new Thread(() -> System.out.println(Thread.currentThread().getName()));
t.start();
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Что такое функциональный интерфейс @FunctionalInterface?

A

Это аннотация. Ставится перед интерфейсом и имеет “защиту от дурака” (иначе ошибка компилятора), а-ля оверрайд-аннотации.

Функциональный интерфейс в Java – это интерфейс, который содержит только 1 абстрактный! метод. Основное назначение – использование в лямбда выражениях и method reference.

Наличие 1 абстрактного метода - это единственное условие, таким образом функциональный интерфейс может содержать так же default и static методы.
Но оказывается есть один тонкий момент, описанный в Java Language Specification: “interfaces do not inherit from Object, but rather implicitly declare many of the same methods as Object.”
Это означает, что функциональные интерфейсы могут содержать дополнительно абстрактные методы, определенные в классе Object.
@FunctionalInterface
public interface Comparator {
int compare(T o1, T o2);
boolean equals(Object obj);
// другие default или static методы
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Расскажите про интерфейс Predicate?

A

Это все - встроенные интерйесы, чтобы программисты не изобретали велосипед.

Predicate встроенный обобщенный функциональный интерфейс, добавленный в Java SE 8 в пакет java.util.function., который принимает на вход значение, проверяет состояние и возвращает boolean значение в качестве результата.

T -> boolean

__(метод тест) - добавить__

Predicate интерфейс содержит методы по умолчанию:

default Predicate and(Predicate super T> other);
default Predicate or(Predicate super T> other);
default Predicate negate();
static Predicate isEqual(Object targetRef);

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

Расскажите про интерфейс Function?

A

Function - это встроенный обобщенный функциональный интерфейс, добавленный в Java SE 8 в пакет java.util.function.

Принимает значение в качестве аргумента одного типа и возвращает другое значение. Часто используется для преобразования одного значения в другое:

@FunctionalInterface
public interface Function {
R apply(T t);
}

T -> R

Методы по умолчанию интерфейса Function для построения цепочек вызовов:

default Function andThen(Function super R, ? extends V> after);
default Function compose(Function super V, ? extends T> before);

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Расскажите про интерфейс Supplier?

A

Supplier - это встроенный обобщенный функциональный интерфейс, добавленный в Java SE 8 в пакет java.util.function. Входящего параметра нет. Возвращает значение, одно и тоже или разные:

@FunctionalInterface
public interface Supplier {
T get();
}

Интерфейс Supplier используется тогда, когда на вход не передаются значения, но необходимо вернуть результат. (нет аргумента, есть потребитель)

() -> T

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Расскажите про интерфейс Consumer?

A

Consumer - встроенный обобщенный функциональный интерфейс, добавленный в Java SE 8 в пакет java.util.function.

Принимает значение в качестве аргумента и ничего не возвращает:

@FunctionalInterface
public interface Consumer {
void accept(T t);
}
Consumer интерфейс используется в случае, если необходимо передать объект на вход и произвести над ним некоторые операции не возвращая результат. Самый частый случай использования этого интерфейса - это вывод на консоль.

T -> void

Consumer интерфейс (есть аргумент, нет потребителя) содержит метод по умолчанию, который возвращает составной Consumer, выполняющий последовательно действия указанные в каждом интерфейсе:

default Consumer andThen(Consumer super T> after)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

Расскажите про интерфейс Comparator?

A

to be added
вкратце - сранивать 2 элемента с помощью компейр, возвращая инт
int compare(T o1, To2)

+ куа вспомогательныйх методов:
reserved()
thenComapring(перегруженный, в т.ч. с Дабл, Инт, Лонг)
naturalOrder()

статический компейринг и пр.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Что такое Stream?

A

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

Тип java.util.Stream представляет собой последовательность элементов, над которой можно производить различные операции. Операции над потоками бывают или промежуточными (intermediate) или конечными (terminal). Конечные операции возвращают результат определенного типа, а промежуточные операции возвращают тот же поток. Таким образом вы можете строить цепочки из несколько операций над одним и тем же потоком. Поток создаются на основе источников, например типов, реализующих java.util.Collection, такие как списки или множества (ассоциативные массивы не поддерживаются). Операции над потоками могут выполняться как последовательно, так и параллельно.

Filter

Операция Filter принимает предикат, который фильтрует все элементы потока. Эта операция является промежуточной, т.е. позволяет нам вызвать другую операцию (например, forEach) над результатом. ForEach принимает функцию, которая вызывается для каждого элемента в (уже отфильтрованном) поток. ForEach является конечной операцией. Она не возращает никакого значения, поэтому дальнейший вызов потоковых операций невозможен.

stringCollection
.stream()
.filter((s) -> s.startsWith(“a”))
.forEach(System.out::println);

// “aaa2”, “aaa1”

Sorted

Операция Sorted является промежуточной операцией, которая возвращает отсортированное представление потока. Элементы сортируются в обычном порядке, если вы не предоставили свой компаратор:

stringCollection
.stream()
.sorted()
.filter((s) -> s.startsWith("a"))
.forEach(System.out::println);

// “aaa1”, “aaa2”

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

System.out.println(stringCollection);
// ddd2, aaa2, bbb1, aaa1, bbb3, ccc, bbb2, ddd1

Map

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

stringCollection
.stream()
.map(String::toUpperCase)
.sorted((a, b) -> b.compareTo(a))
.forEach(System.out::println);

// “DDD2”, “DDD1”, “CCC”, “BBB3”, “BBB2”, “AAA2”, “AAA1”

Match

Для проверки, удовлетворяет ли поток заданному предикату, используются различные операции сопоставления (match). Все операции сопоставления являются конечными и возвращают результат типа boolean.

boolean anyStartsWithA =
stringCollection
.stream()
.anyMatch((s) -> s.startsWith(“a”));

System.out.println(anyStartsWithA); // true

boolean allStartsWithA =
stringCollection
.stream()
.allMatch((s) -> s.startsWith(“a”));

System.out.println(allStartsWithA); // false

boolean noneStartsWithZ =
stringCollection
.stream()
.noneMatch((s) -> s.startsWith(“z”));

System.out.println(noneStartsWithZ); // true

Count

Операция Count является конечной операцией и возвращает количество элементов в потоке. Типом возвращаемого значения является long.

long startsWithB = 
stringCollection
.stream()
.filter((s) -> s.startsWith("b"))
.count();

System.out.println(startsWithB); // 3

Reduce

Эта конечная операция производит свертку элементов потока по заданной функции. Результатом является опциональное значение.

Optional reduced =
stringCollection
.stream()
.sorted()
.reduce((s1, s2) -> s1 + "#" + s2);
reduced.ifPresent(System.out::println);
// "aaa1#aaa2#bbb1#bbb2#bbb3#ccc#ddd1#ddd2"
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Что такое parallelStream?

A

Параллельные потоки

Как уже упоминалось выше, потоки могут быть последовательными и параллельными. Операции над последовательными потоками выполняются в одном потоке процессора, над параллельными — используя несколько потоков процессора.

Вызов, например:
listOfNumbers.parallelStream()
или integerList.stream().parallel()

to be added

How well did you know this?
1
Not at all
2
3
4
5
Perfectly