Какие тонкости и нюансы Java часто упускают из виду?

«Какие тонкости и нюансы Java часто упускают из виду?» — вопрос из категории Софт-скиллы, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый пример ответа, который можно адаптировать под свой опыт.

Ответ

1. String Pool и Immutability строк Строковые литералы кэшируются в пуле строк (String Pool) для экономии памяти. Оператор new создает новый объект в куче.

String a = "hello"; // Может быть взята из пула
String b = "hello"; // Ссылается на тот же объект из пула, что и 'a'
String c = new String("hello"); // Создается новый объект String
System.out.println(a == b); // true (одинаковые ссылки)
System.out.println(a == c); // false (разные объекты)
System.out.println(a.equals(c)); // true (одинаковое содержимое)

2. Кэширование значений в классах-обертках (Integer Cache) JVM кэширует объекты Integer для значений от -128 до 127.

Integer i1 = 127;
Integer i2 = 127;
System.out.println(i1 == i2); // true (объект из кэша)

Integer i3 = 128;
Integer i4 = 128;
System.out.println(i3 == i4); // false (созданы новые объекты)
// Сравнивайте значения через .equals()

3. Переопределение (Override) vs Перегрузка (Overload)

  • @Override: Аннотация для метода, который переопределяет метод суперкласса/интерфейса. Проверяет совместимость сигнатур во время компиляции.
  • Перегрузка: Создание метода с тем же именем, но другими параметрами в том же классе.

4. Try-with-Resources (AutoCloseable) Конструкция автоматически закрывает ресурсы, реализующие AutoCloseable, даже при возникновении исключения.

try (FileInputStream fis = new FileInputStream("file.txt");
     BufferedReader br = new BufferedReader(new InputStreamReader(fis))) {
    System.out.println(br.readLine());
} // fis.close() и br.close() вызываются автоматически здесь

5. Ленивая инициализация статических полей (Initialization-on-demand holder idiom) Класс-холдер загружается только при первом обращении к его статическому полю.

public class Singleton {
    private Singleton() {}

    private static class Holder {
        static final Singleton INSTANCE = new Singleton(); // Инициализация здесь
    }

    public static Singleton getInstance() {
        return Holder.INSTANCE; // Загрузка класса Holder и создание INSTANCE
    }
}