Вы находитесь на странице: 1из 26

1.

Инкапсуляция
Инкапсуляция - языковая конструкция, позволяющая связать данные с методами,
предназначенными для обработки этих данных

2. Управление доступом, модификаторы доступа


privet
• запрещает доступ к члену класса из других классов
• применим к полям и методам
public
• применим к полям, методам, типам (класс и т.д.)
• разрешает доступ к члену класса или типу из любого класса
по_умолчанию (модификатор отсутствует)
• применим к члену класса или типу (класс и т.д.)
• доступ к члену класса или типу возможен из любого класса, принадлежащего
тому же пакету
protected
• доступ к члену класса разрешен из классов-наследников и из классов,
принадлежащих тому же пакету
• применим к полям и методам
Градация: private < “default” < protected < public

3. Понятие класса
Класс - тип данных, задающий общее поведение для группы объектов (этого типа).
Доступ извне (из других объектов) к отдельным членам класса может быть ограничен.

4. Конструкторы и блоки инициализации


Конструктор - специальный метод класса, который вызывается во время создания
экземпляра класса.
public class Employee {
public Employee (String name) {
this.name = “Sir ” + name;
}
Блок инициализации — последовательность команд, выполняемых при создании
классов и объектов. Разработано, чтобы значительно увеличить мощность
конструктора.
public class Test {
private int num;
{
this.num = 101;}}

1
5. Наследование
Наследование - один из механизмов повторного использования кода, при котором
открытые члены класса родителя доступны классу потомку.
• В Java при наследовании классов может быть только один родитель
• Суперкласс, подкласс, базовый класс
• Иерархия наследования классов - дерево узлами, которого являются классы
• Подкласс не наследует конструкторы суперкласса
• Методы суперкласса могут быть перекрыты в подклассе
• Метод считается перекрытым в подклассе, если он имеет такую же сигнатуру,
что и в суперклассе
• Область видимости метода подкласса должна быть не ниже области видимости
метода суперкласса
public class SuperClass {}
public class SubClass extends SuperClass {}

6. Upcasting, Downcasting, оператор instanceof


Upcasting (обобщение или расширение) - это приведение к родительскому типу
простыми словами, приведение отдельного типа к одному общему типу называется
повышающим преобразованием, в то время как Downcasting (специализация или
сужение) - это приведение к дочернему типу или приведение общего типа к
индивидуальному типу.
public class Employee {}
public class Manager extends Emplyee {}
Employee emp;
Manager mgr = new Manager();
emp = mgr; // Upcasting
mgr = emp; // Compiler ERROR. Downcasting
mgr = (Manager) emp; // Downcasting
Оператор instanceof нужен, чтобы проверить, был ли объект, на который ссылается
переменная, создан на основе какого-либо класса.
<<Class Reference Variable>>instanceof <<Class Name or
Interface>>
Manager mgr = new Manager();
Employee emp = mgr;
if (emp instanceof Manager) {
mgr = (Manager)emp; }

2
7. Модификатор static
• внутренний класс
• поле
• метод
• инициализатор
• static-метод не виртуальный
• static-метод может использовать только static-поля
static String text = “FirstName”;
static void aClassMethod() {
System.out.println(text);
}
public static void main(String[] args) {
// Method body goes here
}
Зачем нужен static
• точка входа в программу - метод main()
• final static константы, экземпляры вспомогательных классов
• static методы - методы, не использующие состояние объекта, не зависящие от
состояния объекта
• static конструкторы
• static методы создающие экземпляры класса (паттерн фабрика)

8. Модификатор final
• класс
• метод
• поле (экземпляр, статическое)
• переменная
• параметр метода
Объявление переменной:
• инициализация во время объявления
final int x = 10;
• инициализация 1 раз (!) после объявления переменной
final int multiplier; // Blank final variable
/* Do something*/
multiplier = 3;
3
Объявление параметра:
public void test2(final int x) {
/* Can read x, but cannot change it */
int y = x + 11;
/* Perform other logic here... */
}
Объявление поля экземпляра:
• присвоение значения в одном из экземплярных инициализаторов или во всех
конструкторах
o если присвоение в инициализаторе, то НЕЛЬЗЯ присваивать в
конструкторах
o если не присвоено в инициализаторе, то присвоение должно быть в
конструкторе, который не вызывает другой конструктор
Объявление статического поля:
public class Test3 {
public static final int YES = 1;
public static final int NO = 2;
public static final String MSG;
static {
MSG = "I am a blank final static variable";
}
}

9. Корень иерархии типов - класс Object


Базовым классом для всех классов является Object
• Каждый объект в Java принадлежит какому-либо классу
• Каждый класс компилируется в бинарный файл .class
• Class Loader загружает определение класса из class-файла в JVM
• JVM создает объект типа java.lang.Class, который представляет двоичное
представление класса в JVM
• Класс в JVM идентифицируется полным именем и загрузчиком, который его
загрузил
• “Class - runtime descriptor of class source code” (Класс - идентификатор времени
выполнения исходного кода класса)
• НЕ все классы загружаются при старте приложения
• Класс загружается перед первым использованием
4
Cat c = new Cat();
Class catClass = c.getClass();
Class catClass = c.getClass();

10. Полиморфизм
Полиморфизм - возможность для одного и того же кода обрабатывать данные по-
разному.
В Java по умолчанию все экземплярные методы виртуальные (virtual)
Типичные ошибки
• Отсутствие полиморфизма
• Ненужное приведение типов
Пример:
public class SuperClass{
public void sayHello(){
System.out.println(“Hello!”); } }

11. Абстрактный класс, абстрактный метод


• Абстрактные классы используются как основа для создания «реальных» классов
• Нельзя создать экземпляр абстрактного класса
• Абстрактный класс может не иметь абстрактных методов
• Абстрактный класс может иметь конструкторы
public abstract class Person {
. . .
public abstract String getSummary(){
. . .
}
}
public class Employee extends Person {}
• Методы, не имеющие реализации
o Заготовка для последующей реализации
o Могут быть объявлены только в абстрактных классах
o Должны быть реализованы в неабстрактных подклассах
public abstract class Person{
. . .
public abstract float getSalary();
}
public class Employee extends Person{
. . .
@Override
public float getSalary(){
return salary+salary*0.1;}
}
5
12. Понятие интерфейса, члены интерфейса
Интерфейс — это регламент взаимодействия между классами, абстракция,
позволяющая отделить описание от реализации.
Интерфейсы предназначены для реализации модульности и слабой связанности
классов.
Наследование класса расширяет функциональность “вертикально”, реализация
интерфейса “горизонтально”.
<modifiers> interface <interface-name> {
Constant-Declaration
Method-Declaration
Nested-Type-Declaration
}
Члены интерфейса:
• Постоянные поля
• Абстрактные, статические методы и методы по умолчанию
• Статические типы (вложенные интерфейсы и классы)

13. Реализация интерфейса


public class NoLimitBank implements Banker {
@Override
public double withdraw(double amount) {
// Code for this method goes here
}
@Override
public void deposit(double amount) {
// Code for this method goes here
}
}

14. Сравнение объектов на равенство, методы equals(),


hashCode()
Метод equals() используется для сравнения объектов. Чтобы определить одинаковые
объекты или нет, сравнивает значения полей объектов.
Для оптимизации производительности при сравнении объектов используется метод
hashCode(). Метод возвращает уникальный идентификатор для каждого объекта, что
упрощает сравнение состояний объектов.
6
Point pt1 = new Point(10, 10);
Point pt2 = new Point(10, 10);
Point pt3 = new Point(12, 19);
Point pt4 = pt1;
pt1 == pt1: true
pt1.equals(pt1): true
pt1 == pt2: false
pt1.equals(pt2): false
pt1 == pt3: false
pt1.equals(pt3): false
pt1 == pt4: true
pt1.equals(pt4): true

if x.equals(y) then x.hashCode() == y.hashCode()


if x.hashCode() == y.hashCode() then ∃ x|x.equals(y) ==
false
x.hashCode()i == x.hashCode()j ∀ i > 0, j>0

15. Класс Objects


• <T> int compare(T a, T b, Comparator<? super T> c)
• boolean deepEquals(Object a, Object b)
• boolean equals(Object a, Object b)
• int hash(Object... values)
• int hashCode(Object o)
• boolean isNull(Object obj)
• boolean nonNull(Object obj)
• <T> T requireNonNull(T obj)
• <T> T requireNonNull(T obj, String message)
• String toString(Object o)
• String toString(Object o, String nullDefault)

7
16. Перечисления
Кроме отдельных примитивных типов данных и классов в Java есть такой тип как enum
или перечисление. Перечисления представляют набор логически связанных констант.
Объявление перечисления происходит с помощью оператора enum, после которого
идет название перечисления. Затем идет список элементов перечисления через
запятую:

enum Day{
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY
}
• Перечисление фактически представляет новый тип, поэтому мы можем
определить переменную данного типа и использовать ее
• Перечисления могут использоваться в классах для хранения данных
Методы перечислений
• статический метод values() - возвращает массив всех констант перечисления
• ordinal() возвращает порядковый номер определенной константы (нумерация
начинается с 0)

17. Понятие исключения. Перехват и обработка исключения


Исключение — это состояние приложения, при котором нормальный способ
выполнения не определён.
Ключевые слова:
• try – определяет блок кода, в котором может произойти исключение;
• catch – определяет блок кода, в котором происходит обработка исключения;
• finally – определяет блок кода, который является необязательным, но при его
наличии выполняется в любом случае независимо от результатов выполнения
блока try.
Эти ключевые слова используются для создания в программном коде специальных
обрабатывающих конструкций: try{}catch, try{}catch{}finally, try{}finally{}.

8
int x = 10, y = 0, z;
try {
z = x / y;
System.out.println("z = " + z);
}
catch(ArithmeticException e) {
String msg = e.getMessage();
System.out.println("An error has occurred. The error is: " +
msg);
}

18. Иерархия типов исключений


При возникновении ошибки в процессе выполнения программы исполняющая среда
JVM создает объект нужного типа из иерархии исключений Java – множества
возможных исключительных ситуаций, унаследованных от общего «предка» – класса
Throwable.

9
19. Обработка нескольких типов исключений
try {
// Exception1, Exception2 or
Exception 3 thrown here
}
catch (Exception3 e1) {
// Handle Exception3
}
catch (Exception2 e2) {
// Handle Exception2
}
catch (Exception1 e3) {
// Handle Exception1
}
catch (Exception e) {
// Handle Exception
}

20. Проверяемые и непроверяемые исключения


Исключительные ситуации, возникающие в программе, можно разделить на две
группы:
1. Непроверяемые: ситуации, при которых восстановление дальнейшей
нормальной работы программы невозможно
2. Проверяемые: восстановление возможно.
Непроверяемые: ситуации, когда возникают исключения, унаследованные из класса
Error. Это ошибки, возникающие при выполнении программы в результате сбоя
работы JVM, переполнения памяти или сбоя системы. Обычно они свидетельствуют о
серьезных проблемах, устранить которые программными средствами невозможно.
Такой вид исключений в Java относится к неконтролируемым (unchecked) на стадии
компиляции. К этой группе также относят RuntimeException – исключения, наследники
класса Exception, генерируемые JVM во время выполнения программы. Часто
причиной возникновения их являются ошибки программирования.
Проверяемые: исключительные ситуации, предвидимые еще на стадии написания
программы, и для которых должен быть написан код обработки. Такие исключения
являются контролируемыми (checked). Основная часть работы разработчика на Java
при работе с исключениями – обработка таких ситуаций.

10
21. Выброс исключения
throw – используется для возбуждения исключения;
throws – используется в сигнатуре методов для предупреждения, о том, что метод
может выбросить исключение.

throw <<A throwable object reference>>;


// Create an object of IOException
IOException e1 = new IOException("File not found");
// Throw the IOException
throw e1;
// Throw an IOException
throw new IOException("File not found");

22. Объявление собственных классов исключений


При исполнении программы исключение генерируется JVM или вручную, с помощью
оператора throw. При этом в памяти создается объект исключения и выполнение
основного кода программы прерывается, а обработчик исключений JVM пытается
найти способ обработать исключение.
public class MyException extends Exception {
public MyException() {
super();
}
public MyException(String message) {
super(message);
}
public MyException(String message, Throwable cause){
super(message, cause);
}
public MyException(Throwable cause) {
super(cause);
}
}

11
23. Понятие обобщенного типа
Обобщения (Generic) — ссылочный тип, который принимает один или несколько
параметров типа. С их помощью можно объявлять классы, интерфейсы и методы, где
тип данных указан в виде параметра.
• SomeType<T> - обобщенный тип, generic-тип
• T - параметр типа (formal type parameter)
List<String> words = new ArrayList<String>();
words.add("Hello ");
words.add("world!");
String s = words.get(0)+words.get(1);

24. Стирание типов


Стирание типов применяется к использованию обобщений. В файле класса есть
метаданные, чтобы сказать, является ли метод/тип универсальным, каковы
ограничения и т. д. Но, когда используются generic, они преобразуются в проверки во
время компиляции и приведения во время выполнения. Код:

List<String> list = new ArrayList<String>();


list.add("Hi");
String x = list.get(0);
компилируется в

List list = new ArrayList();


list.add("Hi");
String x = (String) list.get(0);

Во время выполнения нет никакого способа узнать, что T=String для объекта списка -
эта информация исчезла.

... но сам интерфейс List<T> по-прежнему рекламирует себя как универсальный.

EDIT: просто чтобы уточнить, компилятор действительно сохраняет информацию о


том, что переменная является List<String> - но вы все равно не можете узнать, что
T=String для самого объекта списка.

12
25. Принцип подстановки
• Переменной данного типа может быть присвоено значение любого подтипа
данного типа.
• Метод с параметром данного типа может быть вызван с аргументом любого
подтипа данного типа
Integer – подтип Number
Double – подтип Number
ArrayList<E> – подтип List<E>
List<E> – подтип Collection<E>
Collection<E> – подтип Iterable<E>

26. Get-принцип
Get-принцип - используй extends там, где значения только читаются (get) из структуры
данных.
public static double sum(Collection<? extends Number> nums)
{
double s = 0.0;
for (Number num : nums) s += num.doubleValue();
return s;
}
List<Integer> ints = Arrays.asList(1, 2, 3);
assert sum(ints) == 6.0;
List<Double> doubles = Arrays.asList(2.78, 3.14);
assert sum(doubles) == 5.92;
List<Number> nums = Arrays.<Number>asList(1, 2, 2.78, 3.14);
assert sum(nums) == 8.92;

27. Put-принцип
Put-принцип - используй super там, где значения только записываются (put) в
структуру данных
public static void count(Collection<? super Integer> ints,
int n) {
for (int i = 0; i < n; i++) ints.add(i);
}
List<Integer> ints = new ArrayList<Integer>();
count(ints, 5);
assert ints.toString().equals("[0, 1, 2, 3, 4]");
List<Number> nums = new ArrayList<Number>();
count(nums, 5); nums.add(5.0);
assert nums.toString().equals("[0, 1, 2, 3, 4, 5.0]");
List<Object> objs = new ArrayList<Object>();
count(objs, 5); objs.add("five");
assert objs.toString().equals("[0, 1, 2, 3, 4, five]");

13
28. Захват символа подстановки
Захват подстановочного типа — это тип, который используется компилятором,
представляет тип конкретного экземпляра типа подстановочного знака в одном
конкретном месте.
Пример:

public Integer accept(RecipientTypeVisitor<?> visitor){


//Error:
return visitor.visit(this); //Cannot convert
capture of #1 to Integer
}
При компиляции вводится захват параметра типа RecipientTypeVisitor. Записанный
параметр типа конкретный, но полностью неизвестный и не конвертируется в Integer.
Невозможно напрямую обозначить захват подстановочного типа, поэтому нельзя
объявлять переменные этого тип. Однако, можно получить имя для него косвенно,
вызывая общий метод с ним в качестве параметра:
public static void reverse(List<?> list) { rev(list); }
private static <T> void rev(List<T> list) {
List<T> tmp = new ArrayList<T>(list);
for (int i = 0; i < list.size(); i++) {
list.set(i, tmp.get(list.size() - i - 1));
}
}

29. Типы коллекций, итератор.


Типы коллекций
• Список
o очередь, стек
o связный список
• Множество
• Словарь/соответствие/карта
Метод Iterator<E> является одним из ключевых методов интерфейса Collection.
Итератор позволяет поочередно получить все элементы коллекции.
Итератор - это поведенческий шаблон проектирования, который позволяет
пройтись по всем элементам некоторого составного объекта

14
30. Списки
Для создания простых списков применяется
интерфейс List, который расширяет
функциональность интерфейса Collection.

По умолчанию в Java есть встроенная реализация


этого интерфейса - класс ArrayList. Он представляет
обобщенную коллекцию, которая наследует свою
функциональность от класса AbstractList и
применяет интерфейс List. Проще говоря, ArrayList
представляет простой список, аналогичный массиву,
за тем исключением, что количество элементов в
нем не фиксировано.
ArrayList имеет следующие конструкторы:
ArrayList(): создает пустой список
ArrayList(Collection <? extends E> col): создает список, в который добавляются все
элементы коллекции col.
ArrayList (int capacity): создает список, который имеет начальную емкость capacity

Обобщенный класс LinkedList<E> представляет структуру данных в виде связанного


списка. Он наследуется от класса AbstractSequentialList и реализует интерфейсы List,
Dequeue и Queue. То есть он соединяет функциональность работы со списком и
фукциональность очереди.
Класс LinkedList имеет следующие конструкторы:
LinkedList(): создает пустой список
LinkedList(Collection<? extends E> col): создает список, в который добавляет все
элементы коллекции col

31. Множества
Множество в Java – это коллекция, содержащая
неупорядоченные уникальные, то есть неповторяющиеся,
элементы.

Интерфейс Set реализован в Java тремя классами: HashSet,


TreeSet, SortedSet (отсортированное множество). Наиболее
используемыми методами данных классов являются
методы добавления элементов, удаления, проверки
вхождения: add(), addAll(), remove(), removeAll(), contains(),
containsAll().

15
32. Очередь и дек
Очередь реализует принцип «first in - first out», т.е. «первым пришёл - первым ушёл».
Базовым интерфейсом всех очередей Java является Queue. Добавление элементов в
очередь делается методом add(), удаление - poll(), получение первого элемента без
его удаления - peek().
Две самые простые реализации очереди - это LinkedList (элементы извлекаются в том
же порядке, в котором были добавлены) и PriorityQueue(сортирует элементы в
порядке возрастания (или алфавитный порядок для строк)).

Интерфейс Deque (дек) позиционируется как современная альтернатива классу Stack


(принцип «last in - first out», т.е. «последним пришёл - первым вышел».). Deque — это
сокращение от «double ended queue» (двусторонняя очередь). Технически Deque
является расширением интерфейса очереди Queue.
Интерфейс Deque реализуют всё тот же LinkedList, а также ArrayDeque.

33. Очередь с приоритетами


• Класс PriorityQueue является частью Java Collections Framework. Является
неограниченной очередью. Элементы упорядочены по умолчанию или же
отсортированы с помощью компаратора.
• Не позволяет добавлять null-значения и non-comparable объекты. Размер
очереди неограничен, но можно указать начальный размер в момент его
создания. При добавлении элементов, размер автоматически увеличивается.
• PriorityQueue не является потокобезопасной. Для этих целей в Java реализован
класс PriorityBlockingQueue, реализующий интерфейс BlockingQueue. Именно он
используется в многопоточной среде.
• В PriorityQueue добавление/удаление элементов происходит за время O(log(n)).

34. Соответствие/словарь
В Java словари, также называемые картами и отображениями, реализованы классами
HashMap, TreeMap (через интерфейс SortedMap), Hashtable (хэш-таблица),
LinkedHashMap. Словарь представляет собой набор пар ключ-значение. При этом ключ
в пределах словаря должен быть уникальным.
Методы:
• put(key, value) – добавление элемента в словарь
• get(key) – получение значения по ключу
• entrySet(), keySet() и values() – получение множества пар, ключей, либо значений.
Можно преобразовать в списки, передав в конструктор List или методом addAll()
• containsKey(key) – проверка наличия ключа
• remove(key) – удаление элемента по ключу
• containsValue(value) – проверка наличия значения

16
35. Обход коллекции, удаление элементов коллекции
Обход:
• Iterator
• for-each loop
• forEach() method
Удаление элементов коллекции:
Collection<Type> collection = …;
Iterator<Type> it = collection.iterator();
while(it.hasNext()) {
Type value = it.next();
if (value ○ condition) it.remove();
}

Collection<Type> collection = …;
Collection<Type> toRemoveList = new ArrayList();
for(Type t: collection) {
if (t ○ condition) toRemoveList.add(t);
}
collection.removeAll(toRemoveList)

36. Сравнение коллекций


public interface Comparable<T> {
int compareTo(T object);
}
public class Employee implements Comparable<Employee> {
@Override
public int compareTo(Employee e) {
if (this > e) return 1;
if (this < e) return -1;
return 0;
}
}

17
37. Компаратор. Сортировка коллекции
Компаратор:
Comparator<T>
public interface Comparator<T> {
int compare<T object1, T object2);
}

