3.18M
Категория: ПрограммированиеПрограммирование

StreamApi + ReflectionApi + Collections Pres

1.

COLLECTIONS +
STREAM API +
REFLECTION API
{}
begin

2.

ЦЕЛИ ЗАНЯТИЯ
1. Закрепить умение выбирать
оптимальные структуры
данных под конкретные задачи.
2. Научиться писать более
"элегантный" код
с использованием современных
средств java (дженерики, stream
api, лямбды, reflection api).
ref
@

3.

РЕЗУЛЬТАТОМ ЗАНЯТИЯ СТАНЕТ
//
Будете знать:
1. 7 основных коллекций
и отличия в их реализации.
2. Зачем настраивать параметры
коллекций и как использовать
свои объекты в коллекциях.
/>
3. Самые распространенные ошибки
при использовании
дженериков на примерах.
4. Зачем используется stream api и лямбды
и как выполняется написанный с их помощью код
(порядок выполнения, потоки и т.п.).
&
%
ref
5. Где и как использовать в коде
reflection api.
@

4.

РЕЗУЛЬТАТОМ ЗАНЯТИЯ СТАНЕТ
//
Научитесь:
1. Выбрать оптимальную
структуру данных
в зависимости от задачи
и обосновать свой выбор
/>
2. Писать сложные
обработчики коллекций
с использованием
Stream API и лямбд.
3. Работать с полями классов
к которым нет доступа
напрямую.
&
%
ref
@

5.

ТЕМЫ
Коллекции
разница в реализации
и скорости выполнения
операций
Stream API
работаем с коллекциями,
используем лямбды
для обработки
Дженерики
как можно использовать
для написания более
универсального кода
для работы с коллекциями.
Распространенные ошибки.
Reflection API
варианты применения
на реальных примерах
ref
@

6.

ПРАВИЛА ВЗАИМОДЕЙСТВИЯ
Будьте с нами!
Отложите телефон,
рабочие дела,
мессенджеры.
Выключайте микрофон,
когда говорит ведущий.
Задавайте вопросы.
Это поможет
разобраться в теме.
Выполняйте практику
вместе с экспертом
во время занятия.
Будьте активны!
Участвуйте в интерактивах.
ref
@

7.

ГДЕ ВОЗНИКЛИ
САМЫЕ БОЛЬШИЕ
ТРУДНОСТИ?
Напишите в чате тему / подтему,
где у вас возникли проблемы
при самостоятельном разборе материала
Форматы
выполнения:
индивидуально
Чат
5 минут

8.

Тема 1
КОЛЛЕКЦИИ
{}
begin

9.

ПЛАН
• Основные коллекции
• Разница в их реализации
• Скорость работы основных операций
• Параметры конфигурации коллекций
ref
@
5

10.

ИЕРАРХИЯ КОЛЛЕКЦИЙ
ref
@

11.

КОЛЛЕКЦИЯ №1: ARRAY LIST
Время выполнения
основных операций:
• получение элемента
по индексу = О(1)
• добавление элемента
в конец = O(1),
но в худшем случае за O(N)
• добавление элемента
в случайное место = O(N)
• проверка наличия
элемента = O(N)
ref
• удаление элемента = O(N)
@

12.

КОЛЛЕКЦИЯ №2: LINKED LIST
Время выполнения:
• получение элемента
по индексу = O(N)
• добавление элемента
в конец = O(1)
• добавление элемента
в случайное место = O(N)
• проверка наличия элемента =
O(N)
ref
• удаление элемента = O(N)
@

13.

КОЛЛЕКЦИЯ №3: QUEUE
Основные операции:
• получение головного элемента
(без удаления)
• получение головного элемента
(с удалением)
• добавление элемента в конец
очереди
ref
@

14.

КОЛЛЕКЦИЯ №4: HASHMAP
Время выполнения
основных операций:
• получение элемента
по индексу = O(1),
в худшем случае O(log N)
• добавление элемента
в случайное место = O(1),
в худшем случае O(log N)
• проверка наличия элемента =
O(1), в худшем случае O(log N)
• удаление элемента = O(1),
в худшем случае O(log N)
@
ref

