Главная страница
Навигация по странице:

  • Какой символ является разделителем при указании пути в файловой

  • Что такое «абсолютный путь» и «относительный путь»

  • Что такое «символьная ссылка»

  • Что такое default-методы интерфейса

  • Как вызывать default-метод интерфейса в реализующем этот интерфейс

  • Что такое static-метод интерфейса

  • Как вызывать static метод интерфейса

  • К каким переменным есть доступ у лямбда-выражений

  • Как отсортировать список строк с помощью лямбда-выражения

  • Какие виды ссылок на методы вы знаете

  • Какие существуют способы создания стрима

  • В чем разница между Collection и Stream

  • Для чего нужен метод collect() в стримах

  • Для чего в стримах применяются методы forEach() и forEachOrdered()

  • Для чего в стримах предназначены методы map() и mapToInt()

  • Какова цель метода filter() в стримах

  • Для чего в стримах предназначен метод limit()

  • Для чего в стримах предназначен метод sorted()

  • Для чего в стримах предназначены методы flatMap(), flatMapToInt()

  • Расскажите о параллельной обработке в Java 8

  • ОглавлениеCore


    Скачать 1.53 Mb.
    НазваниеОглавлениеCore
    Дата17.05.2023
    Размер1.53 Mb.
    Формат файлаpdf
    Имя файлаpolnaya_metodichka (1).pdf
    ТипДокументы
    #1138113
    страница12 из 25
    1   ...   8   9   10   11   12   13   14   15   ...   25
    Какие режимы доступа к файлу есть у RandomAccessFile?
    «r» открывает файл только для чтения. Запуск любых методов записи данных приведет к выбросу исключения IOException.
    «rw» открывает файл для чтения и записи. Если файл еще не создан, то осуществляется попытка создать его.
    «rws» открывает файл для чтения и записи подобно «rw», но требует от системы при каждом изменении содержимого файла или метаданных синхронно записывать эти изменения на физический носитель.
    «rwd» открывает файл для чтения и записи подобно «rws», но требует от системы синхронно записывать изменения на физический носитель только при каждом изменении содержимого файла. Если изменяются метаданные, синхронная запись не требуется.

    Какой символ является разделителем при указании пути в файловой
    системе?
    Для различных операционных систем символ разделителя различается. Для Windows это \,
    для Linux – /.
    В Java получить разделитель для текущей операционной системы можно через обращение к статическому полю File.separator.
    Что такое «абсолютный путь» и «относительный путь»?
    Абсолютный (полный) путь – это путь, который указывает на одно и то же место в файловой системе вне зависимости от текущей рабочей директории или других обстоятельств. Полный путь всегда начинается с корневого каталога.
    Относительный путь представляет собой путь по отношению к текущему рабочему каталогу пользователя или активного приложения.
    Что такое «символьная ссылка»?
    Символьная (символическая) ссылка (также «симлинк», Symbolic link) – специальный файл в файловой системе, в котором вместо пользовательских данных содержится путь к файлу,
    который должен быть открыт при попытке обратиться к данной ссылке (файлу). Целью ссылки может быть любой объект: например, другая ссылка, файл, каталог или даже несуществующий файл (в последнем случае при попытке открыть его должно выдаваться сообщение об отсутствии файла).
    Символьные ссылки используются для более удобной организации структуры файлов на компьютере, так как:

    позволяют для одного файла или каталога иметь несколько имен и различных атрибутов;

    свободны от некоторых ограничений, присущих жестким ссылкам (последние действуют только в пределах одной файловой системы (одного раздела) и не могут ссылаться на каталоги).
    Что такое default-методы интерфейса?
    Java 8 позволяет добавлять неабстрактные реализации методов в интерфейс, используя ключевое слово default:
    interface Example {
    int process(int a);
    default void show() {
    System.out.println("default show()");
    }
    }
    Если класс реализует интерфейс, он может, но не обязан, реализовать методы по умолчанию, уже реализованные в интерфейсе. Класс наследует реализацию по умолчанию.
    Если некий класс реализует несколько интерфейсов, которые имеют одинаковый метод по умолчанию, то класс должен реализовать метод с совпадающей сигнатурой самостоятельно.

    Ситуация аналогична, если один интерфейс имеет метод по умолчанию, а в другом этот же метод является абстрактным – никакой реализации по умолчанию классом не наследуется.
    Метод по умолчанию не может переопределить метод класса java.lang.Object.
    Помогают реализовывать интерфейсы без страха нарушить работу других классов.
    Позволяют избежать создания служебных классов, так как все необходимые методы могут быть представлены в самих интерфейсах.
    Дают свободу классам выбрать метод, который нужно переопределить.
    Одной из основных причин внедрения методов по умолчанию является возможность коллекций в Java 8 использовать лямбда-выражения.
    Как вызывать default-метод интерфейса в реализующем этот интерфейс
    классе?
    Используя ключевое слово super вместе с именем интерфейса:
    Paper.super.show();
    Что такое static-метод интерфейса?
    Статические методы интерфейса похожи на методы по умолчанию, за исключением того, что для них отсутствует возможность переопределения в классах, реализующих интерфейс.
    Статические методы в интерфейсе являются частью интерфейса без возможности использовать их для объектов класса реализации.
    Методы класса java.lang.Object нельзя переопределить как статические.
    Статические методы в интерфейсе используются для обеспечения вспомогательных методов, например, проверки на null, сортировки коллекций и т. д.
    Как вызывать static метод интерфейса?
    Используя имя интерфейса:
    Paper.show();
    Что такое «лямбда»? Какова структура и особенности использования
    лямбда-выражения?
    Лямбда представляет собой набор инструкций, которые можно выделить в отдельную переменную и затем многократно вызвать в различных местах программы.
    Основу лямбда-выражения составляет лямбда-оператор, который представляет стрелку ->.
    Этот оператор разделяет лямбда-выражение на две части: левая часть содержит список параметров выражения, а правая представляет тело лямбда-выражения, где выполняются все действия.
    Лямбда-выражение не выполняется само по себе, а образует реализацию метода,
    определенного в функциональном интерфейсе. При этом важно, что функциональный интерфейс должен содержать только один единственный метод без реализации.
    По факту лямбда-выражения являются в некотором роде сокращенной формой внутренних анонимных классов, которые ранее применялись в Java.

    Отложенное выполнение (deferred execution) лямбда-выражения определяется один раз в одном месте программы, вызываются при необходимости любое количество раз и в произвольном месте программы.
    Параметры лямбда-выражения должны соответствовать по типу параметрам метода функционального интерфейса:
    operation = (int x, int y) -> x + y;
    //При написании самого лямбда-выражения тип параметров разрешается не указывать:
    (x, y) -> x + y;
    //Если метод не принимает никаких параметров, то пишутся пустые скобки, например:
    () -> 30 + 20;
    //Если метод принимает только один параметр, то скобки можно опустить:
    n -> n * n;
    Конечные лямбда-выражения не обязаны возвращать какое-либо значение.
    Блочные лямбда-выражения обрамляются фигурными скобками. В блочных лямбда- выражениях можно использовать внутренние вложенные блоки, циклы, конструкции if, switch,
    создавать переменные и т. д. Если блочное лямбда-выражение должно возвращать значение, то явным образом применяется оператор return:
    Operationable operation = (int x, int y) -> {
    if (y == 0) {
    return 0;
    }
    else {
    return x / y;
    }
    }
    Передача лямбда-выражения в качестве параметра метода:
    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));
    }
    К каким переменным есть доступ у лямбда-выражений?
    Доступ к переменным внешней области действия из лямбда-выражения очень схож с доступом из анонимных объектов. Можно ссылаться на:

    неизменяемые (effectively final – не обязательно помеченные как final) локальные переменные;

    поля класса;

    статические переменные.
    К методам по умолчанию реализуемого функционального интерфейса обращаться внутри лямбда-выражения запрещено.
    Как отсортировать список строк с помощью лямбда-выражения?
    public static List sort(List list){
    Collections.sort(list, (a, b) -> a.compareTo(b));
    return list;
    }
    Что такое «ссылка на метод»?
    Если существующий в классе метод уже делает все, что необходимо, то можно воспользоваться механизмом method reference (ссылка на метод) для непосредственной передачи этого метода. Такая ссылка передается в виде:

    имя_класса::имя_статического_метода для статического метода;

    объект_класса::имя_метода для метода экземпляра;

    название_класса::new для конструктора.
    Результат будет в точности таким же, как в случае определения лямбда-выражения, которое вызывает этот метод.
    private interface Measurable {
    public int length(String string);
    }
    public static void main(String[] args) {
    Measurable a = String::length;
    System.out.println(a.length("abc"));
    }

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

    на статический метод;

    на метод экземпляра;

    на конструктор.
    Объясните выражение System.out::println.
    Данное выражение иллюстрирует механизм instance method reference: передачи ссылки на метод println() статического поля out класса System.
    Что такое 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().
    Какие существуют способы создания стрима?

    Из коллекции:
    Stream fromCollection = Arrays.asList("x", "y", "z").stream();


    Из набора значений:
    Stream fromValues = Stream.of("x", "y", "z");

    Из массива:
    Stream fromArray = Arrays.stream(new String[]{"x", "y", "z"});

    Из файла (каждая строка в файле будет отдельным элементом в стриме):
    Stream fromFile = Files.lines(Paths.get("input.txt"));

    Из строки:
    IntStream fromString = "0123456789".chars();

    С помощью Stream.builder():
    Stream fromBuilder = Stream.builder().add("z").add("y").add("z").build();

    С помощью Stream.iterate() (бесконечный):
    Stream fromIterate = Stream.iterate(1, n -> n + 1);

    С помощью Stream.generate() (бесконечный):
    Stream fromGenerate = Stream.generate(() -> "0");
    В чем разница между Collection и Stream?
    Коллекции позволяют работать с элементами по отдельности, тогда как стримы так делать не позволяют, но вместо этого предоставляют возможность выполнять функции над данными как над одним целым.
    Стоит отметить важность самой концепции сущностей: Collection – это прежде всего воплощение структуры данных. Например, Set не просто хранит в себе элементы, он реализует идею множества с уникальными элементами, тогда как Stream – это прежде всего абстракция, необходимая для реализации конвейера вычислений, поэтому результатом работы конвейера являются те или иные структуры данных или же результаты проверок/поиска и т. п.
    Для чего нужен метод 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;

    groupingBy() разделяет коллекцию на несколько частей и возвращает MapList>;

    mapping() – дополнительные преобразования значений для сложных Collector-ов.
    Также существует возможность создания собственного коллектора через Collector.of():
    Collector, List> toList = Collector.of(
    ArrayList::new,
    List::add,
    (l1, l2) -> { l1.addAll(l2); return l1; }
    );
    Для чего в стримах применяются методы forEach() и forEachOrdered()?
    forEach() применяет функцию к каждому объекту стрима, порядок при параллельном выполнении не гарантируется;
    forEachOrdered() применяет функцию к каждому объекту стрима с сохранением порядка элементов.
    Для чего в стримах предназначены методы map() и mapToInt(),
    mapToDouble(), mapToLong()?
    Метод map() является промежуточной операцией, которая заданным образом преобразует каждый элемент стрима.
    mapToInt(), mapToDouble(), mapToLong() – аналоги map(), возвращающие соответствующий числовой стрим (то есть стрим из числовых примитивов):
    Stream
    .of("12", "22", "4", "444", "123")
    .mapToInt(Integer::parseInt)
    .toArray(); //[12, 22, 4, 444, 123]
    Какова цель метода filter() в стримах?
    Метод filter() является промежуточной операцией, принимающей предикат, который фильтрует все элементы, возвращая только те, что соответствуют условию.
    Для чего в стримах предназначен метод limit()?
    Метод limit() является промежуточной операцией, которая позволяет ограничить выборку определенным количеством первых элементов.

    Для чего в стримах предназначен метод sorted()?
    Метод sorted() является промежуточной операцией, которая позволяет сортировать значения либо в натуральном порядке, либо задавая Comparator.
    Порядок элементов в исходной коллекции остается нетронутым – sorted() всего лишь создает его отсортированное представление.
    Для чего в стримах предназначены методы flatMap(), flatMapToInt(),
    flatMapToDouble(), flatMapToLong()?
    Метод flatMap() похож на map, но может создавать из одного элемента несколько. Таким образом, каждый объект будет преобразован в ноль, один или несколько других объектов,
    поддерживаемых потоком. Наиболее очевидный способ применения этой операции –
    преобразование элементов контейнера при помощи функций, которые возвращают контейнеры.
    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
    Стримы могут быть последовательными и параллельными. Операции над последовательными стримами выполняются в одном потоке процессора, над параллельными используются несколько потоков процессора. Параллельные стримы используют общий ForkJoinPool, доступный через статический метод
    ForkJoinPool.commonPool(). При этом, если окружение не является многоядерным, то поток будет выполняться как последовательный. Фактически применение параллельных стримов сводится к тому, что данные в стримах будут разделены на части, каждая часть обрабатывается на отдельном ядре процессора, и в конце эти части соединяются и над ними выполняются конечные операции.
    Для создания параллельного потока из коллекции можно использовать метод parallelStream()
    интерфейса Collection.
    Чтобы сделать обычный последовательный стрим параллельным, надо вызвать у объекта
    Stream метод parallel(). Метод isParallel() позволяет узнать, является ли стрим параллельным.
    С помощью методов parallel() и sequential() можно определять, какие операции могут быть параллельными, а какие только последовательными. Также из любого последовательного стрима можно сделать параллельный и наоборот:
    collection
    .stream()
    .peek(...) // операция последовательна
    .parallel()

    .map(...) // операция может выполняться параллельно,
    .sequential()
    .reduce(...) // операция снова последовательна
    Как правило, элементы передаются в стрим в том же порядке, в котором они определены в источнике данных. При работе с параллельными стримами система сохраняет порядок следования элементов. Исключение составляет метод forEach(), который может выводить элементы в произвольном порядке. И чтобы сохранить порядок следования, необходимо применять метод forEachOrdered().
    Критерии, которые могут повлиять на производительность в параллельных стримах:
    Размер данных – чем больше данных, тем сложнее сначала разделять данные, а потом их соединять.
    Количество ядер процессора. Теоретически, чем больше ядер в компьютере, тем быстрее программа будет работать. Если на машине одно ядро, нет смысла применять параллельные потоки.
    Чем проще структура данных, с которой работает поток, тем быстрее будут происходить операции. Например, данные из ArrayList легко использовать, так как структура данной коллекции предполагает последовательность несвязанных данных. А вот коллекция типа
    LinkedList – не лучший вариант, так как в последовательном списке все элементы связаны с предыдущими/последующими. И такие данные трудно распараллелить.
    Над данными примитивных типов операции будут производиться быстрее, чем над объектами классов.
    Крайне не рекомендуется использовать параллельные стримы для сколько-нибудь долгих операций (например, сетевых соединений), так как все параллельные стримы работают c одним ForkJoinPool, то такие долгие операции могут остановить работу всех параллельных стримов в JVM из-за отсутствия доступных потоков в пуле, т. е. параллельные стримы стоит использовать лишь для коротких операций, где счет идет на миллисекунды, но не для тех,
    где счет может идти на секунды и минуты.
    Сохранение порядка в параллельных стримах увеличивает издержки при выполнении, и если порядок не важен, то имеется возможность отключить его сохранение, тем самым увеличить производительность, использовав промежуточную операцию unordered():
    collection.parallelStream()
    .sorted()
    .unordered()
    .collect(Collectors.toList());
    1   ...   8   9   10   11   12   13   14   15   ...   25


    написать администратору сайта