Сортировка:
List<String> list = new ArrayList<>();
list.add("John");
list.add("Richard");
list.add("Donna");
list.add("Ken");
Collections.sort(list);
list.sort(Comparator.comparing(String::length));

38. Поиск элемента в коллекции


<T> int binarySearch(List<? extends Comparable<? super
T>>list, T key)
<T> int binarySearch(List<? extends T> list, T key,
Comparator<? super T> c)

List<String> list = new ArrayList<>();


list.add("John");
list.add("Richard");
list.add("Donna");
list.add("Ken");
Collections.sort(list); [Donna, John, Ken, Richard]
int index = Collections.binarySearch(list, "Donna");
System.out.println("Donna in List is at " + index);
index = Collections.binarySearch(list, "Ellen");
System.out.println("Ellen in List is at " + index);
Donna in List is at 0
Ellen in List is at -2
insert pos = -(index + 1), -((-2) + 1) = 1

18
39. Специализированные коллекции: только для чтения,
синхронизированные, пустые, вырожденные
Коллекцию, доступную только для чтения можно получить с помощью методов:
<T> Collection<T> unmodifiableCollection(Collection<?
extends T> c)
<T> List<T> unmodifiableList(List<? extends T> list)
<K,V> Map<K,V> unmodifiableMap(Map<? extends K,? extends V>
m)
<K,V> NavigableMap<K,V>
unmodifiableNavigableMap(NavigableMap<K,?
extends V> m)
<T> Set<T> unmodifiableSet(Set<? extends T> s)
<T> NavigableSet<T> unmodifiableNavigableSet(NavigableSet<T>
s)
static <T> SortedSet<T> unmodifiableSortedSet(SortedSet<T>
s)
<K,V> SortedMap<K,V> unmodifiableSortedMap(SortedMap<K,?
extends V>
m)