15.

КОЛЛЕКЦИЯ №5: TREEMAP
Время выполнения
основных операций:
• получение элемента
по индексу = O(log N)
• добавление элемента
в случайное место = O(log N)
• проверка наличия
элемента = O(log N)
• удаление элемента = O(log N)
ref
@

16.

КОЛЛЕКЦИЯ №6: HASHSET
Время выполнения
основных операций:
• получение элемента по индексу = O(1),
в худшем случае O(log N)
• добавление элемента
в случайное место = O(1),
в худшем случае O(log N)
• проверка наличия элемента = O(1),
в худшем случае O(log N)
• удаление элемента = O(1),
в худшем случае O(log N)
@
ref

17.

КОЛЛЕКЦИЯ №7: TREESET
Время выполнения
основных операций:
• получение элемента
по индексу = O(log N)
• добавление элемента
в случайное место = O(log N)
• проверка наличия
элемента = O(log N)
• удаление элемента = O(log N)
ref
@

18.

ПРАКТИКА!
Выбираем наиболее подходящую для задачи коллекцию
ref
@

19.

КАК БУДЕМ
ВЫБИРАТЬ
1
6 задач
2
Пишем в чат самый подходящий
из изученных ранее вариантов коллекций
3
Обсуждаем результаты
Форматы
выполнения:
индивидуально
Чат
10 минут

20.

ЗАДАЧА №1
Есть список организаторов разных потоков курса. Списки в
рамках потока не меняются, могут только добавляться новые
потоки со своими организаторами.
Самые частые операции:
• получение списка организаторов
по конкретному потоку
• получение информации об одном
из организаторов потока
• добавление списка организаторов нового потока

21.

ЗАДАЧА №1
Есть список организаторов разных потоков курса. Списки в
рамках потока не меняются, могут только добавляться новые
потоки со своими организаторами.
Самые частые операции:
• получение списка организаторов
по конкретному потоку
• получение информации об одном
из организаторов потока
• добавление списка организаторов нового потока
HASHMAP

22.

ЗАДАЧА №2
Есть список студентов текущего курса, который пополняется
новыми участниками по мере набора. Участники могут также
удаляться, если они были отчислены из-за неуспеваемости.
Основные операции:
• добавление нового студента
• удаление студента
• получение списка студентов

23.

ЗАДАЧА №2
Есть список студентов текущего курса, который пополняется
новыми участниками по мере набора. Участники могут также
удаляться, если они были отчислены из-за неуспеваемости.
Основные операции:
• добавление нового студента
• удаление студента
• получение списка студентов
ARRAYLIS
T

24.

ЗАДАЧА №3
Есть список кандидатов для прохождения курса.
Приемная комиссия должна обработать их анкеты в том
порядке, в котором они были поданы.
Основные операции:
• добавление новых кандидатов
• получение анкеты кандидата в порядке очередности
(кто раньше пришел, у того больше шансов
для попадания на курс) и удаление анкеты после обработки

25.

ЗАДАЧА №3
Есть список кандидатов для прохождения курса.
Приемная комиссия должна обработать их анкеты в том
порядке, в котором они были поданы.
Основные операции:
• добавление новых кандидатов
• получение анкеты кандидата в порядке очередности
(кто раньше пришел, у того больше шансов
для попадания на курс) и удаление анкеты после обработки
QUEUE

26.

ЗАДАЧА №4
Есть общая база преподавателей всех потоков курса.
При добавлении новых преподавателей, важно сохранять
алфавитный порядок, порядок их добавления не важен.
Основные операции:
• получение списка преподавателей
• добавление нового преподавателя с поддержкой алфавитного
порядка
• получение первого/последнего преподавателя в списке

27.

ЗАДАЧА №4
Есть общая база преподавателей всех потоков курса.
При добавлении новых преподавателей, важно сохранять
алфавитный порядок, порядок их добавления не важен.
Основные операции:
• получение списка преподавателей
• добавление нового преподавателя с поддержкой алфавитного
порядка
• получение первого/последнего преподавателя в списке
TREESET

