Перейти к содержимому

Понемногу — но каждый день.

Java OCA 8 глазами frontend-разработчика

10 мин чтения

На этой странице
Коротко
Я frontend-разработчик на Angular и TypeScript и готовлюсь к сертификации Oracle Java SE 8 Programmer I (1Z0-808) по книге Boyarsky и Selikoff. Цель — собеседование на junior/стажёра Java (Spring) backend. В посте — прогресс в цифрах, что в каждой из шести глав, где привычки из TypeScript ведут к неправильному ответу, и по одной-две задачи LeetCode к каждой главе, чтобы закрепить её кодом. Синтаксис у Java и TypeScript похож, поэтому самые коварные места — те, где код выглядит знакомо, а работает иначе.

Почему Java и почему этот экзамен

Цель — уметь писать backend на Java/Spring, а не только frontend. Сертификат сам по себе работу не даёт. Но подготовка к нему заставляет выучить основу языка до мелочей, а не «на уровне Stack Overflow». Экзамен проверяет именно мелочи: скомпилируется ли этот код, что он напечатает, какое исключение бросит.

Книга — официальный Study Guide под этот экзамен: 6 глав, к каждой — список целей экзамена, итог и вопросы для самопроверки. В начале — входной тест, в конце — ответы с разбором и советы по подготовке.

План в цифрах

Страницы каждой главы считаются по оглавлению: начало следующей главы минус начало текущей.

ГлаваТемаСтраницыДней при 10 стр/день
1Java Building Blocks1–50 → 505
2Operators and Statements51–100 → 505
3Core Java APIs101–164 → 647
4Methods and Encapsulation165–232 → 687
5Class Design233–298 → 667
6Exceptions299–332 → 344
Итого33235

Почему 35, а не 332 / 10 = 33,2? Потому что дни считаются по главам с округлением вверх: 64 страницы — это 7 дней, а не 6,4: неполный день всё равно занимает день. Сумма округлений: 5 + 5 + 7 + 7 + 7 + 4 = 35. Это округление вверх (ceil) — то же самое, что в программировании Math.ceil(64 / 10).

Где я сейчас

Прочитано 271 страница из 332 — середина главы 5, раздел про интерфейсы.

  • Прочитано: 271 / 332 = 0,816 → 82%.
  • Осталось: 332 − 271 = 61 страница.
  • При 10 страницах в день: ⌈61 / 10⌉ = ⌈6,1⌉ = 7 дней → главы закончатся к 16 ноября.

Скобки ⌈ ⌉ — это то же округление вверх: 6,1 дня — это всё равно семь календарных дней.

Дальше — не «прочитал и забыл», а повтор глав 1–4 через задачи LeetCode (план ниже) и пробные тесты. Цель — к декабрю, когда начнутся отклики на вакансии.

Правило самопроверки: после каждой главы — Review Questions без подсказок, результат в процентах. Ниже 65% (проходной балл экзамена) — глава перечитывается, а не «потом разберусь».

Глава 1. Java Building Blocks

О чём: структура класса, main(), пакеты и импорты, конструкторы и порядок инициализации, примитивы и ссылочные типы, область видимости переменных, сборщик мусора.

Где мешает TypeScript:

  • Примитивов восемь, и у них фиксированный размер. В TypeScript одно number на всё. В Java — byte (8 бит), short (16), int (32), long (64), float, double, плюс char и boolean. От размера зависит, влезет ли значение: byte хранит от −128 до 127, потому что 8 бит дают 2⁸ = 256 значений, и половина отдана отрицательным.
  • Локальную переменную без значения нельзя прочитать. В TypeScript это undefined. В Java — ошибка компиляции. А вот поля класса получают значение по умолчанию: 0, false, null.
  • Импорт со звёздочкой не заходит в подпапки. import java.util.*; не импортирует классы из java.util.concurrent.

Ловушка экзамена: порядок инициализации объекта. Сначала поля и блоки инициализации — сверху вниз, в том порядке, как они написаны, — и только потом тело конструктора.

public class Order {
    private String name = "поле";
    { System.out.println(name); }          // блок инициализации
    public Order() { name = "конструктор"; System.out.println(name); }
    public static void main(String[] args) { new Order(); }
}
// напечатает: поле, затем конструктор

Мой результат Review Questions: TODO

Глава 2. Operators and Statements

О чём: операторы и их приоритет, приведение типов при вычислениях, if, switch, циклы, break и continue с метками.

