Solutions for Java Advanced course
Домашнее задание 1. Обход файлов
- Разработайте класс
Walk
, осуществляющий подсчет хеш-сумм файлов.
1.1. Формат запуска.java Walk
<входной файл> <выходной файл>. 1.2. Входной файл содержит список файлов, которые требуется обойти.
1.3. Выходной файл должен содержать по одной строке для каждого файла. Формат строки:
<шестнадцатеричная хеш-сумма> <путь к файлу>. 1.4. Для подсчета хеш-суммы используйте 64-битную версию алгоритма PJW.
1.5. Если при чтении файла возникают ошибки, укажите в качестве его хеш-суммы 0000000000000000.
1.6. Кодировка входного и выходного файлов — UTF-8.
1.7. Если родительская директория выходного файла не существует, то соответствующий путь надо создать.
1.8. Размеры файлов могут превышать размер оперативной памяти.
1.9. Пример
Входной файл
samples/1
samples/12
samples/123
samples/1234
samples/1
samples/binary
samples/no-such-file
Выходной файл
0000000000000031 samples/1
0000000000003132 samples/12
0000000000313233 samples/123
0000000031323334 samples/1234
0000000000000031 samples/1
005501015554abff samples/binary
0000000000000000 samples/no-such-file
- Сложный вариант:
2.1. Разработайте классRecursiveWalk
, осуществляющий подсчет хеш-сумм файлов в директориях.
2.2. Входной файл содержит список файлов и директорий, которые требуется обойти. Обход директорий осуществляется рекурсивно.
2.3. Пример
Входной файл
samples/binary
samples
samples/no-such-file
Выходной файл
005501015554abff samples/binary
0000000000000031 samples/1
0000000000003132 samples/12
0000000000313233 samples/123
0000000031323334 samples/1234
005501015554abff samples/binary
0000000000000000 samples/no-such-file
- При выполнении задания следует обратить внимание на:
- Дизайн и обработку исключений, диагностику ошибок.
- Программа должна корректно завершаться даже в случае ошибки.
- Корректная работа с вводом-выводом.
- Отсутствие утечки ресурсов.
- Требования к оформлению задания.
- Проверяется исходный код задания.
- Весь код должен находиться в пакете info.kgeorgiy.ja.фамилия.walk.
- Тесты к домашним заданиям.
Домашнее задание 2. Множество на массиве
- Разработайте класс
ArraySet
, реализующие неизменяемое упорядоченное множество.
- Класс
ArraySet
должен реализовывать интерфейсSortedSet
(простой вариант) илиNavigableSet
(сложный вариант). - Все операции над множествами должны производиться с максимально возможной асимптотической эффективностью.
- При выполнении задания следует обратить внимание на:
- Применение стандартных коллекций.
- Избавление от повторяющегося кода.
Домашнее задание 3. Студенты
- Разработайте класс
StudentDB
, осуществляющий поиск по базе данных студентов.
- Класс
StudentDB
должен реализовывать интерфейсStudentQuery
(простой вариант) илиGroupQuery
(сложный вариант). - Каждый метод должен состоять из ровно одного оператора. При этом длинные операторы надо разбивать на несколько строк.
- При выполнении задания следует обратить внимание на:
- применение лямбда-выражений и потоков;
- избавление от повторяющегося кода.
Домашнее задание 4. Implementor
- Реализуйте класс
Implementor
, который будет генерировать реализации классов и интерфейсов.
- Аргумент командной строки: полное имя класса/интерфейса, для которого требуется сгенерировать реализацию.
- В результате работы должен быть сгенерирован java-код класса с суффиксом Impl, расширяющий (реализующий) указанный класс (интерфейс).
- Сгенерированный класс должен компилироваться без ошибок.
- Сгенерированный класс не должен быть абстрактным.
- Методы сгенерированного класса должны игнорировать свои аргументы и возвращать значения по умолчанию.
- В задании выделяются три варианта:
- Простой —
Implementor
должен уметь реализовывать только интерфейсы (но не классы). Поддержка generics не требуется. - Сложный —
Implementor
должен уметь реализовывать и классы, и интерфейсы. Поддержка generics не требуется. - Бонусный —
Implementor
должен уметь реализовывать generic-классы и интерфейсы. Сгенерированный код должен иметь корректные параметры типов и не порождать UncheckedWarning.
Домашнее задание 5. Jar Implementor
- Создайте .jar-файл, содержащий скомпилированный
Implementor
и сопутствующие классы. - Созданный .jar-файл должен запускаться командой java -jar.
- Запускаемый .jar-файл должен принимать те же аргументы командной строки, что и класс
Implementor
. - Модифицируйте
Implemetor
так, чтобы при запуске с аргументами -jar имя-класса файл.jar он генерировал .jar-файл с реализацией соответствующего класса (интерфейса). - Для проверки, кроме исходного кода так же должны быть представлены:
- скрипт для создания запускаемого .jar-файла, в том числе, исходный код манифеста;
- запускаемый .jar-файл.
- Данное домашнее задание сдается только вместе с предыдущим. Предыдущее домашнее задание отдельно сдать будет нельзя.
Сложный вариант. Решение должно быть модуляризовано.
Домашнее задание 6. Javadoc
- Документируйте класс Implementor и сопутствующие классы с применением Javadoc.
- Должны быть документированы все классы и все члены классов, в том числе
private
. - Документация должна генерироваться без предупреждений.
- Сгенерированная документация должна содержать корректные ссылки на классы стандартной библиотеки.
- Для проверки, кроме исходного кода так же должны быть представлены:
- скрипт для генерации документации;
- сгенерированная документация.
- Данное домашнее задание сдается только вместе с предыдущим. Предыдущее домашнее задание отдельно сдать будет нельзя.
Домашнее задание 7. Итеративный параллелизм
- Реализуйте класс
IterativeParallelism
, который будет обрабатывать списки в несколько потоков. - В простом варианте должны быть реализованы следующие методы:
minimum(threads, list, comparator)
— первый минимум;maximum(threads, list, comparator)
— первый максимум;all(threads, list, predicate)
— проверка, что все элементы списка удовлетворяют предикату;any(threads, list, predicate)
— проверка, что существует элемент списка, удовлетворяющий предикату.
- В сложном варианте должны быть дополнительно реализованы следующие методы:
filter(threads, list, predicate)
— вернуть список, содержащий элементы удовлетворяющие предикату;map(threads, list, function)
— вернуть список, содержащий результаты применения функции;join(threads, list)
— конкатенация строковых представлений элементов списка.
- Во все функции передается параметр
threads
— сколько потоков надо использовать при вычислении. Вы можете рассчитывать, что число потоков не велико. - Не следует рассчитывать на то, что переданные компараторы, предикаты и функции работают быстро.
- При выполнении задания нельзя использовать Concurrency Utilities.
- Рекомендуется подумать, какое отношение к заданию имеют моноиды.
Домашнее задание 8. Параллельный запуск
- Напишите класс
ParallelMapperImpl
, реализующий интерфейсParallelMapper
.
public interface ParallelMapper extends AutoCloseable {
<T, R> List<R> map(
Function<? super T, ? extends R> f,
List<? extends T> args
) throws InterruptedException;
@Override
void close() throws InterruptedException;
}
- Метод run должен параллельно вычислять функцию
f
на каждом из указанных аргументов (args
). - Метод
close
должен останавливать все рабочие потоки. - Конструктор
ParallelMapperImpl(int threads)
создаетthreads
рабочих потоков, которые могут быть использованы для распараллеливания. - К одному
ParallelMapperImpl
могут одновременно обращаться несколько клиентов. - Задания на исполнение должны накапливаться в очереди и обрабатываться в порядке поступления.
В реализации не должно быть активных ожиданий.
- Доработайте класс
IterativeParallelism
так, чтобы он мог использоватьParallelMapper
.
- Добавьте конструктор
IterativeParallelism(ParallelMapper)
. - Методы класса должны делить работу на threads фрагментов и исполнять их при помощи
ParallelMapper
. - При наличии
ParallelMapper
самIterativeParallelism
новые потоки создавать не должен. - Должна быть возможность одновременного запуска и работы нескольких клиентов, использующих один
ParallelMapper
.
Домашнее задание 9. Web Crawler
Напишите потокобезопасный класс WebCrawler
, который будет рекурсивно обходить сайты.
- Класс
WebCrawler
должен иметь конструктор.
public WebCrawler(Downloader downloader, int downloaders, int extractors, int perHost)
downloader
позволяет скачивать страницы и извлекать из них ссылки;downloaders
— максимальное число одновременно загружаемых страниц;extractors
— максимальное число страниц, из которых одновременно извлекаются ссылки;perHost
— максимальное число страниц, одновременно загружаемых c одного хоста. Для определения хоста следует использовать методgetHost
классаURLUtils
из тестов.
- Класс
WebCrawler
должен реализовывать интерфейсCrawler
.
public interface Crawler extends AutoCloseable {
Result download(String url, int depth);
void close();
}
- Метод
download
должен рекурсивно обходить страницы, начиная с указанного URL на указанную глубину и возвращать список загруженных страниц и файлов. Например, если глубина равна 1, то должна быть загружена только указанная страница. Если глубина равна 2, то указанная страница и те страницы и файлы, на которые она ссылается и так далее. Этот метод может вызываться параллельно в нескольких потоках. - Загрузка и обработка страниц (извлечение ссылок) должна выполняться максимально параллельно, с учетом ограничений на число одновременно загружаемых страниц (в том числе с одного хоста) и страниц, с которых загружаются ссылки.
- Для распараллеливания разрешается создать до
downloaders + extractors
вспомогательных потоков. - Загружать и/или извлекать ссылки из одной и той же страницы в рамках одного обхода (
download
) запрещается. - Метод
close
должен завершать все вспомогательные потоки.
- Для загрузки страниц должен применяться
Downloader
, передаваемый первым аргументом конструктора.
public interface Downloader {
public Document download(final String url) throws IOException;
}
- Метод
download
загружает документ по его адресу (URL). - Документ позволяет получить ссылки по загруженной странице:
public interface Document {
List<String> extractLinks() throws IOException;
}
Ссылки, возвращаемые документом, являются абсолютными и имеют схему http или https.
4. Должен быть реализован метод main
, позволяющий запустить обход из командной строки.
-
Командная строка
WebCrawler url [depth [downloads [extractors [perHost]]]]
-
Для загрузки страниц требуется использовать реализацию
CachingDownloader
из тестов.
- Версии задания:
- Простая — не требуется учитывать ограничения на число одновременных закачек с одного хоста (
perHost >= downloaders
). - Полная — требуется учитывать все ограничения.
- Бонусная — сделать параллельный обод в ширину.
Домашнее задание 10. HelloUDP
- Реализуйте клиент и сервер, взаимодействующие по UDP.
- Класс
HelloUDPClient
должен отправлять запросы на сервер, принимать результаты и выводить их на консоль.
- Аргументы командной строки:
2.1. имя или ip-адрес компьютера, на котором запущен сервер;
2.2. номер порта, на который отсылать запросы;
2.3. префикс запросов (строка);
2.4. число параллельных потоков запросов;
2.5. число запросов в каждом потоке. - Запросы должны одновременно отсылаться в указанном числе потоков. Каждый поток должен ожидать обработки своего запроса и выводить сам запрос и результат его обработки на консоль. Если запрос не был обработан, требуется послать его заново.
- Запросы должны формироваться по схеме
<префикс запросов><номер потока>_<номер запроса в потоке>
.
- Класс
HelloUDPServer
должен принимать задания, отсылаемые классомHelloUDPClient
и отвечать на них.
- Аргументы командной строки:
3.1. номер порта, по которому будут приниматься запросы;
3.2. число рабочих потоков, которые будут обрабатывать запросы. - Ответом на запрос должно быть
Hello, <текст запроса>
. - Если сервер не успевает обрабатывать запросы, прием запросов может быть временно приостановлен.
Домашнее задание 11. Физические лица
- Добавьте к банковскому приложению возможность работы с физическими лицами.
- У физического лица (
Person
) можно запросить имя, фамилию и номер паспорта. - Локальные физические лица (
LocalPerson
) должны передаваться при помощи механизма сериализации. - Удалённые физические лица (
RemotePerson
) должны передаваться при помощи удалённых объектов. - Должна быть возможность поиска физического лица по номеру паспорта, с выбором типа возвращаемого лица.
- Должна быть возможность создания записи о физическом лице по его данным.
- У физического лица может быть несколько счетов, к которым должен предоставляться доступ.
- Счету физического лица с идентификатором
subId
должен соответствовать банковский счет сid
видаpassport:subId
. - Изменения, производимые со счетом в банке (создание и изменение баланса), должны быть видны всем соответствующим
RemotePerson
, и только темLocalPerson
, которые были созданы после этого изменения. - Изменения в счетах, производимые через
RemotePerson
, должны сразу применяться глобально, а производимые черезLocalPerson
– только локально для этого конкретногоLocalPerson
.
- Реализуйте приложение, демонстрирующее работу с физическим лицами.
- Аргументы командной строки: имя, фамилия, номер паспорта физического лица, номер счета, изменение суммы счета.
- Если информация об указанном физическом лице отсутствует, то оно должно быть добавлено. В противном случае – должны быть проверены его данные.
- Если у физического лица отсутствует счет с указанным номером, то он создается с нулевым балансом.
- После обновления суммы счета новый баланс должен выводиться на консоль.
- Напишите тесты, проверяющее вышеуказанное поведение как банка, так и приложения.
- Для реализации тестов рекомендуется использовать JUnit (Tutorial). Множество примеров использования можно найти в тестах.
- Если вы знакомы с другим тестовым фреймворком (например, TestNG), то можете использовать его.
- Jar-файлы используемых библиотек надо класть в каталог lib вашего репозитория.
- Использовать самописные фреймворки и тесты запускаемые через
main
нельзя.
- Сложный вариант
- Тесты не должны рассчитывать на наличие запущенного RMI Registry.
- Создайте класс
BankTests
, запускающий тесты. - Создайте скрипт, запускающий
BankTests
и возвращающий код (статус) 0 в случае успеха и 1 в случае неудачи. - Создайте скрипт, запускающий тесты с использованием стандартного подхода для вашего тестового фреймворка. Код возврата должен быть как в предыдущем пункте.
Домашнее задание 12. HelloNonblockingUDP
- Реализуйте клиент и сервер, взаимодействующие по UDP, используя только неблокирующий ввод-вывод.
- Класс
HelloUDPNonblockingClient
должен иметь функциональность аналогичнуюHelloUDPClient
, но без создания новых потоков. - Класс
HelloUDPNonblockingServer
должен иметь функциональность аналогичнуюHelloUDPServer
, но все операции с сокетом должны производиться в одном потоке. - В реализации не должно быть активных ожиданий, в том числе через
Selector
. - Обратите внимание на выделение общего кода старой и новой реализации.
- Бонусный вариант. Клиент и сервер могут перед началом работы выделить O(число потоков) памяти. Выделять дополнительную память во время работы запрещено.
Домашнее задание 13. Статистика текста
- Создайте приложение
TextStatistics
, анализирующее тексты на различных языках.
- Аргументы командной строки:
1.1. локаль текста,
1.2. локаль вывода,
1.3. файл с текстом,
1.4. файл отчета. - Поддерживаемые локали текста: все локали, имеющиеся в системе.
- Поддерживаемые локали вывода: русская и английская.
- Файлы имеют кодировку UTF-8.
- Подсчет статистики должен вестись по следующим категориям:
1.1. предложения,
1.2. слова,
1.3. числа,
1.4. деньги,
1.5. даты. - Для каждой категории должна собираться следующая статистика:
1.1. число вхождений,
1.2. число различных значений,
1.3. минимальное значение,
1.4. максимальное значение,
1.5. минимальная длина,
1.6. максимальная длина,
1.7. среднее значение/длина. - Пример отчета:
Анализируемый файл "input.txt".
Сводная статистика
Число предложений: 43.
Число слов: 275.
Число чисел: 40.
Число сумм: 3.
Число дат: 3.
Статистика по предложениям
Число предложений: 43 (43 различных).
Минимальное предложение: "Аргументы командной строки: локаль текста, локаль вывода, файл с текстом, файл отчета.".
Максимальное предложение: "Число чисел: 40.".
Минимальная длина предложения: 13 ("Число дат: 3.").
Максимальная длина предложения: 211 ("GK: если сюда поставить реальное предложение, то процесс не сойдётся").
Средняя длина предложения: 55,465.
Статистика по словам
Число слов: 275 (157 различных).
Минимальное слово: "GK".
Максимальное слово: "языках".
Минимальная длина слова: 1 ("с").
Максимальная длина слова: 14 ("TextStatistics").
Средняя длина слова: 6,72.
Статистика по числам
Число чисел: 40 (24 различных).
Минимальное число: -12345,0.
Максимальное число: 12345,67.
Среднее число: 207,676.
Статистика по суммам денег
Число сумм: 3 (3 различных).
Минимальная сумма: 100,00 ₽.
Максимальная сумма: 345,67 ₽.
Средняя сумма: 222,83 ₽.
Статистика по датам
Число дат: 3 (3 различных).
Минимальная дата: 22 мая 2021 г..
Максимальная дата: 8 июн. 2021 г..
Средняя дата: 30 мая 2021 г..
- Вы можете рассчитывать на то, что весь текст помещается в память.
- При выполнении задания следует обратить внимание на:
- Декомпозицию сообщений для локализации
- Согласование сообщений по роду и числу
- Напишите тесты, проверяющее вышеуказанное поведение приложения.