Чтобы получить синхронизированную коллекцию, применяются методы:


<T> Collection<T> synchronizedCollection(Collection<T> c)
<T> List<T> synchronizedList(List<T> list)
<K,V> Map<K,V> synchronizedMap(Map<K,V> m)
<K,V> NavigableMap<K,V>
synchronizedNavigableMap(NavigableMap<K,V> m)
<T> NavigableSet<T> synchronizedNavigableSet(NavigableSet<T>
s)
<T> Set<T> synchronizedSet(Set<T> s)
<T> SortedSet<T> synchronizedSortedSet(SortedSet<T> s)
<K,V> SortedMap<K,V> synchronizedSortedMap (SortedMap<K,V>
m)

Создание пустых коллекций:


<T> List<T> emptyList()
<K,V> Map<K,V> emptyMap()
<T> Set<T> emptySet()
<T> Iterator<T> emptyIterator()
<T> ListIterator<T> emptyListIterator()

Создание вырожденных коллекций:


<T> Set<T> singleton(T o)
<T> List<T> singletonList(T o)
<K,V> Map<K,V> singletonMap(K key, V value)

19
40. Понятие лямбда-выражения
Лямбда-выражение — это безымянная функция, используемая в функциональном
программировании, анонимная реализация функционального интерфейса.
• НЕ МЕТОД
• это экземпляр реализации функционального интерфейса
• не имеет имени
• не имеет return-типа, тип выводится из контекста
• не имеет предложения throws
• не может иметь параметров типа - не может быть Generic