Где мешает TypeScript:

  • Числа «повышаются» при вычислении. Результат арифметики над byte и short — всегда int. Поэтому byte a = 1, b = 2; byte c = a + b; не скомпилируется: справа int, а его нельзя молча положить в byte.
  • Целочисленное деление. 7 / 2 в Java — 3, а не 3.5, если оба числа целые. В JavaScript — 3.5.
  • if принимает только boolean. Никакой «истинности»: if (count) с числом не скомпилируется. Привычка из JS писать if (value) здесь — ошибка.
  • switch в Java 8 работает с int и меньшими типами, char, String и enum, но не с long и boolean.

Ловушка экзамена: x++ и ++x в одном выражении. Постфикс возвращает старое значение, префикс — новое:

int x = 3;
int y = x++ + ++x;   // 3 + 5 = 8, а x в итоге 5

Мой результат Review Questions: TODO

Глава 3. Core Java APIs

О чём: String и пул строк, StringBuilder, сравнение == и equals(), массивы, ArrayList, обёртки и автоупаковка, дата и время из java.time.

Где мешает TypeScript:

  • == у объектов сравнивает ссылки, а не содержимое. Две разные строки с одинаковым текстом могут быть не равны по ==. Содержимое сравнивает equals(). В JS === у строк сравнивает значения, поэтому рука пишет == — и ответ неверный.
  • Строки неизменяемы, как и в JS: s.toUpperCase() возвращает новую строку и не меняет s. Если результат не присвоить — он пропал. Экзамен любит такой код.
  • Массив фиксированной длины. push у массива нет; для растущего списка — ArrayList.
  • substring(begin, end) не включает end — как slice в JS. Зато у StringBuilder методы append, insert, delete меняют сам объект, а substring — нет.
  • Даты неизменяемы. date.plusDays(1) возвращает новую дату. Вызов без присваивания ничего не делает.

Ловушка экзамена: у ArrayList<Integer> два метода remove: по индексу (int) и по объекту (Integer):

List<Integer> list = new ArrayList<>(Arrays.asList(10, 20, 30));
list.remove(1);                    // удалит элемент с индексом 1 → [10, 30]
list.remove(Integer.valueOf(10));  // удалит значение 10 → [30]

Мой результат Review Questions: TODO

Глава 4. Methods and Encapsulation

О чём: объявление методов, модификаторы доступа, static, передача параметров, перегрузка, конструкторы, инкапсуляция, неизменяемые классы, простые лямбды и Predicate.

Где мешает TypeScript:

  • Четыре уровня доступа, а не три. private, без модификатора («package-private» — виден внутри пакета), protected (пакет + наследники), public. В TypeScript уровня «внутри пакета» нет.
  • Java всегда передаёт по значению. Для объектов по значению передаётся ссылка. Присвоить параметру новый объект — вызывающий этого не увидит. Вызвать метод у объекта — увидит. Это то же, что в JS, но экзамен проверяет это на каждом шагу.
  • Перегрузка методов. В TypeScript перегрузки — это только типы, тело у функции одно. В Java несколько методов с одним именем — реально разные методы, и компилятор выбирает нужный.

Ловушка экзамена: порядок выбора перегрузки. Сначала точное совпадение типа, потом расширение примитива (int → long), потом автоупаковка (int → Integer), и только потом varargs:

static void print(long x)    { System.out.println("long"); }
static void print(Integer x) { System.out.println("Integer"); }
public static void main(String[] args) { print(5); }   // long: расширение раньше упаковки

Мой результат Review Questions: TODO

Глава 5. Class Design

О чём: наследование, вызов конструкторов родителя, переопределение и скрытие методов, абстрактные классы, интерфейсы с default- и static-методами, полиморфизм и приведение типов.

Где мешает TypeScript:

  • Типизация номинальная, а не структурная. В TypeScript объект подходит под интерфейс, если у него есть нужные поля. В Java класс подходит, только если он явно написал implements.
  • Первая строка конструктора — всегда this(...) или super(...). Если не написал — компилятор вставит super(). И если у родителя нет конструктора без параметров, код не скомпилируется.
  • Переопределение и скрытие. Обычный метод переопределяется: вызывается версия реального объекта. static-метод скрывается: вызывается версия по типу переменной. Поля тоже скрываются, а не переопределяются.

Ловушка экзамена: правила переопределения. Метод в наследнике должен иметь ту же сигнатуру, быть не менее доступным, не объявлять новых или более широких проверяемых исключений, а возвращаемый тип — тот же или его подтип.

Мой результат Review Questions: TODO

Глава 6. Exceptions

О чём: зачем нужны исключения, проверяемые и непроверяемые, try/catch/finally, типичные исключения, throw и throws.

Где мешает TypeScript:

  • Проверяемые исключения. В TypeScript любая функция может бросить что угодно, и компилятор молчит. В Java проверяемое исключение (наследник Exception, но не RuntimeException) нужно либо поймать, либо объявить в throws. Иначе код не скомпилируется.
  • Порядок catch важен. Блок для родительского исключения выше блока для дочернего — ошибка компиляции: второй блок недостижим.
  • finally выполняется почти всегда, даже если в try есть return.

