— Привет, Амиго. Продолжаем говорить об ошибках. На этот раз те, с которыми компилятор тебе поможет далеко не всегда. Слушай и узнавай себя.
— Готов внимать, Диего. Надеюсь, мне будет не очень стыдно.
Сравнение объектов с помощью ==
— Наш топчик любимых ошибок программистов-новичков открывает “сравнение объектов (особенно строк) с помощью оператора ==
”
Пример:
Scanner console = new Scanner(System.in);
String s1 = console.nextLine();
String s2 = console.nextLine();
if (s1 == s2)
{
System.out.println("Строки равны");
}
— Я действительно частенько так делал. Сейчас чётко вижу, что такой код никогда не выведет надпись «строки равны», поскольку в if
-е происходит сравнение ссылок на два разных объекта строк.
— Да. Поэтому правильный вариант будет таким:
Scanner console = new Scanner(System.in);
String s1 = console.nextLine();
String s2 = console.nextLine();
if (s1.equals(s2))
{
System.out.println("Строки равны");
}
Изменение объекта String
— Часто программисты-новички забывают, что все объекты класса являются неизменяемыми (immutable), и все методы класса String
возвращают новый объект, а текущий объект никогда не меняется.
— Я не так давно выучил про immutable, но, кажись, было дело.
— Я почти уверен, что было. Пример:
String s = "Привет";
s.toUpperCase(); //преобразование строки к верхнему регистру
— Такой код очень похож на правильный, но работать не будет. Метод toUpperCase()
не меняет объект, у которого был вызван. Правильный код будет выглядеть так:
String s = "Привет";
String result = s.toUpperCase(); //преобразование строки к верхнему регистру
— Точно. Я так делал, но даже толком не понимал, что не так. Спасибо за пояснение!
Забыли проинициализировать объекты, являющиеся элементами массива
— Еще одна частая ошибка — забыли инициализировать переменную-массив. Пример:
int[] array;
array[0] = 1;
array[0] = 2;
— Такой код работать не будет: в переменную array нужно явно присвоить ссылку на объект-контейнер, который будет хранить элементы массива. Правильный вариант:
int[] array = new int[10];
array[0] = 1;
array[0] = 2;
Подмена поля класса локальной переменной.
—Новички не любят придумывать длинные и осмысленные названия переменным.
— Так и есть. Я иногда для скорости называю переменные a
, b
, i
и так далее.
— Не делай так. Это может сыграть злую шутку, когда таких переменных в коде несколько:
Занести в 100 ячеек массива число 99 |
---|
|
— Гораздо сложнее ошибиться в коде с нормальными названиями. Исправленный вариант будет выглядеть так:
Занести в 100 ячеек массива число 99 |
---|
|
Удаление элемента коллекции
— Ты уже заглядывал в коллекции?
— Буквально одним глазком.
— Если не знаешь, о чём речь, отметь себе на будущее. Очень часто бывают ситуации, когда из коллекции нужно удалить определенный элемент. Выглядит этот код примерно так:
ArrayList<Integer> list = new ArrayList<Integer>();
Collections.addAll(list, 0, -5, -7, -12, 5, 15);
for (Integer value: list)
if (value < 0)
list.remove(value);
— Такой код работать не будет, поскольку нельзя одновременно обходить элементы коллекции с помощью цикла for-each
и изменять ту же самую коллекцию.
— Есть несколько решений. Во-первых, можно идти по одной коллекции, а менять другую:
Решение 1 |
---|
|
— Во-вторых, у коллекции, начиная с Java 8, появился метод removeIf()
, в который можно передать правило (лямбда-функцию), указывающее, какие элементы нужно удалить. Пример:
Решение 2 |
---|
|
Помещение в один файл сразу нескольких классов с модификатором public
— В одном файле может быть только один публичный класс. В файле могут быть объявлены еще классы, но они должны быть или внутренними классами публичного класса, или же не иметь модификатора public
. Пример:
Содержимое файла Solution.java | Примечание |
---|---|
|
Так нельзя: два публичных класса в одном файле. |
|
А так можно. Класс Main — не публичный |
|
И так можно. Класс Main — вложенный класс |
Вызов обычных методов класса из метода статического main()
— Иногда программисты-новички обращаются к нестатическим переменным и методам из метода main()
или других статических методов. Такой код, конечно, не будет работать.
public class Solution
{
public int n = 100;
public int[] createArray()
{
return new int[n];
}
public static void main(String[]args)
{
int[] array = createArray();
}
}
— Метод main
может обратиться только к статическому методу/переменной. Ну или сначала создать объект класса Solution
, и только потом вызвать нестатические методы у этого объекта. Пример:
Решение 1 | Решение 2 |
---|---|
|
|
Объявление конструктора как метода
— Ещё одна частая ошибка — неверное объявление конструктора класса. Имя конструктора должно совпадать с именем класса, и типа-результата у конструктора нет. Самые частые ошибки выглядят так:
|
Тип результата тут не нужен |
|
Неверное имя конструктора, должно совпадать с именем класса |
|
Пропущен this — переменная value будет присвоена сама себе |
|
Все правильно. |
Неверное наследование интерфейсов
— Разработчики Java старались сделать его очень близким к английскому языку, поэтому для некоторых родственных понятий они выбрали разные ключевые слова.
Когда класс наследуется от класса, нужно использовать ключевое слово extends
:
class Pet
{
}
class Cat extends Pet
{
}
— Когда класс наследуется от интерфейса, а, точнее — реализует его, нужно использовать ключевое слово implements
:
interface Meow
{
}
class Cat implements Meow
{
}
— Когда интерфейс наследуется от интерфейса, нужно использовать ключевое слово extends
:
interface Meow
{
}
interface Voice extends Meov
{
}
Пропуск слова break
в операторе switch
— И последняя на сегодня, но далеко не последняя для новичков ошибка, — это пропуск оператора break
в операторе множественного выбора switch
. Пример:
Неправильно | Правильно |
---|---|
|
|
— Да, Диего… Судя по коллекции ошибок, такое ощущение, что ты прямо читал мой дневник… Или следил за тем, как я решаю задачки.
— Ха! Даже не сомневайся. И читал, и следил, и продолжаю. Так что будь на чеку!
— ???
— Не дрейфь, шучу. Будь на чеку и делай поменьше глупых ошибок.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