28.

ЗАДАЧА №5
Есть список задач для проверочных работ.
Список постоянно пополняется новыми задачами,
удаляются устаревшие. Со списком активно работают
при составлении теста — проходят по списку,
возвращаются к заинтересовавшим задачам.
Основные операции:
• проход по списку в двух направлениях
• добавление элемента в конец
• удаление элемента

29.

ЗАДАЧА №5
Есть список задач для проверочных работ.
Список постоянно пополняется новыми задачами,
удаляются устаревшие. Со списком активно работают
при составлении теста — проходят по списку,
возвращаются к заинтересовавшим задачам.
Основные операции:
• проход по списку в двух направлениях
• добавление элемента в конец
• удаление элемента
LINKEDLIST

30.

ЗАДАЧА №6
Есть список выпускников курса. В него добавляются новые
люди после выпуска. Важно, что список уникальный —
если человек закончил несколько потоков, он должен
присутствовать в списке один раз.
Основные операции:
• добавление в список
• получение списка

31.

ЗАДАЧА №6
Есть список выпускников курса. В него добавляются новые
люди после выпуска. Важно, что список уникальный —
если человек закончил несколько потоков, он должен
присутствовать в списке один раз.
Основные операции:
• добавление в список
• получение списка
HASHSET

32.

Тема 2
ДЖЕНЕРИКИ
И ОШИБКИ ИХ
ИСПОЛЬЗОВАНИЯ
{}
begin

33.

СОДЕРЖАНИЕ
• Примеры использования
• Самые распространенные ошибки
• Как избежать их в будущем
ref
@
5

34.

ЗАЧЕМ НУЖНЫ?
//
Явное указание ожидаемых типов
в коллекциях и объектах
Избежание ошибок
в коде на этапе компиляции
Сокращение кода за счет отсутствия необходимости
явного приведения и проверки типов
Задание единичных и множественных
ограничений на типы принимаемых объектов
/>
&
%
ref
Уменьшение дублирования кода за счет реализации
общих типизированных методов и классов
@

35.

ГДЕ ПРИМЕНЯЕМ?
//
Во всех коллекциях и объектах,
где работаем с заранее
определенными типами данных
/>
В методах и классах, которые работают
только с заданными видами объектов
(например, наследниками одного из
классов)
В местах дублирования методов
и классов, где для параметров разных
типов сохраняется одинаковое поведение
&
%
ref
@

36.

ПРИМЕР ОШИБКИ №1
Хотим выполнить присвоение массивов чисел (String в raw type)
public static void genericsWithNoType() {
List<String> stringsList = new ArrayList<>(asList("s1", "s2"));
// ...
// ...
List preparedDataList = new ArrayList<Long>(asList(1L, 2L, 3L));
preparedDataList = stringsList;
preparedDataList.add(4L);
// ...
// ...
Long lastAddedNumber = preparedDataList.get(2);
}
ref
@

37.

КАК ПРАВИЛЬНО
В IDE будет отображаться, что такое присваивание невалидно
public static void genericsWithNoType() {
List<String> stringsList = new ArrayList<>(asList("s1", "s2"));
// ...
// ...
List<Long> preparedDataList = new ArrayList<Long>(asList(1L, 2L,
3L));
preparedDataList = stringsList;
preparedDataList.add(4L);
// ...
// ...
Long lastAddedNumber = preparedDataList.get(2);
}
ref
@

38.

ПРИМЕР ОШИБКИ №2
Хотим выполнить присвоение массивов чисел (Long в Number)
public final class Long extends Number implements
Comparable<Long>
public static void genericsWithHierarchy() {
List<Long> longList = asList(1L, 2L, 3L);
List<Number> numbersList = asList(1, 2, 3);
numbersList = longList;
}
ref
@

39.

КАК ПРАВИЛЬНО
Из иерархии типов не следует такая же иерархия коллекций элементов этого типа
public static void genericsWithHierarchy() {
List<? extends Long> longList = asList(1L, 2L, 3L);
List<? extends Number> numbersList = asList(1, 2, 3);
numbersList = longList;
}
ref
@