Ловушка экзамена: throw и throws. throw new X() бросает исключение внутри метода; throws X в объявлении метода предупреждает, что оно может вылететь.

Мой результат Review Questions: TODO

LeetCode к каждой главе

Книга учит язык, а на собеседовании junior/стажёра почти всегда дают задачу «напиши код». Поэтому к каждой главе — одна-две задачи, где тема главы реально нужна. Не ради количества: каждую задачу оформляю в leetcode/ по шаблону и ставлю confidence и дату повтора.

Легенда: ✅ решена, ⬜ в плане. Задачи выбраны так, чтобы ловушка главы встретилась в коде, а не только в тесте.

ГлаваЗадачаСложностьЧто закрепляет
1. Building Blocks⬜ 7. Reverse Integermediumint 32 бита: переполнение, проверка через Integer.MAX_VALUE до умножения
1. Building Blocks⬜ 9. Palindrome Numbereasyцелочисленное деление / 10 и остаток % 10 вместо перевода в строку
2. Operators⬜ 136. Single NumbereasyXOR (^): a ^ a = 0, a ^ 0 = a — решение за O(1) памяти
2. Operators⬜ 191. Number of 1 Bitseasyсдвиги: разница >> и >>> для отрицательных чисел (в JS есть такая же пара)
3. Core APIs✅ 151. Reverse Words in a StringmediumString неизменяема, split, StringBuilder
3. Core APIs⬜ 242. Valid Anagrameasyмассив int[26] и арифметика char: c - 'a' — это число
3. Core APIs⬜ 1. Two SumeasyHashMap: одна из самых частых задач на собеседованиях
4. Methods✅ 206. Reverse Linked Listeasyссылки передаются по значению: что меняется у вызывающего, а что нет
4. Methods✅ 21. Merge Two Sorted Listseasyто же: работа со ссылками в цикле; для повтора — переписать рекурсией
4. Methods⬜ 49. Group Anagramsmediumлямбда в computeIfAbsent(key, k -> new ArrayList<>())
5. Class Design✅ 20. Valid ParentheseseasyDeque (интерфейс) вместо Stack (класс); автоупаковка Character
5. Class Design⬜ 155. Min Stackmediumсвой класс: private-поля, инкапсуляция, только нужные публичные методы
5. Class Design⬜ 232. Implement Queue using Stackseasyреализовать заданный API поверх другой структуры
6. Exceptions⬜ 8. String to Integer (atoi)mediumчто делает Integer.parseInt и когда бросает NumberFormatException; разбор краевых случаев руками

Итого: 4 решено, 10 в плане.

Хитрые места, которые стоит проверить в задачах

  • Integer и ==. Сравнение двух Integer через == работает для чисел от −128 до 127 (они кэшируются) и ломается для больших. В задаче 20 у меня equals — правильно. Это частый вопрос на собеседовании.
  • char — это число. 'b' - 'a' == 1, поэтому int[26] вместо HashMap для букв.
  • Переполнение молчит. Integer.MAX_VALUE + 1 даёт отрицательное число без ошибки. В задачах 7 и 8 это и есть суть.

Темп

10 задач за 4 недели: 2–3 задачи в неделю после чтения, в выходные — повтор задач, у которых подошла дата next_review.

НеделяЗадачи
10–16 ноябрядочитать главы 5–6; 155, 232
17–23 ноября7, 9, 136
24–30 ноября191, 242, 1
1–7 декабря49, 8 + повтор 20, 21, 151, 206

После книги: что ещё нужно для Spring backend

Книга OCA про Java Core. На собеседовании backend-разработчика спросят ещё:

  • SQL — на LeetCode есть подборка SQL 50; начать с 175 (Combine Two Tables) и 176 (Second Highest Salary): JOIN, LIMIT/OFFSET, NULL.
  • Коллекции глубже: HashMap изнутри, equals/hashCode.
  • Spring Boot: пет-проект с REST API и базой — он важнее числа решённых задач.

Как я учусь

  • 10 страниц в день, прогресс — в карточке книги; задачи — в leetcode/.
  • Каждый пример из книги набираю руками и запускаю (javac + java), а не читаю глазами. Экзамен проверяет, что делает код, а это видно только по запуску.
  • Перед запуском записываю свой ответ: «скомпилируется? что напечатает?». Потом сверяю. Ошибся — пишу, почему.
  • Review Questions — без подсказок, результат в таблицу.

Что дальше

После книги — пробные тесты и запись на экзамен. Потом — Spring Boot и пет-проект: сертификат проверяет язык, а работу дают за то, что умеешь им сделать.