41. Функциональный интерфейс


Функциональный интерфейс — это интерфейс, который имеет только один
абстрактный метод. Содержит определение одной операции в виде абстрактного
метода.
Основное назначение – использование в лямбда выражениях и method reference.
• Функциональный интерфейс может содержать любое количество методов по
умолчанию (default) или статических методов
• Функциональный интерфейс может содержать методы класса Object

42. Сравнение особенностей лямбда-выражений и анонимных


классов
Лямбда выражения являются альтернативой анонимным классам. Но они не
одинаковы.
Общее:
• Локальные переменные могут быть использованы только если они final или
effective final.
• Разрешается доступ к переменным класса и статическим переменным класса.
• Они не должны выбрасывать больше исключений чем определено в throws
метода функционального интерфейса.
Различия:
• Для анонимных классов ключевое слово this ссылается на сам класс. Для
лямбды выражений на внешний класс.
• Анонимные классы компилируются во внутренние классы. Но лямбда
выражения преобразуются в статические private методы класса, в котором они
используют invokedynamic инструкцию. Лямбда более эффективны, так как не
надо загружать еще один класс.

20
43. Анонимная реализация интерфейса
@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
}
@FunctionalInterface
public interface Operations {
double add(double n1, double n2);
double subtract(double n1, double n2);
}