40.

ПРИМЕР ОШИБКИ №3
Метод добавления нового элемента в список чисел
public static void genericsWithIncreasingList() {
List<Integer> numbers = new ArrayList<>(asList(1, 2));
addNewElement(numbers, 3);
}
public static void addNewElement(List<? extends Number> list,
Integer elementValue) {
list.add(elementValue);
}
@
ref

41.

КАК ПРАВИЛЬНО
Принцип PECS (producer extends, consumer super)
public static void genericsWithIncreasingList() {
List<Integer> numbers = new ArrayList<>(asList(1, 2));
addNewElement(numbers, 3);
}
public static void addNewElement(List<? super Integer> list,
Integer elementValue) {
list.add(elementValue);
}
ref
@

42.

ПРИМЕР ОШИБКИ №4
Метод с различным поведением в зависимости от типа входных данных
public <T> int resolveStatusCode(T parameter) {
if (parameter instanceof String) {
return 1;
} else if (parameter instanceof Long) {
return 2;
} else {
//
}
return 0;
}
ref
@

43.

КАК ПРАВИЛЬНО
Не пытаемся использовать дженерики там, где проще обойтись без них
public int resolveStatusCode(String parameter) {
return 1;
}
public int resolveStatusCode(Long parameter) {
return 2;
}
ref
@

44.

ГДЕ ЕЩЕ МОГУТ БЫТЬ ПРОБЛЕМЫ?
//
Нельзя использовать примитивные типы
Нельзя явно создать экземпляр параметризированного типа
Нельзя создать массив параметризованных типов
Нельзя ловить и бросать исключения параметризованных
типов
Нельзя объявить статическое поле параметризованного типа
/>
&
%
ref
@

45.

Тема 3
STREAM API
И ЛЯМБДЫ
{}
begin

46.

ПЛАН
• Зачем использовать
• Как реализованы
• Порядок применения операторов
• Многопоточность
ref
@
5

47.

ЛЯМБДЫ
//
Лямбда — функция с параметрами (блок кода),
которую можно передавать в другие методы
в качестве аргумента.
В отличие от других методов, не имеет имени.
/>
По сути является реализацией
функционального интерфейса.
Общий синтаксис: (параметры) -> {тело метода}
Используются для повышения
читаемости и упрощения кода.
&
%
ref
@

48.

ПРИМЕРЫ ИСПОЛЬЗОВАНИЯ
@Test
public void sortingWithComparator() {
List<Integer> numbersList = asList(1, 2, 3, 4);
Comparator<Integer> reversedOrder = new Comparator<Integer>() {
@Override
public int compare(Integer n1, Integer n2) {
return n2 - n1;
}
};
numbersList.sort(reversedOrder);
}
@Test
public void sortingWithLambda() {
List<Integer> numbersList = asList(1, 2, 3, 4);
ref
numbersList.sort((n1, n2) -> n2 - n1);
}
@

49.

ПРИМЕРЫ ИСПОЛЬЗОВАНИЯ
@FunctionalInterface
interface Result {
void print();
}
Result successResult = () -> System.out.println("Success");
Result failResult = () -> System.out.println("Fail");
public void finishExecution(Result funResult) {
// do smth
funResult.print();
}
ref
@

50.

ОСНОВНЫЕ ПОНЯТИЯ STREAM API
Stream API — способ работать со структурами
данных в функциональном стиле
Создание стрима
на основе существующей коллекции (с помощью
методов .stream())
из набора данных (с помощью Stream.of())
сгенерировать новый стрим заданного типа
(например, через IntStream.of())
ref
Основные операторы:
промежуточные (например, filter, map)
терминальные (например, count, collect, findFirst)
@

51.

ЗАЧЕМ ИСПОЛЬЗУЕМ?
//
• Ускорение обработки данных
• Упрощение обработки данных
/>
• Более читаемый код
• Используем стандартные реализации
основных методов (сортировка,
фильтрация, …)
&
%
ref
@

