java задачи для тренировки
Список задач по Java для начинающих
Если вы начинающий Java программист то вам обязательно нужно ознакомится и выполнить все задания из этого списка.
Условные операторы
1. Найти наибольшее значение из двух переменных, трех, четырех, описать общий принцип для большего числа
3. Определить какой четверти принадлежит точка с координатами (х,у)
4. Найти суммы только положительных из трех чисел
5. Посчитать выражение макс(а*б*с, а+б+с)+3
6. Есть два конверта со сторонами (а,б) и (с,д) определить, можно ли один конверт вложить в другой
7. Отсортировать значения двух, трех, четырех переменных используя только условные операторы
8. Написать программу определения оценки студента по его рейтингу, на основе следующих правил:
рейтинг Оценка
Путем минимальных изменений модифицируйте код таким образом, чтобы на экране было напечатано
134 (при a =2 и b= 4)
4 (при a =2 и b= 44)
14 (при a =2 и b= 4)
1 (при a =2 и b= 4)
Циклы
1. найти сумму четных чисел и их количество в диапазоне от 1 до 99
2. Проверить простое ли число? (число называется простым, если оно делится только само на себя и на 1)
3. Вывести на экран квадрат, со стороной а
4. Вывести шахматную доску с заданными размерами, по принципу:
5. Напишите программу, которая определяет, является ли введенное число палиндромом? (Палиндром – число или текст, которые одинаково читаются слева направо и справа налево)
6. Вывести все простые числа в диапазоне от 2 до n
7. Вывести все натуральные числа, квадрат которых больше меньше заданного числа n
8. Вывести все делители числа
9. Найти корень натурального числа с точностью до целого (рассмотреть переборный вариант, и метод бинарного поиска)
10. Теорема Пифагора: вывести все прямоугольные треугольники, стороны которых – натуральные числа меньше 1000, посчитать их количество(по теореме Пифагора у прямоугольного треугольника сумма квадратов катетов равна квадрату гипотенузы). Подсказка: использовать полный перебор с трижды вложенными циклами.
11. Вычислить факториал числа n. n! = 1*2*…*n-1*n;
12. Вычислить среднее значение чисел, не являющихся простыми, в диапазоне от 1 до n.
13. Посчитать сумму цифр заданного числа
14. Вывести число, которое является зеркальным отображением последовательности цифр заданного числа, например, задано число 123, вывести 321.
15. Вставить цифру в число не прибегая к строковым преобразованиям.
Одномерные массивы
Функции
Рекурсия
Найти наибольшее значение из двух переменных, трех, четырех, описать общий принцип для большего числа
Хорошая задача, но она мало чем отличается от задачи №7 из темы «Условные операторы», описанной выше.
Если вас интересует ее решение — то «для большего числа» целесообразно использовать любой метод сортировки массива.
Хитрые задачи по Java
Совсем недавно я сдал OCA Java SE 7 Programmer I. За время подготовки успел решить огромное количество задач и извлечь из них много тонких моментов языка. Самые интересные и ловкие — сохранял на будущее. И вот у меня накопилась небольшая личная коллекция, лучшую часть которой я здесь и опишу.
В замечательной статье Знаешь ли ты JAVA, %username% и её второй части автор тоже поделился опытом после подготовки. Однако я пришёл к выводу, что могу добавить что-то своё. Так и зародилась эта статья.
Задачи
Итак, начнём. Я разбил все хитрости на маленькие задачки, которые составил специально для вас. Тонкости языка выделяются в чистом виде — без лишних наворотов и заблуждений, как это было в тестах. Также я рекомендую вам сначала ответить на вопрос с точностью до символа и записать куда-нибудь, а потом уже смотреть правильный ответ. Интересно, сколько пользователей, решивших этот тест, ответит больше чем на половину? И не забывайте, что все эти примеры ориентированы на Java 7.
1)Скомпилируется ли данный код и если да — то каким будет вывод?
Я специально выключил подсветку — чтобы не было заметно подвоха. Иначе последняя буква визуально выделялась бы — а в ней вся соль вопроса.
В английском языке строчная буква l очень похожа на цифру 1. И этим примером я хочу вас предостеречь — никогда не используйте l маленькую для обозначения long-литералов, хотя Java это позволяет. И вообще не используете её там, где потенциально может быть единица. Просто возьмите за правило использовать прописную L, как это и делает большинство программистов.
Если посмотреть внимательно, то можно заметить, что единицы визуально чуточку отличаются. Совсем капельку. Но мы же с вами хотим продумать всё до мелочей, не так ли?
Вывод будет — 201, а не 2011, как может показаться на первый взгляд.
Заблуждение обычно вызывают две «лишних» запятых в конце.
Когда я первый раз увидел такой код в одном из тестов, я твёрдо решил, что код не скомпилируется — и оказался не прав. Некоторые из вас могут предположить, что не указанные элементы будут заполнены значением по-умолчанию — и это будет тоже неверно.
А вывод будет простой — [[1, 2, 3], [0, 0, 0]]. Получается, что компилятор просто игнорирует одну лишнюю запятую в конце массива. Причём именно одну — две подряд уже вызовут ошибку компиляции.
Описание этой ситуации я без проблем нашёл в спецификации языка — A trailing comma may appear after the last expression in an array initializer and is ignored.
А на практике — сделано для удобства при ручном копировании из одного массива в другой. Если бы компилятор не позволял ставить лишнюю запятую — то в некоторых случаях приходилось бы добавлять запятую в конце, когда мы копируем и вставляем значения из одного массива в конец другого — или удалять лишнюю в конце.
Вы наверно будете уверены в том, что этот код не скомпилируется. А вот и нет! он вполне рабочий.
Когда я изучал Java, я сразу взял на заметку, что из подчёркиваний и экспоненциальной формы для HEX можно сделать что-то дикое. Этот пример, конечно же, не для использования в реальных проектах — а для тренировки ваших знаний. Я думаю, это самый сложный пример и изюминка статьи. Первые два были лёгкой разминкой. Кто-нибудь ответил правильно с первого раза?
В этом примере заключены два интересных момента. Первое — это название переменной. Называть переменную долларом весьма забавно. Но никогда, никогда так не делайте в реальных проектах. Хотя компилятор не запрещает такой подход — он не рекомендован, так как доллар используется в технических целях. Например, для наименования анонимных и вложенных классов. MyClass$MyInnerClass, или же MyClass$1. И можно без труда устроить коллапс имён — один класс назвать просто MyClass$MyInnerClass, а другой — MyClass с вложенным MyInnerClass — и они будут иметь одинаковое имя. Так что включать в свои переменные доллар — не рекомендуется.
Также вполне корректен такой код
А теперь давайте разберём второй момент — непосредственно сам литерал. Я наворотил его, как только мог. Для начала легко заметить, что это число записано в шестнадцатеричной форме. Но ведь она допускает только A,B,C,D,E,F в качестве букв — кажете вы. Откуда тогда P? И причём тут знак подчёркивания?
Обо всём по-порядку. F в конце означает, что этот литерал — типа float. И у нас он автоматически приводится к типу double. Далее очень интересный момент — P2. Если мы хотим записать шестнадцатеричное число в экспоненциальной форме — мы не сможем использовать E+N, потому что E у нас может использоваться в самом числе и может возникнуть неоднозначность. Зато никто не мешает нам использовать BinaryExponentIndicator — указываем p и степень. Число будет умножено на 2 в указанной степени. В данном случае — на 4.
А вот символ подчёркивания — очень удобное нововведение Java 7. Мы просто можем вставлять его в число и разделять им, например, разряды, или группировать цифры. Компилятор его просто вырежет — он нужен для более удобного чтения, не более.
Итак, чтобы точно ответить на вопрос, нам нужно вспомнить, что System.out.print выводит переменную типа double в обычной, десятичной форме. Следственно, нам нужно перевести из шестнадцатеричного вида в десятичный. Это уже совсем тривиальная задача. DE16 = 22210. Далее, умножаем 222 на 2 2 и получаем 888. Наконец не забываем, что для типа double при отсутствии дробной части дописывается точка и ноль. Вот и ответ — 888.0.
Первое, что бросается в глаза — это использование точек с запятой там, где их можно не использовать. Например после объявления класса (как в С++). Или же между членами класса. Зачем компилятор дал возможность ставить их там — я так и не выяснил. Но это вполне допустимо.
Имя метода — вполне допустимый идентификатор. А вот возвращаемый тип здесь не short а массив из short. Компилятор разрешает 2 формы объявления массива — квадратные скобки до идентификатора и после. Причём первый случай предназначен как-раз для метода. А что если попробовать второй случай для метода? Он тоже корректен, но выглядит ужасно, поэтому никогда не используйте его в реальных проектах. Но такая возможность есть.
Далее — внутри метода просто два вложенных блока кода, которые можно безболезненно убрать. И в итоге — метод просто возвращает массив из short длинной в 7 элементов, который инициализируется нулями и элемент с индексом 2 равен 0. Ах да, 007 — это восьмеричный литерал. Но это тоже ни на что не влияет.
Внимательные читатели заметят, что в названии метода присутствует русская буква б. Мало того, что Java позволяет полностью писать название идентификаторов на языках, отличных от английского, так мы ещё можем перемешивать буквы из разных языков.
Важный момент, который я хотел донести до вас — можно случайно напечатать не тот символ из другого языка и потом долго и мучительно искать ошибку. Например, английская a и русская а визуально неотличимы (по крайней мере, в этом шрифте). Если единицу можно отличить от l хоть как-то, то тут всё значительно хуже. Представьте себе ситуацию — вы по каким-либо причинам случайно в конце в названии класса или метода набрали русскую букву вместо английской. Или что более вероятно — редактировали уже существующее латинское название с русской раскладкой. Похожих букв между этими языками довольно много, так что шанс ошибиться вполне есть. Автозаполнение будет вставлять интернациональный идентификатор и всё будет отлично работать. Но вот если вы попробуете вызвать метод или получить класс через рефлексию — получите ошибку, которую будет не так просто обнаружить. Скорее, вы будете искать её в другом, так как названия будут визуально совпадать — потеряете время и силы.
Я хотел добавить ещё один пример, в котором два на внешний вид одинаковых идентификатора будут содержать внешне идентичные буквы из разных алфавитов, но по коду разные и посему идентификаторы будут также разные. И заставить объяснить, почему код вызывает ошибку компиляции. Но это было бы слишком жестоко — на вид подвох никак не заметить.
Далее — мы вызываем статический метод довольно оригинально — приводим null к типу Main. И это не вызовет ошибки времени выполнения! Дело в том, что вызов статических методов разрешается на этапе компиляции и зависит только от типа объекта.
В комментариях к данной статье пользователь Yurevich1 привёл пример из реального проекта:
Итак, вот вам ещё один пример кода, который на первый взгляд вводит в заблуждение. Для начала вас должно смутить казалось бы следующее два раза друг за другом объявление массива из оболочек для байтов. Однако если вы внимательно изучали язык, вы должны знать, что есть два способа объявления массива — с квадратными скобками до имени и после. Более того, никто не мешает нам использовать эти два способа одновременно — перед вами просто двумерный массив.
Далее вас должно смутить имя массива, которое полностью совпадает с именем класса. Java позволяет называть локальные переменные классами стандартной библиотеки, при этом они будут перекрывать классы. Однако компилятор у Джавы умный. Очень умный. Он сообразит, что после оператора new может следовать только класс, да и перед .class — тоже. И в том контексте будет подразумеваться именно класс Byte, хотя имя экземпляра должно его перекрывать.
Итоги
Мне нравится Java за её жёсткую стандартизованность. Спецификация определяет практически все тонкости с очень большой точностью. А значит — изучив эти тонкости один раз — вы сможете работать с ними везде.
Хочу добавить, что скрин кода над катом взят из IDEA. Схему подсветки я сам разработал и использую её преимущества по максимуму. Если кому понравилась — могу скинуть.
Я готовился по нескольким разным системам тестирования. Для начала, хорошим сайтом будет Quizful. Тесты «Java-Основы» и «Java-средний уровень» содержат очень большое количество полезных задач. Далее — очень хороши тесты от ExamLab — гонял по ним SCJP 6. И наконец — для самого экзамена — Enthuware.
После прохождения многочисленных тестов и решения задач «в уме» я стал приятно удивлён, каким комфортным и эффективным стало написание кода. Тесты очень хорошо систематизируют и организуют знания. Я стал предвидеть в уме многие ошибки, а также выбирать лучшие решения. И не пожалел, что выучил некоторую часть API, хотя сначала считал что не следует помнить названия методов и классов наизусть. Я считаю Java одним из лучших языков в мире и рекомендую тесты для его углублённого изучения. А Java SE 7 Programmer I был совсем не сложным — без труда набрал 96 из 100 баллов. Кто собирается сдавать — могу дать пару советов — напишите в личку.
Java задачи для тренировки
Напишите консольную программу, в которой пользователь с клавиатуры вводит два числа. А программа сранивает два введенных числа и выводит на консоль результат сравнения (два числа равны, первое число больше второго или первое число меньше второго).
Напишите консольную программу, в которой пользователь вводит с клавиатуры число. Если число одновременно меньше 9 и больше 2, то программа выводит «Число больше 5 и меньше 10». Иначе программа выводит сообщение «Неизвестное число».
В банке в зависимости от суммы вклада начисляемый процент по вкладу может отличаться. Напишите консольную программу, в которую пользователь вводит сумму вклада. Если сумма вклада меньше 100, то начисляется 5%. Если сумма вклада от 100 до 200, то начисляется 7%. Если сумма вклада больше 200, то начисляется 10%. В конце программа должна выводить сумму вклада с начисленными процентами.
Напишите консольную программу, которая выводит пользователю сообщение «Введите номер операции: 1.Сложение 2.Вычитание 3.Умножение». Рядом с названием каждой операции указан ее номер, например, операция вычитания имеет номер 2. Пусть пользователь вводит в программе номер операции, и в зависимости от этого номера программа выводит название операции.
Для определения операции по введенному номеру используйте конструкцию switch. case.
Если введенное пользователем число не соответствует никакой операции (например, число 120), то выведите пользователю сообщение о том, что операция неопределена.
Пример работы программы:
Измените предыдущую программу. Пусть пользователь кроме номера операции вводит два числа, и в зависимости от номера операции с введенными числами выполняются определенные действия (например, при вводе числа 3 числа умножаются). Результат операции выводиться на консоль.
Практические задачи по Java — для курсов и прочих занятий
Практические задачи по Java — для курсов и прочих занятий
Несколько вводных слов
Последние несколько лет я читаю курс по программированию на Java. Со временем он менялся — то добавлялись, то выкидывались разные части, менялась последовательность тем, менялся подход к построению плана самих занятий, и так далее. То есть, курс совершенствовался. Одной из основных проблем, возникших при подготовке курса — это задачи. О них и пойдёт речь.
Дело в том, что каждое моё занятие состоит из двух частей. На первой я выступаю в роли лектора — рассказываю с примерами кода о какой-то новой теме (классы, наследование, дженерики и так далее). Вторая часть — практическая. Очевидно, что нет смысла просто рассуждать о программировании, надо программировать. Приоритет на занятиях — решение задач, то есть программирование чего-то как-то. Программирование на занятиях отличается от программирования дома, так как на занятиях можно задать вопрос, показать код, получить быструю оценку кода, комментарии по улучшению, исправлению написанного. Очень легко было найти задачи для самых первых занятий. Задачи на циклы, условные операторы, и ООП (к примеру, написать класс «Собака» или класс «Вектор»). Сервисы вроде leetcode позволяют даже проверить правильность решения таких задач сразу, онлайн. Но какие задачи дать студентам на занятии, которое было посвящено коллекциям? Потокам? А аннотациям? За несколько лет я придумал, или переработал несколько таких задач, и эта статья, по сути, является сборником этих задач (к некоторым задачам прилагается решение).
Конечно, все задачи уже где-то появлялись. Однако, эта статья ориентирована на преподавателей курсов по программированию (для языков, похожих на Java, большинство задач подойдёт), или тех, кто преподаёт программирование частным образом. Эти задачи можно использовать «из коробки» на своих занятиях. Изучающие Java тоже могут попробовать решать их. Но такие решения требуют сторонней проверки и оценки.
Некоторые самые простые задачи, которые уже десятилетия все используют, я тоже включил в эту статью. Пожалуй, для того, чтобы не начинать сразу с абстрактных классов.
Любые идеи и пожелания приветствуются!
Список задач
Основы
1.0. Максимальное, минимальное и среднее значение
1.1 Сортировка массива
1.2 Поиск простых чисел
1.3 Удаление из массива
Основы ООП
2.0 Проектирование и создание класса, описывающего вектор
2.1 Генерация случайного элемента с весом
2.2 Связный список
Рекурсия
3.0 Двоичный поиск
3.1 Найти корень уравнения
3.2 Бинарное дерево поиска
Наследование
4.0 Реализовать иерархию классов, описывающую трёхмерные фигуры
4.1 Реализовать иерархию классов, описывающую трёхмерные фигуры — 2
4.2 Реализовать иерархию классов, описывающую трёхмерные фигуры — 3
4.3 Реализовать иерархию классов, описывающую трёхмерные фигуры — 4
Строки
5.0 Частотный словарь букв
Абстрактные классы и интерфейсы
6.0. Конвертер температур
6.1. Stringbuilder с поддержкой операции undo
6.2. Stringbuilder с возможностью отслеживания состояния (паттерн наблюдатель)
6.4. Заполнение массива с помощью Function
Коллекции
7.0. Частотный словарь слов
7.1. Коллекция без дубликатов
7.2. ArrayList и LinkedList
7.3. Написать итератор по массиву
7.4. Написать итератор по двумерному массиву
7.5. Ещё более сложный итератор
7.6. Итератор по двум итераторам
7.7. Подсчёт элементов
7.8. Поменять ключи и значения в Map
Многопоточность
8.0. Состояния
8.1. Синхронизация потоков
8.2. Производитель-потребительt
Аннотации
9.0. Своя аннотация — создание и использование с помощью reflection
Итоговые и прочие задания
10.0. Количество дорожных ограничений
10.1. Поиск по Википедии. В консольной программе
10.2. Итоговое задание — консольная утилита для скачивания файлов по HTTP
10.3. Итоговое задание — погодный Telegram-бот
10.4. Итоговое задание — распознавание рукописных цифр
Основы
1.0. Максимальное, минимальное и среднее значение
Заполните массив случайным числами и выведете максимальное, минимальное и среднее значение.
Для генерации случайного числа используйте метод Math.random(), который возвращает значение в промежутке [0, 1].
1.1. Реализуйте алгоритм сортировки пузырьком для сортировки массива
1.2. Поиск простых чисел
Напишите программу, которая выводит на консоль простые числа в промежутке от [2, 100].
Используйте для решения этой задачи оператор «%» (остаток от деления) и циклы.
Или, используя циклы с метками:
1.3. Удаление из массива
Дан массив целых чисел и ещё одно целое число. Удалите все вхождения этого числа из массива (пропусков быть не должно).
Можно написать метод для «отрезания хвоста» массива и самостоятельно, но стоит отметить, что стандартный метод будет работать быстрее:
Впрочем, если идти таким путём, то можно сначала создать массив нужной длины, а потом уже заполнить его:
2.0. Проектирование и создание класса, описывающего вектор
Создайте класс, который описывает вектор (в трёхмерном пространстве).
У него должны быть:
Использовать этот класс можно так:
Это решение можно обобщить и написать класс Vector для произвольной размерности:
2.1. Генерация случайного элемента с весом
Напишите класс, конструктор которого принимает два массива: массив значений и массив весов значений.
Класс должен содержать метод, который будет возвращать элемент из первого массива случайным образом, с учётом его веса.
Пример:
Дан массив [1, 2, 3], и массив весов [1, 2, 10].
В среднем, значение «1» должно возвращаться в 2 раза реже, чем значение «2» и в десять раз реже, чем значение «3».
Но, так как массив ranges отсортирован, то можно (и нужно) использовать бинарный поиск:
Есть ещё один вариант решения этой задачи. Можно создать массив, размер которого равен сумме всех весов. Тогда выбор случайного элемента сводится к генерации случайного индекса. То есть, если дан массив значений [1, 2, 3], и массив весов [1, 2, 10], то можно сразу создать массив [1, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3] и извлекать из него случайный элемент:
У этого решения есть преимущество — время извлечения случайного элемента O(1), в отличии от log(n) в предыдущем решении. Однако требует много памяти:
2.2. Связный список
Еще одна задача, которую я часто даю — реализация связного списка. Её можно давать в самом простом виде (реализовать только add() и get()), а можно попросить реализовать java.util.List.
Я не буду подробно на этом останавливаться, много статей о реализации связного списка на Java есть на Хабре, к примеру эта:
Структуры данных в картинках. LinkedList
3.0. Двоичный поиск
Напишите метод, который проверяет, входит ли в массив заданный элемент или нет.
Используйте перебор и двоичный поиск для решения этой задачи.
Сравните время выполнения обоих решений для больших массивов (например, 100000000 элементов).
Решение:
3.1. Найти корень уравнения
Найдите корень уравнения
на отрезке [0; 10] с точностью по x не хуже, чем 0.001. Известно, что на этом промежутке корень единственный.
Используйте для этого метод деления отрезка пополам (и рекурсию).
Замечание: если мы хотим добиться нужной точности не по x, по y, то условие в методе следует переписать:
Маленькая хитрость: учитывая, что множество значений double конечно (есть два соседних значения, между которыми нет ни одного значения double), условие выхода из рекурсии переписать так:
Таким образом получим максимальную точность, которую вообще можно получить, используя этот подход.
3.2. Бинарное дерево поиска
Реализация бинарного дерева поиска — отличная задача. Я обычно даю её, когда заходит разговор про рекурсию.
Об этом я тоже много писать не буду, есть много статей/реализаций самого разного вида:
Структуры данных: бинарные деревья.
Бинарное дерево, быстрая реализация
Реализация на Java хешированного бинарного дерева
Наследование
4.0. Реализовать иерархию классов, описывающую трёхмерные фигуры
Реализуйте иерархию классов:
Класс Box является контейнером, он можем содержать в себе другие фигуры. Метод add() принимает на вход Shape. Нужно добавлять новые фигуры до тех пор, пока для них хватаем места в Box (будем считать только объём, игнорируя форму. Допустим, мы переливаем жидкость). Если места для добавления новой фигуры не хватает, то метод должен вернуть false.
Чтобы к этой задаче не возвращаться, далее описывается еще несколько вариаций этой задачи.
4.1. Реализовать иерархию классов, описывающую трёхмерные фигуры — 2
Реализуйте ту же иерархию классов, но сделав некоторые классы абстрактными.
4.2. Реализовать иерархию классов, описывающую трёхмерные фигуры — 3
Реализуйте ту же иерархию классов, но использовав интерфейсы.
Дополнительно, студентам предлагается реализовать интерфейс Comparable.
4.3. Реализовать иерархию классов, описывающую трёхмерные фигуры — 4
Добавьте в иерархию классов фигуру вращения для произвольной функции. Вычислять объём можно приближенное с помощью определённого интеграла. Так как объём фигуры вращения вокруг оси x это
То можно написать реализацию метода прямоугольников:
Конечно, мы не учитываем точность вычислений здесь, и не подбираем количество разбиений для достижения необходимой точности, но это задача на программирование, а не численные методы, так что на занятиях мы это опускаем.
Строки
Можно найти очень много задач на строки. Я обычно даю такие:
Из более интересных мне нравится эта:
5.0. Частотный словарь букв русского (или английского) алфавита.
Постройте частотный словарь букв русского (или английского) алфавита. Опустим проблему выбора и анализа корпуса языка, достаточно будет взять текст небольшой длины).
Абстрактные классы и интерфейсы
6.0. Конвертер температур
Напишите класс BaseConverter для конвертации из градусов по Цельсию в
Кельвины, Фаренгейты, и так далее. У метода должен быть метод convert, который
и делает конвертацию.
Дополнительно можно попросить реализовать фабричный метод, как-то так:
6.1. Stringbuilder с поддержкой операции undo
Напишите свой класс StringBuilder с поддержкой операции undo. Для этого делегируйте все методы стандартному StringBuilder, а в собственном классе храните список всех операций для выполнения undo(). Это будет реализацией шаблона «Команда».
6.2. Stringbuilder с возможностью отслеживания состояния (паттерн наблюдатель)
Напишите свой класс StringBuilder, с возможностью оповещения других объектов об изменении своего состояния. Для этого делегируйте все методы стандартному StringBuilder, а в собственном классе реализуйте шаблон проектирования «Наблюдатель».
6.3. Фильтр
Напишите метод filter, который принимает на вход массив (любого типа) и реализацию интерфейса Filter c методом apply(Object o), чтобы убрать из массива лишнее.
Проверьте как он работает на строках или других объектах.
Решение:
Обычно, я даю эту задачу еще до Generics, поэтому студенты пишут метод без них, используя Object:
Но, можно и с Generics. Тогда можно использовать стандартный Function:
6.4. Заполнение массива
Задача, немного похожая на предыдущую:
Напишите метод fill, который принимает массив объектов, и реализацию интерфейса Function (или своего).
Метод fill должен заполнить массив, получая новое значение по индексу с помощью реализации интерфейса Function. То есть, использовать его хочется так:
Коллекции
7.0. Частотный словарь слов
см. Задачу про частотный словарь букв алфавита
7.1. Коллекция без дубликатов
Напишите метод, который на вход получает коллекцию объектов, а возвращает коллекцию уже без дубликатов.
7.2. ArrayList и LinkedList
Напишите метод, который добавляет 1000000 элементов в ArrayList и LinkedList. Напишите еще один метод, который выбирает из заполненного списка элемент наугад 100000 раз. Замерьте время, которое потрачено на это. Сравните результаты и предположите, почему они именно такие.
7.3. Написать итератор по массиву
7.4. Итератор по двумерному массиву
Напишите итератор по двумерному массиву.
7.5. Ещё более сложный итератор
Мне нравится эта задача. До неё доходит всего несколько студентов в группе, которые сравнительно легко справляются с предыдущими задачи.
Дан итератор. Метод next() возвращает либо String, либо итератор такой же структуры (то есть который опять возвращает или String, или такой же итератор). Напишите поверх этого итератора другой, уже «плоский».
7.6. Итератор по двум итераторам
Напишите итератор, который проходит по двум итератором.
7.7. Подсчёт элементов
7.8. Поменять ключи и значения в Map
Напишите метод, который получает на вход Map и возвращает Map, где ключи и значения поменяны местами. Так как значения могут совпадать, то тип значения в Map будет уже не K, а
Многопоточность
8.0. Состояния
Выведете состояние потока перед его запуском, после запуска и во время выполнения.
Добавим WAITING и BLOCKED:
Для TIMED_WAITING немного изменим тот же код:
8.1. Синхронизация потоков
Напишите программу, в которой создаются два потока, которые выводят на консоль своё имя по очереди.
8.2. Производитель-потребитель
Одна из классических задач по многопоточности. Дано два потока — производитель и потребитель. Производитель генерирует некоторые данные (в примере — числа). Производитель «потребляет» их.
Два потока разделяют общий буфер данных, размер которого ограничен. Если буфер пуст, потребитель должен ждать, пока там появятся данные. Если буфер заполнен полностью, производитель должен ждать, пока потребитель заберёт данные и место освободится.
9.0. Своя аннотация — создание и использование
Эту задачу я обычно даю, когда речь заходит про аннотации и reflection. Заодно, можно рассказать про Executors, ThreadPoolExecutor и другие.
Создайте свою аннотацию Repeat с целочисленным параметром.
Расширьте класс ThreadPoolExecutor и переопределите метод execute следующим образом: если экземпляр Runnable имеет аннотацию Repeat, то его метод run выполняется несколько раз (количество задается параметром в Repeat).
То есть, написав такой класс:
Итоговые и прочие задания
В течение курса я даю студентам несколько сложных задач — на целое занятие. Требуется написать небольшую программу, используя ранее изученное. Кстати, тут часто возникает сложность. Решение задач, сводящихся к написанию одного метода — это одно, а придумать алгоритм, вспомнить всё, что изучали ранее и еще и написать сразу 50 строк на Java — совсем другое. Но на занятии я могу подталкивать их в нужном направлении, помогаю решать проблемы, дебажить, находить нужные классы и методы, и так далее. Несколько таких задач описаны ниже. В таком виде я и даю их своим студентам.
Кроме того, в конце курса все должны выполнить итоговое задание. То есть дома, самостоятельно, написать программу. Еще немного более сложную. Я даю возможность выбрать один из нескольких вариантов. Кстати, интересный факт — необходимо написать минимум одну программу, а можно написать сразу несколько. Кажется, я помню только одного человека, кто написал больше одной.
10.0. Количество дорожных ограничений
Небольшая задача, которая демонстрирует, как можно приложить Java к решению практических задач.
Подготовка данных:
С портала открытых данных Санкт-Петербурга загружаем данные об ограничении движения транспорта на период производства работ в формате csv.
Требуется определить, сколько дорожных ограничений действовало в городе на определенную дату.
Программа в качестве аргумент получает два параметра:
Необходимо вывести количество действовавших ограничений движения транспорта на эту дату.
Решение я тут не привожу, их может быть много разных и каждое надо смотреть индивидуально.
10.1. Поиск по Википедии. В консольной программе
Эту задачу тоже можно разбить на несколько этапов:
Генерация запроса
API предоставляет возможность делать поисковые запросы, без ключей. Вот таким, примерно, образом:
Вы можете открыть эту ссылку в браузере, и посмотреть на результат запроса.
Однако, чтобы запрос прошел удачно, следует убрать из ссылки недопустимые символы, то есть сделать Percent-encoding, он же URL Encoding.
Для этого в Java можно воспользоваться статическим методом encode в классе URLEncoder, вот так:
Вот и всё, URL готов! Осталось теперь сделать запрос к серверу…
Запрос к серверу
Для GET и POST запросов можно воспользоваться классом HttpURLConnection. Это самое простое. Просто создать, открыть соединение и получить InputStream. Нам его даже не надо читать, за нас это сделает Gson.
Ещё можно использовать retrofit, или что-то подобное.
Подготовка к обработке ответа
Сервер возвращает данные в формате JSON.
Но нам его не надо парсить вручную, для этого есть библиотека Gson от Google.
Примеры есть тут:
https://github.com/google/gson
https://habrahabr.ru/company/naumen/blog/228279/
Если остаётся время, можно написать получение статьи, выбранной при поиске и так далее.
10.2. Итоговое задание — консольная утилита для скачивания файлов по HTTP
Консольная утилита для скачивания файлов по HTTP… звучит знакомо? Да, это оно и есть — История одного тестового задания. Всё логично — итоговое задание курса по Java такого же уровня, как и тестовое задание на должность Junior Java разработчика.
И это действительно хорошая задача — несложная, но охватывает самые разные темы. И сразу видно, насколько автор структурирует код, использует разные подходы и паттерны, использует сам язык и стандартную библиотеку.
10.3. Итоговое задание — погодный Telegram-бот
Напишите бота для Telegram, который будет:
Эта задача скорее на умение и способность разобраться в новой технологии (bot-api) и разных библиотеках. А еще настроить VPN надо! И код написать придётся, само собой.
Кстати, интересный факт — большинство студентов игнорируют словосочетание «присланное местоположение» и наличие возможности его отправки. Они пишут бота, который ожидает название города. Я не знаю почему. Это часто работает плохо, код становится немного сложнее, но они продолжают это делать.
10.4. Итоговое задание — распознавание рукописных цифр
Реализовать программу для классификации рукописных цифр.
Эта задача уже больше ориентирована на реализацию алгоритма, умение разбираться в таковых. Обычно код у студентов получается не очень структурированный.
Описание задачи
В качестве исследуемого набора данных будет использоваться база изображений рукописных цифр MNIST. Изображения в данной базе имеют разрешение 28×28 и хранятся в виде набора значений оттенков серого. Вся база разбита на две части: тренировочную, состоящую из 50000 изображений, и тестовую — 10000 изображений.
Для решения этой задачи предлагается реализовать метод k ближайших соседей — метрический алгоритм для автоматической классификации объектов. Основным принципом метода ближайших соседей является то, что объект присваивается тому классу, который является наиболее распространённым среди соседей данного элемента.
Соседи берутся исходя из множества объектов, классы которых уже известны, и, исходя из ключевого для данного метода значения k рассчитывается, какой класс наиболее многочислен среди них. В качестве расстояния между объектами можно использовать Евклидову метрику, то есть привычное нам расстояние между точками в пространстве.
Необходимо написать программу, которая будет распознавать рукописные цифры. Должна быть возможность инициализировать некий класс данными для обучения и предоставить метод для распознавания одного изображения.
Кроме самой реализации алгоритма, следует написать код для проверки его точности (посчитать error rate). Для этого следует использовать 10000 тестовых изображений.
Кроме вычисления точности предлагается провести эксперимент: вместо евклидовой метрики использовать расстояние городских кварталов, угол между векторами или что-то еще, и проверить качество распознавания.
Если всё хорошо работает, то можно ещё немного усложнить задание. Добавив, к примеру, отсев шума (выбросов) или использование метода Парзеновского окна для повышения точности.