44. Стандартные функциональные интерфейсы


• Function<T,R> - R apply(T t) - представляет функцию перехода от объекта типа T к
объекту типа R
• BiFunction<T, U, R> - R apply(T t, U u)
• Predicate<T> - boolean test(T t) - проверяет соблюдение некоторого условия. Если
оно соблюдается, то возвращается значение true. В качестве параметра лямбда-
выражение принимает объект типа T
• BiPredicate<T, U> - boolean test(T t, U u)
• Consumer<T> - void accept(T t) - выполняет некоторое действие над объектом
типа T, при этом ничего не возвращая
• BiConsumer<T, U>
• Supplier<T> - T get() - не принимает никаких аргументов, но должен возвращать
объект типа T
• UnaryOperator<T> - T apply(T t) - принимает в качестве параметра объект типа T,
выполняет над ними операции и возвращает результат операций в виде объекта
типа T
• BinaryOperator<T> - T apply(T t1, T t2) - принимает в качестве параметра два
объекта типа T, выполняет над ними бинарную операцию и возвращает ее
результат также в виде объекта типа T

45. Захват переменной лямбда-выражением


• объявлен окончательным
• не объявлен окончательным, но инициализируется только один раз
public Printer test() {
final String msg = "Hello"; // msg is effectively final
Printer printer = msg1 -> System.out.println(msg + " " +
msg1);
return printer;
}