52.

КОГДА ИСПОЛЬЗОВАТЬ НЕ СТОИТ?
//
• Хотим изменить существующую коллекцию,
а не создать новую
• Для создания новой коллекции нужно
использовать много внешних объектов и
зависимых данных
/>
&
• Есть много разных задач,
которые хочется решить за один проход
• Нужно бросать проверяемые исключения при
обработке коллекции
%
ref
@

53.

КАКОЕ ЗНАЧЕНИЕ БУДЕТ ИМЕТЬ
COUNTER В РЕЗУЛЬТАТЕ ВЫПОЛНЕНИЯ
КОДА?
public static void counterInStreamTest() {
int counter = 0;
IntStream.range(0, 4).forEach(i -> counter += i);
}
ref
Ответ напишите в чате
@

54.

ИСПОЛЬЗОВАНИЕ ВНЕШНИХ
ОБЪЕКТОВ В STREAM API
В стримах можно использовать:
статические переменные
глобальные переменные
локальные переменные только final и effectively final
Основная причина: защита от проблем параллелизма
ref
@

55.

БУДЕТ ЛИ РАБОТАТЬ ЭТОТ КОД?
public void listInStreamTest() {
List<Integer> numbersList = asList(1, 2, 3, 4);
IntStream.range(0, 4)
.forEach(i ->
numbersList.add(numbersList.get(i) + i)
);
}
ref
Ответ напишите в чате
@

56.

СКОЛЬКО ПОТОКОВ ИСПОЛЬЗУЕТСЯ
ПРИ ВЫПОЛНЕНИИ КОДА?
public void parallelStreamTest() {
List<Integer> numbersList = asList(1, 2, 3, 4);
numbersList.parallelStream()
.mapToInt(i -> i + 5)
.forEach(i -> System.out.println("number = " + i));
}
ref
I
1 поток
II
2 потока
III
4 поток
@

57.

ПАРАЛЛЕЛИЗАЦИЯ В STREAM API
По умолчанию создаваемый поток последовательный.
Чтобы сделать его параллельным, надо использовать
.parallel() для стрима, либо .parallelStream() для объекта.
Для работы используется общий fork-join пул.
Число потоков в пуле = числу процессорных ядер - 1.
Можно переопределить значение через проперти
java.util.concurrent.ForkJoinPool.common.parallelism
(но помним, что переопределение повлияет на все другие
операции, которые также работают с общим пулом)
Важно
Не пытайтесь использовать параллелизацию
везде, это может не ускорить, а замедлить ваш
код или привести к ошибкам. Используем там,
где есть требование к ускорению кода, но
проводим тесты для сравнения результатов
//
/>
&
%
ref
@

58.

СКОЛЬКО ПОТОКОВ ИСПОЛЬЗУЕТСЯ
ПРИ ВЫПОЛНЕНИИ КОДА?
public void parallelStreamTest() {
List<Integer> numbersList = asList(1, 2, 3, 4);
numbersList.parallelStream()
.filter(i -> i != 2)
.mapToInt(i -> i + 5)
.forEachOrdered(i -> System.out.println(
" number = " + i));
}
ref
I
1 поток
II
3 потока
III
4 поток
@

59.

РАЗБИРАЕМ
СЛОЖНЫЕ
ПРИМЕРЫ
{}
begin

60.

ПИШЕМ
СТРИМЫ
1
На слайдах будет представлена задача
2
Пробуем написать решение самостоятельно
3
Разбираем правильное решение
Форматы
выполнения:
индивидуально
Написание кода
5 минут

61.

ЗАДАЧА №1
Метод, который на вход принимает массив
студентов курса. У студента есть имя,
возраст и номер потока курса,
в котором он принимает участие.
Написать стрим, который возвращает список
уникальных имен студентов возраста от 18 до 30 лет
из второго потока

62.

МОДЕЛЬ
public class Student {
private String name;
private int age;
private Integer groupNumber;
String getName() {
return name;
}
int getAge() {
return age;
}
Integer getGroupNumber() {
return groupNumber;
}
}

