билеты модуль 7. 1 Функциональные интерфейсы, основные типы
Скачать 184 Kb.
|
39) К каким переменным и как можно обращаться в теле лямда-выражениях? Доступ к переменным внешней области действия из лямбда-выражения очень схож к доступу из анонимных объектов. Можно ссылаться на: 1) неизменяемые (effectively final - не обязательно помеченные как final) локальные переменные; 2) поля класса; 3) статические переменные. К методам по умолчанию реализуемого функционального интерфейса обращаться внутри лямбда-выражения запрещено. effectively final локальные переменные В в лямбда-выражениях стоит использовать внешние (относительно выражения) неизменяемые значения, а не внешние переменные, значение и внутреннее состояние которых могут меняться. Под внешними неизменяемыми значениями, соответственно, подразумеваются effectively final локальные переменные и поля примитивных типов, а также effectively final объекты, внутреннее состояние которых не будет меняться. Связано это с тем, что Streams и лямбда-выражения проектировались из расчета на их многопоточное использование. //1 вариант параметрам лямбды, а также свободно объявлять и использовать любые переменные IntUnaryOperator squaer = x -> x * x; //2 вариант к полям(переменным) того класса в нутри котого объявлена лямбда, можно как читать, так и писать. IntSupplier sequense = () -> counter++; //3 вариант к переменным которые объявлены внутри метода где объявлена лямбда. Но есть ограничения переменные должны быть эффективно финальные // т.е. значение им должно присвоено ровно один раз до объявления лямбды, после чего оно менятся уже не может.(Типа мы написали final) int bonus = 10; IntUnaryOperator bonusAdder = (x) -> x + bonus; //трюк с обходом еденичной длинны int[] test = new int[] {0};//ссылка является эффективно финальной но на содержимое это не влияет. 40) Что такое Stream? Какие бывают стримы (По разным критериям, например "конечные и бесконечные", последовательные и параллельные) Стрим это последовательность элементов, потенциально бесконечная, свозможность применять к ней, сложные, поэтапные приобразования цикла и условного оператора. И программа будет иметь, простую линейную структуру.(Владыкин) Стрим состаит из источника - (элементы) -> промежуточные операторв - (элементы) -> терминальный оператор !!! Важно обработка происходит от терминального источника Операторы можно разделить на две группы: Промежуточные или КОНВЕЕРНЫЕ операторы(“intermediate”, ещё называют “lazy”) — обрабатывают поступающие элементы и возвращают стрим. Промежуточных операторов в цепочке обработки элементов может быть много. Терминальные (“terminal”, ещё называют “eager”) — обрабатывают элементы и завершают работу стрима, так что терминальный оператор в цепочке может быть только один. У стрима может быть сколько угодно вызовов промежуточных операций и последним вызов конечной операции. При этом все промежуточные операции выполняются лениво и пока не будет вызвана конечная операция никаких действий на самом деле не происходит (похоже на создание объекта Thread или Runnable, без вызова start()). Стримы создаются на основе каких-либо источников, например классов из java.util.Collection. Операции над стримами могут выполняться как последовательно, так и параллельно. Потоки не могут быть использованы повторно. Как только была вызвана какая-нибудь конечная операция, поток закрывается. Ассоциативные массивы (maps), например, HashMap, не поддерживаются. Кроме универсальных объектных существуют особые виды стримов для работы с примитивными типами данных int, long и double: IntStream, LongStream и DoubleStream. Эти примитивные стримы работают так же, как и обычные объектные, но со следующими отличиями: используют специализированные лямбда-выражения, например, IntFunction или IntPredicate вместо Function и Predicate; поддерживают дополнительные конечные операции [sum(), average(), mapToObj(). 41) Чем является Stream в контексте Java? Обработчик потоков объекта Поток представляет собой последовательность элементов и поддерживает различные виды операций для выполнения вычислений: Большинство операций потока принимают в качестве параметров какие-то лямбда-выражения, в функциональный интерфейс точное поведение по каждой операции. Большинство этих операций должны быть как [неинтерферирующими (non-interfering), так и лишенными состояния (stateless). Что это значит? [Неинтерферирующуя функция не изменяет основной источник данных потока. Например, в приведенном выше примере лямбда выражение не изменяет mList путем добавления или удаления элементов из коллекции. Лишенная состояния функция — выполнение операции является детерминированным, например, в приведенном выше примере лямбда-выражение не зависит от какой-либо изменяемой переменной или состояния из внешней среды, которая могла бы измениться во время выполнения. 42) В каком пакете находится Stream? Средства работы с потоками данных Stream API являются составляющей пакета [java.util.stream. Данный пакет содержит набор потоковых интерфейсов, образующих иерархию. Базовым поточным интерфейсом является [BaseStream. 43) Чем Stream отличается от итератора? [Итератор это простой обьект который умеет выдовать только один элемент по одному Стрим гораздо сложный и навароченный, у него огромное количество методлов он содержит не только средства обхода элементов 1) описания 2) обработки 3) преобразования последовательности элементов 44) Сравнение стримов с [коллекцией коллекции предпологают хранение элементов и соответственно конечны Стримы бесконечны коллекции часто предоставляют индивидуальный доступ(индекс, ключ) Стрим такого не позволяет колекции можно менять, добавлять либо удалять элементы в том числе через итератора А применение трансформации к Стриму, ни как не влияют на источник откуда берется информация 45) Из каких частей состоит использование стримов? 1) получение Стрима откуда будут браться элементы последовательно 2) Ноль или более промежуточных преобразований. Стрим их запоминате но пока не выполняет 3) Единственная терминальная иоперация запускающая вес процесс вычесления и которая должна стать его полезным результатом. 4) Закрытие стрима вызвать метод Close, обязателен только в том случае, когда стрим выделял какието системные ресурсы.(файл, потоки) можно использовать в с трай ресурсами 46) В каком случае нужно закрывать стрим? 4) Закрытие стрима вызвать метод Close, обязателен только в том случае, когда стрим выделял какието системные ресурсы.(файл, потоки) можно использовать в с трай ресурсами 47) Первый этап работы со стримом 48) Откуда можно получить стрим? Получить стрим можно из любой коллекции с помощью стрим или получить из потока, с помощью метода lines(); Из дерриктории на диске с пмомощью list(), walk(); Получить из строчки с помощью метода shars() Стримы можно [пораждать динамически Например с помощью Supplier, который имеет один метод get() Итерирование какойто функции Диапазон в виде стрема 1) от начало диапазона до конца не в ключительно(0 - 99) 2) от начала до конца включительно(0 - 100) Конкатенации двух других Стримов Или взять пустой стрим из массива указать явно 1) Из коллекции: Stream Стрим из List: list.stream() Стрим из Map: map.entrySet().stream() 2) Из набора значений: Stream 3) Из массива: Stream 4) Из файла (каждая строка в файле будет отдельным элементом в стриме): Stream 5) Из строки: IntStream fromString = "0123456789".chars(); 6) С помощью Stream.builder(): Stream 7) С помощью Stream.iterate() (бесконечный): Stream 8) С помощью Stream.generate() (бесконечный): Stream 9) Создание паралельного стрима collection.parallelStream() Stream 50) Разница методов .list() и walk() Что такое саплер-поставщик? какой содержит метод? Как динамически получать стрим? Files.[list() возвращает массив файлов в указанной директории Files.[walk() возвращает поток файлов в указанной директории и субдиректориях Из опыта скажу, что list(); метод подразумевает когда мы указываем ему, где нужно проходить List возвращает список либо String либо File А метод walk(); сам идет в поддериктории ему просто надо указать на какую глубину нужно идти прогулка walk(); public static Stream walk(Path start, FileVisitOption... options) throws IOException DoubleStream doubleStream = DoubleStream.generate(Math::random);//сеплаер поставщик [Supplier (с англ. — поставщик) — функциональный интерфейс, который не принимает никаких аргументов, но возвращает некоторый объект типа T: который представляет собой оператор, предоставляющий значение для каждого вызова. Supplier имеет только один метод get() и не имеет метода по умолчанию. Supplier IntSupplier int getAsInt(); DoubleSupplier double getAsDouble(); LongSupplier long getAsLong(); BooleanSupplier boolean getAsBoolean(); 61) Как получить стрим диапазона чисел? IntStream smalInteger = IntStream.[range(0, 100);//Не выдает IntStream smallInteger2 = IntStream.range[Closed(0, 100); выдает последний элемент 62) В чем разница методов range и [rangeClosed? в том, что первый не выдает последний элемент а второй выдает. 63) Можно ли конкатенировать стримы? если да то каким методом? Можно ли получить [пустой стрим? да можно! IntStream cobiedStream = IntStream.concat(stream1,stream2);//конкатенация IntStream empty = IntStream.[empty();//пустой стрим взять с 9 джава 64) Отличия Абстрактного класса от интерфейса Фундаментальная разница между интерфейсом и абстрактным классом заключается в том, что интерфейс определяет только поведение. Он не сообщает ничего про объект, который будет его реализовывать. Например, такое поведение как «движение» может быть применимо к разным типам объектов: машина, кот, котировки курса и т. д. Эти объекты не имеют ничего общего, кроме того, что они могут двигаться. Перефразируем немного иначе — если существует «движущийся» объект, то глядя на реализованный им интерфейс, мы не сможем понять, какой именно тип объекта имеется ввиду. Это может быть машина, кот, котировка курса валют и много других вариантов. Если перенести это поведение в код, написанный на языке Java, то получится следующее: interface Movable { void move(); } Абстрактный же класс описывает некий абстрактный объект (автомобиль, человека, кота и т. д.), а не только поведение. Если мы рассуждаем про абстрактный «автомобиль», то в нашей голове сразу формируется картинка с объектом. Мы сразу понимаем, что автомобиль содержит двигатель, колеса и может двигаться, поворачивать, ускоряться или тормозить. Он также будет иметь поля для хранения внутренних деталей, таких как мотор, колеса и тормоза. Вы получите все это просто сказав слово «автомобиль». При этом кот и котировка курса валют не могут быть автомобилем, даже если они также могут двигаться. 65) Как получить стрим из [массива? double[] array = ...; DoubleStream doubleStream1 = Arrays.stream([array);//или из массива 66) Какой второй этап работы со стримом? Применение промежуточных методов. //в качестве промежуточной операции можно встроить peek(Consuver) с помощью него можно посмотреть какие объекты летают на разных этапах обработки для отладки можно передовать System.out::println 67) Перечислить основные промежуточные операции. Их предназначение. [Map() - Любое изменение исходного элемента можно делать с помощью метода map(). В качестве параметра метод принимает лямбда-выражение. [filter() - Отсеивание части объектов [sorted() - [peek()- доступ к элементу, не изменяя его, например вывести лог. [flatMap() - [skip() пропустить эл. [limit() ограничивает оставшиеся элементы 68) Для чего терминальные операции? Какие бывают и что делают? Терминальные (“terminal”, ещё называют “eager”) — обрабатывают элементы и завершают работу стрима, так что терминальный оператор в цепочке может быть только один. findFirst Возвращает первый элемент из стрима (возвращает Optional) collection.stream().findFirst().orElse(«1») [findAny Возвращает любой подходящий элемент из стрима (возвращает Optional) collection.stream().findAny().orElse(«1») [collect Представление результатов в виде коллекций и других структур данных collection.stream().filter((s) -> s.contains(«1»)).collect(Collectors.toList()) count Возвращает количество элементов в стриме collection.stream().filter(«a1»::equals).count() [anyMatch Возвращает true, если условие выполняется хотя бы для одного элемента collection.stream().anyMatch(«a1»::equals) [noneMatch Возвращает true, если условие не выполняется ни для одного элемента collection.stream().noneMatch(«a8»::equals) [allMatch Возвращает true, если условие выполняется для всех элементов collection.stream().allMatch((s) -> s.contains(«1»)) [min Возвращает минимальный элемент, в качестве условия использует компаратор collection.stream().min(String::compareTo).get() [max Возвращает максимальный элемент, в качестве условия использует компаратор collection.stream().max(String::compareTo).get() [forEach Применяет функцию к каждому объекту стрима, порядок при параллельном выполнении не гарантируется set.stream().forEach((p) -> p.append("_1")); [forEachOrdered Применяет функцию к каждому объекту стрима, сохранение порядка элементов гарантирует list.stream().forEachOrdered((p) -> p.append("_new")); [toArray Возвращает массив значений стрима collection.stream().map(String::toUpperCase).toArray(String[]::new); [reduce Позволяет выполнять агрегатные функции на всей коллекцией и возвращать один результат collection.stream().reduce((s1, s2) -> s1 + s2).orElse(0) Обратите внимание методы findFirst, findAny, anyMatch это short-circuiting методы, то есть обход стримов организуется таким образом чтобы найти подходящий элемент максимально быстро, а не обходить весь изначальный стрим. Краткое описание терминальных методов работы со стримами findFirst Возвращает первый элемент из стрима (возвращает Optional) collection.stream().findFirst().orElse(«1») findAny Возвращает любой подходящий элемент из стрима (возвращает Optional) collection.stream().findAny().orElse(«1») collect Представление результатов в виде коллекций и других структур данных collection.stream().filter((s) -> s.contains(«1»)).collect(Collectors.toList()) 69) Что такое [коллекторы? [collect(). Он используется для того, чтобы перейти от потоков к привычным коллекциям — List В метод collect() нужно передать специальный объект — collector. Этот объект вычитывает все данные из потока, преобразует их к определенной коллекции и возвращает ее. А следом за ним эту же коллекцию возвращает и сам метод collect. Все это сделано довольно хитро: объект collector имеет тип Collector Последний тип R — это обычно и есть тип вроде List Поэтому компилятор может по этому типу подставить правильный тип результата самого метода collect(). To[List() Объект, который преобразует поток в список — List To[Set() Объект, который преобразует поток во множество — Set [toMap() Объект, который преобразует поток в мэп — Map [joining() Склеивает элементы потока в одну строку [mapping() Преобразует элементы потока в Map [groupingBy() Группирует элементы, возвращает Map 70) Сколько раз можно вызывать терминльную операцию? Один раз. 71) Что такое метод референс? 1. Если лямбда выражения вызывают только один существующий метод, лучше ссылать на этот метод по его имени. Ссылки на методы (Method [References) – это компактные лямбда выражения для методов у которых уже есть имя. 2. Ссылка на статический метод 3. Ссылка на нестатический метод конкретного объекта 4. Ссылка на нестатический метод любого объекта конкретного типа 5. Ссылка на конструктор ContainingClass::staticMethodName Ссылка на статический метод containingObject::instanceMethodName Ссылка на нестатический метод конкретного объекта ContainingType::methodName Ссылка на нестатический метод любого объекта конкретного типа ClassName::new Ссылка на конструктор 72) В чем разница между foreach и foreach[Ordered void forEach(Consumer action) - выполняет указанное действие для каждого элемента стрима. void forEachOrdered(Consumer action) - Тоже выполняет указанное действие для каждого элемента стрима, но перед этим добивается правильного порядка вхождения элементов. Используется для параллельных стримов, когда нужно получить правильную последовательность элементов. |