21
46. Лямбда-синтаксис для компараторов
static <T,U extends Comparable<? super U>>Comparator<T>
comparing(Function<? super T,? extends U> keyExtractor)

default <U extends Comparable<? super U>>Comparator<T>


thenComparing(Function<? super T,? extends U> keyExtractor)

47. Ссылки на методы


• Ссылка на метод — это упрощенный синтаксис для записи лямбда выражения,
в котором используется существующий метод
• Ссылка на метод — это НЕ новый тип в Java, это НЕ указатель на функцию
ToIntFunction<String> lengthFunction = str -> str.length();
String name = "Ellen";
int len = lengthFunction.applyAsInt(name);

ToIntFunction<String> lengthFunction = String::length;


String name = "Ellen";
int len = lengthFunction.applyAsInt(name);

48. Внешнее/внутреннее итерирование


Внешнее итерирование:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = 0;
for (int n : numbers) {
if (n % 2 == 1) {
int square = n * n;
sum = sum + square;
}
}

Внутреннее итерирование:
int sum = numbers.stream()
.filter(n -> n % 2 == 1)
.map(n -> n * n)
.reduce(0, Integer::sum);
int sum = numbers.parallelStream()
.filter(n -> n % 2 == 1)
.map(n -> n * n)
.reduce(0, Integer::sum);
22
49. Понятие потока данных (Stream API). Характеристики
потока данных
Stream — это последовательность элементов данных, которая
поддерживает последовательные или параллельные операции агрегации
над ними
• ● Collection ≠ Stream
Особенности потоков
• Потоки не имеют хранилища
• Потоки могут представлять собой последовательность бесконечных элементов
• Проектирование потоков основано на внутренней итерации
• Потоки предназначены для параллельной обработки без дополнительной
работы со стороны разработчиков
• Потоки предназначены для поддержки функционального программирования
• Потоки поддерживают ленивые операции
• Потоки могут быть упорядочены или неупорядочены
• Потоки не могут быть использованы повторно

