Java OCA 8 глазами frontend-разработчика
На этой странице
Почему Java и почему этот экзамен
Цель — уметь писать backend на Java/Spring, а не только frontend. Сертификат сам по себе работу не даёт. Но подготовка к нему заставляет выучить основу языка до мелочей, а не «на уровне Stack Overflow». Экзамен проверяет именно мелочи: скомпилируется ли этот код, что он напечатает, какое исключение бросит.
Книга — официальный Study Guide под этот экзамен: 6 глав, к каждой — список целей экзамена, итог и вопросы для самопроверки. В начале — входной тест, в конце — ответы с разбором и советы по подготовке.
План в цифрах
Страницы каждой главы считаются по оглавлению: начало следующей главы минус начало текущей.
| Глава | Тема | Страницы | Дней при 10 стр/день |
|---|---|---|---|
| 1 | Java Building Blocks | 1–50 → 50 | 5 |
| 2 | Operators and Statements | 51–100 → 50 | 5 |
| 3 | Core Java APIs | 101–164 → 64 | 7 |
| 4 | Methods and Encapsulation | 165–232 → 68 | 7 |
| 5 | Class Design | 233–298 → 66 | 7 |
| 6 | Exceptions | 299–332 → 34 | 4 |
| Итого | 332 | 35 |
Почему 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 Integer | medium | int 32 бита: переполнение, проверка через Integer.MAX_VALUE до умножения |
| 1. Building Blocks | ⬜ 9. Palindrome Number | easy | целочисленное деление / 10 и остаток % 10 вместо перевода в строку |
| 2. Operators | ⬜ 136. Single Number | easy | XOR (^): a ^ a = 0, a ^ 0 = a — решение за O(1) памяти |
| 2. Operators | ⬜ 191. Number of 1 Bits | easy | сдвиги: разница >> и >>> для отрицательных чисел (в JS есть такая же пара) |
| 3. Core APIs | ✅ 151. Reverse Words in a String | medium | String неизменяема, split, StringBuilder |
| 3. Core APIs | ⬜ 242. Valid Anagram | easy | массив int[26] и арифметика char: c - 'a' — это число |
| 3. Core APIs | ⬜ 1. Two Sum | easy | HashMap: одна из самых частых задач на собеседованиях |
| 4. Methods | ✅ 206. Reverse Linked List | easy | ссылки передаются по значению: что меняется у вызывающего, а что нет |
| 4. Methods | ✅ 21. Merge Two Sorted Lists | easy | то же: работа со ссылками в цикле; для повтора — переписать рекурсией |
| 4. Methods | ⬜ 49. Group Anagrams | medium | лямбда в computeIfAbsent(key, k -> new ArrayList<>()) |
| 5. Class Design | ✅ 20. Valid Parentheses | easy | Deque (интерфейс) вместо Stack (класс); автоупаковка Character |
| 5. Class Design | ⬜ 155. Min Stack | medium | свой класс: private-поля, инкапсуляция, только нужные публичные методы |
| 5. Class Design | ⬜ 232. Implement Queue using Stacks | easy | реализовать заданный 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 и пет-проект: сертификат проверяет язык, а работу дают за то, что умеешь им сделать.