63.

ЗАДАЧА №1
public List<String> getStudentNames(Student[] students) {
return Arrays.stream(students)
.filter(student -> student.getAge() >= 18 &&
student.getAge() <= 30)
.filter(student -> student.getGroupNumber() == 2)
.map(Student::getName)
.distinct()
.collect(Collectors.toList());
}

64.

ЗАДАЧА №2
Метод, который на вход принимает массив
студентов курса. У студента есть имя,
возраст и номер потока курса,
в котором он принимает участие.
Написать стрим, который возвращает максимальный
возраст студента, у которого имя начинается
на букву А или Б и который учится на 1ом потоке,
или выбрасывает исключение с информацией,
что таких студентов нет

65.

ЗАДАЧА №2
public int getStudentAgesSummary(Student[] students) throws Exception {
return Arrays.stream(students)
.filter(student -> student.getName().startsWith("А") ||
student.getName().startsWith("Б"))
.filter(student -> student.getGroupNumber() == 1)
.map(Student::getAge)
.max(Comparator.naturalOrder())
.orElseThrow(() -> new Exception("No students present"));
}

66.

Тема 4
REFLECTION API
{}
begin

67.

СОДЕРЖАНИЕ
• Зачем используем
• Примеры использования
ref
@
5

68.

ГДЕ ПРИМЕНЯЕМ?
//
Чтобы узнать информацию об объекте
(класс, модификаторы класса, какие методы есть)
Для получения недоступных полей объекта
Вызов метода по имени
Создание экземпляра класса,
если его тип не известен на этапе компиляции
Изменение свойств объектов и классов
Работа с аннотациями
/>
&
%
ref
@

69.

ПРИМЕРЫ ИСПОЛЬЗОВАНИЯ (1)
Создаем в методе экземпляр класса параметризованного типа
public <T> List<T> addNewElement(List<T> elementsList,
Class<T> elemClass)
throws Exception {
T newElement = elemClass.newInstance();
elementsList.add(newElement);
return elementsList;
}
ref
@

70.

ПРИМЕРЫ ИСПОЛЬЗОВАНИЯ (2)
Получаем приватную информацию об имене студента
public static class Student {
private String name;
private int age;
private Integer groupNumber;
public Student(String name, int age, Integer groupNumber) {
this.name = name;
this.age = age;
this.groupNumber = groupNumber;
}
int getAge() {
return age;
}
ref
Integer getGroupNumber() {
return groupNumber;
}
}
@

71.

ПРИМЕРЫ ИСПОЛЬЗОВАНИЯ
Получаем приватную информацию об имене студента
@Test
public void studentsTest() throws Exception {
StreamExamples.Student newStudent = new StreamExamples.Student(
"Ivan", 30, null);
String studentName = getStudentName(newStudent);
System.out.println("Student name: " + studentName);
}
private String getStudentName(StreamExamples.Student student) throws
Exception {
Field ageField = student.getClass().getDeclaredField("name");
ageField.setAccessible(true);
return (String) ageField.get(student);
}
ref
@

72.

ПРИМЕРЫ ИСПОЛЬЗОВАНИЯ (3)
Проверяем информацию из аннотации
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE_USE})
public @interface CourseParticipantAnnotation {
String name() default "creator";
}
@CourseParticipantAnnotation(name = "students")
public class Student {
}
ref
@

73.

ПРИМЕРЫ ИСПОЛЬЗОВАНИЯ
Проверяем информацию из аннотации
@Test
public void annotationTest() {
CourseParticipantAnnotation annotation = Student.class.
getAnnotation(CourseParticipantAnnotation.class);
System.out.println(annotation.name());
}
ref
@

74.

ЗАВЕРШЕНИЕ
//
Напишите в чате:
1
Что было самым полезным
2
Что вы использовали раньше неправильно
3
Чем вы будете теперь пользоваться
/>
&
%
ref
@

75.

СПАСИБО
ЗА ВНИМАНИЕ
{}
begin
English     Русский Правила