50. Промежуточные и терминальные операции над потоком


данных
Потоковые операции
● Промежуточные операции (ленивые операции). Все промежуточные операции
возвращают поток, так что можно объединять несколько операций без использования
точки с запятой
● Терминальные операции (нетерпеливые операции). Возвращают void или
непотоковый результат

51. Способы создания потока данных


1. Классический: Создание стрима из коллекции
Шаблон: collection.stream()
Пример: Collection<String> collection = Arrays.asList("a1",
"a2", "a3"); Stream<String> streamFromCollection =
collection.stream();
2. Создание стрима из значений
Шаблон: Stream.of(значение1,… значениеN)

23
Пример: Stream<String> streamFromValues = Stream.of("a1",
"a2", "a3");
3. Создание стрима из массива
Шаблон: Arrays.stream(массив)
Пример: String[] array = {"a1","a2","a3"}; Stream<String>
streamFromArrays = Arrays.stream(array);
4. Создание стрима из файла (каждая строка в файле будет отдельным элементом в
стриме)
Шаблон: Files.lines(путь_к_файлу)
Пример: Stream<String> streamFromFiles =
Files.lines(Paths.get("file.txt"))
5. Создание стрима из строки
Шаблон: «строка».chars()
Пример: IntStream streamFromString = "123".chars()
6. С помощью Stream.builder
Шаблон: Stream.builder().add(...)....build()
Пример:
Stream.builder().add("a1").add("a2").add("a3").build()
7. Создание параллельного стрима
Шаблон: collection.parallelStream()
Пример: Stream<String> stream = collection.parallelStream();
8. Создание бесконечных стрима с помощью Stream.iterate
Шаблон: Stream.iterate(начальное_условие, выражение_генерации)
Пример: Stream<Integer> streamFromIterate = Stream.iterate(1,
n -> n + 1)
9. Создание бесконечных стрима с помощью Stream.generate
Шаблон: Stream.generate(выражение_генерации)
Пример: Stream<String> streamFromGenerate =
Stream.generate(() -> "a1")

52. Необязательное значение


Person ken = new Person(1, "Ken", Person.Gender.MALE, null,
6000.0);
int year = ken.getDob().getYear(); // Throws a
NullPointerException
System.out.println("Ken was born in the year " + year);
Создание:
Optional<T> wrapper
<T> Optional<T> empty()
<T> Optional<T> of(T value) throws NPE
<T> Optional<T> ofNullable(T value)
24
53. Операции peek, forEach
peek - возвращает поток, состоящий из элементов этого потока, дополнительно
выполняющий предоставленное действие для каждого элемента, поскольку элементы
расходуются из результирующего потока. Это промежуточная операция.
forEach — это разновидность цикла for, которая используется, когда нужно обработать
все элементы массива или коллекции. Метод forEach выполняет действие для
каждого элемента этого потока. Для параллельного потока эта операция не
гарантирует поддержания порядка потока.

54. Операции map, flatMap


Stream.flatMap представляет собой комбинацию операций map и flat. Это означает,
что вы сначала применяете функцию к своим элементам, а затем сглаживаете ее.
Stream.map применяет функцию только к потоку, не сглаживая поток.

Чтобы понять, в чем состоит уплощение потока, рассмотрим такую структуру, как [
[1,2,3],[4,5,6],[7,8,9] ] , которая имеет "two levels". Сглаживание этого означает
преобразование его в структуру "one level" : [ 1,2,3,4,5,6,7,8,9 ] .

55. Операция filter


Для фильтрации элементов в потоке применяется метод filter(), который
представляет промежуточную операцию. Он принимает в качестве параметра
некоторое условие в виде объекта Predicate<T> и возвращает новый поток из
элементов, которые удовлетворяют этому условию

56. Формирование коллекции из потока данных


Set<String> names = new HashSet<>();
names.add("Ken");
names.add("jeff");

Stream<String> sequentialStream = names.stream();


Stream<String> parallelStream = names.parallelStream();

57. Операции reduce, groupingBy


reduce - позволяет выполнять агрегатные функции на всей коллекцией и возвращать
один результат
collection.stream().reduce((s1, s2) -> s1 + s2).orElse(0)
groupingBy - разделяет коллекцию на несколько частей и возвращает Map<N, List<T>>

25
58. Понятие сериализации, десереализации
Сериализация представляет процесс записи состояния объекта в поток,
соответственно процесс извлечения или восстановления состояния объекта из потока
называется десериализацией. Сериализация очень удобна, когда идет работа со
сложными объектами.
Для сериализации объектов в поток используется класс ObjectOutputStream. Он
записывает данные в поток.
Для создания объекта ObjectOutputStream в конструктор передается поток, в который
производится запись:
ObjectOutputStream(OutputStream out)
Класс ObjectInputStream отвечает за обратный процесс - чтение ранее
сериализованных данных из потока. В конструкторе он принимает ссылку на поток
ввода:
ObjectInputStream(InputStream in)

59. JSON-формат
JSON стал общепринятым форматом для обмена данными в клиент-серверных
приложения. Он является универсальным форматом для обмена данными.
JSON — текстовый формат обмена данными, основанный на JavaScript. Как и многие
другие текстовые форматы, JSON легко читается людьми.
Несмотря на происхождение от JavaScript, формат считается независимым от языка и
может использоваться практически с любым языком программирования. Для многих
языков существует готовый код для создания и обработки данных в формате JSON.

60. Инструментарий Google Gson


Библиотека GSON была разработана программистами Google и позволяет
конвертировать объекты JSON в Java-объекты и наоборот.
Google GSON (https://github.com/google/gson). Java-библиотека GSON может
преобразовывать объекты Java в JSON. В то же время он также обеспечивает полную
поддержку обобщений Java и не требует добавления аннотаций к классу. Его удобнее
использовать без добавления аннотаций, и это также является необходимым
условием, если исходный код не может быть изменен.

61. Инструментарий FasterXml Jackson


Проект Джексона FasterXML (https://github.com/FasterXML/jackson). Jackson - это
инструментарий для обработки данных, основной особенностью которого является
потоковый анализатор и генератор JSON. Он специально разработан для Java, а также
может обрабатывать другие не-JSON-кодировки. Из нашей статистики на Github, это
должен быть самый популярный парсер JSON.

26