JavaRush /Java блог /Java Developer /8 частых ошибок начинающих программистов
Автор
John Selawsky
Senior Java-разработчик и преподаватель в LearningTree

8 частых ошибок начинающих программистов

Статья из группы Java Developer
Привет! Сегодня мы рассмотрим список из 8 распространенных ошибок начинающих (да и не только) Java-разработчиков. В Сети ты найдешь немало таких подборок: многие из них похожи друг на друга. Когда мы составляли этот список, ориентировались на один критерий: допускали ли эти ошибки сами во время учебы и работы :) Они расставлены не по приоритету и одинаково важны для понимания и запоминания.
  1. Сравнение объектов с помощью ==.

    Оператор == сравнивает ссылки объектов.

    Ссылки указывают на адреса в памяти, и если они находятся по разным адресам, сравнение через == будет возвращать false.

    
    public class Car {
    
       String model;
       int maxSpeed;
       int yearOfManufacture;
    
       public Car(String model, int maxSpeed, int yearOfManufacture) {
           this.model = model;
           this.maxSpeed = maxSpeed;
           this.yearOfManufacture = yearOfManufacture;
       }
    
       public static void main(String[] args) {
           Car ferrari = new Car("Ferrari 360 Spider", 280, 1996);
           Car ferrariTwin = new Car("Ferrari 360 Spider", 280, 1996);
           System.out.println(ferrari == ferrariTwin);
       }
    }
    

    Для сравнения объектов в классе Object есть специальный метод — equals(). Его реализация по умолчанию, прямо скажем, так себе:

    
    public boolean equals(Object obj) {
       return (this == obj);
    }
    

    В самом классе Object логика метода equals() реализована как сравнение двух ссылок. В свою очередь, для корректного сравнения объектов тебе необходимо переопределить этот метод в соответствии с теми критериями, которые важны в конкретной программе для конкретных объектов. Критерии равенства определяешь ты сам.

    Единственное, о чем не стоит забывать, — список требований для правильного переопределения equals(). Ты их легко найдешь в Интернете, но наши крутые ученики уже сделали статью на эту тему.

  2. Использование нестатических переменных в статических методах (и наоборот).

    Если ты хоть раз видел надпись «Non-static variable x cannot be referenced from a static context» — добро пожаловать в клуб :)

    Статические методы не имеют доступа к нестатическим переменным класса.

    Это логично: ведь статический метод можно вызвать, не создавая объект класса, а все переменные-поля принадлежат конкретным объектам. В этом и заключается противоречие, приводящее к ошибке.

    Наоборот, кстати, можно: использовать статические переменные в нестатических методах допустимо:

    
    public class Main {
    
       public int x = 10;
    
       public static int staticX = 100;
    
       public static void main(String[] args) {
    
           System.out.println(x);//ошибка компиляции, так нельзя!
       }
    
       public void printX() {
    
           System.out.println(staticX);//а так можно!
       }
    }
    
  3. Непонимание того, как передаются параметры в методы: по ссылке или по значению.

    Объекты и примитивы передаются в методы в качестве параметров по-разному: первые — по ссылке, вторые — по значению.

    Новичкам часто бывает сложно понять эту концепцию, в результате их код ведет себя неожиданно:

    
    public class Main {
    
       public static void main(String[] args) {
    
           int x = 7;
           incrementNumber(x);
           System.out.println(x);
    
           Cat cat = new Cat(7);
           catLevelUp(cat);
           System.out.println(cat.getAge());
    
       }
    
       public static void catLevelUp(Cat cat) {
    
           cat.setAge(cat.getAge()+1);
       }
    
       public static void incrementNumber(int x) {
           x++;
       }
    }
    

    Если в этом примере ты точно не знаешь, какое число увеличится, а какое нет (обычное число или возраст кота), тогда перечитай еще раз нашу лекцию на эту тему.

  4. Игнорирование правил написания кода.

    И это касается не только соблюдения тех или иных «технических» принципов, но и банальных соглашений об именовании.

    Все эти правила «как надо называть переменные», «как надо писать названия методов» были придуманы не просто так. Это и правда сильно влияет на читаемость кода.

    Ведь код не всегда будет только твоим. Ты можешь перевестись на другой проект в компании, и он перейдет по наследству к твоим коллегам, которые будут явно не в восторге, получив в работу что-то вроде этого:

    
    public class Cat {
    
       private int S_O_M_E_T_H_I_N_G = 7;
       public String striiiiiiiiiiiiiing;
       protected double X3_4TO_ET0_TAK0E = 3.14;
       boolean random = Math.random() > 0.5;
    
    }
    

    Твой код может быть гениальным с точки зрения производительности, но если его невозможно прочитать и понять как он, собственно, работает, цена его, увы, невелика.

    Придерживайся стандартов написания, и твой код, даже далекий от идеала, хотя бы прочтут более опытные товарищи и подскажут, что с технической точки зрения в нем можно улучшить :)

  5. Непонимание работы класса String

    
    public class Main {
    
       public static void main(String[] args) {
    
           String s1 = "Я изучаю Java";
           String s2 = new String("Я изучаю Java");
    
           System.out.println(s1 == s2);
       }
    }
    

    Если ты не знаешь, почему этот код выводит false, знания явно нужно подтянуть:)

    Новички часто не знают что такое String Pool и как он работает.

    Как следствие, не до конца ясно, как правильно сравнивать строки в своем коде. В одной из наших лекций мы подробно рассматривали эту тему

  6. Неправильная работа с исключениями.

    Это свойственно не только новичкам, но и опытным разработчикам. Причин несколько.

    Во-первых, универсального рецепта не существует. Ошибки в программе бывают разные, сценарии их обработки, соответственно, тоже. Во-вторых, не все понимают структуру stackTrace, а антипаттернов обработки ошибок очень много, и каждый из них «неправилен» по-своему. Так что вариантов сделать неправильно здесь намного больше, чем где бы то ни было.

    Распространенные антипаттерны приведены здесь:

  7. Неполное понимание работы операторов (арифметических, логических и других).

    8 частых ошибок начинающих программистов - 2

    Простой пример. Сможешь сходу сказать, что выведет этот код?

    
    public class Main {
    
       public static void main(String[] args) {
    
           int i = 6;
           System.out.println(7 == i++);
       }
    }
    

    Если ты ответил неправильно или наугад, значит, в этой области пока есть пробелы:)

    Код выведет false, потому что приоритет у оператора сравнения == выше, чем у постфиксного инкремента ++. Поэтому сначала будет выполнено сравнение 7 == i, и только потом - операция i++.

    По этой теме, кстати, у нас тоже была подробная лекция. Вот ссылка, если пропустил.

  8. Пропуск слова break в операторе switch.

    Эту ошибку, вероятно, допускали многие из читателей!)

    
    public class Main {
    
       public static void main(String[] args) {
    
           int i = 1;
    
           switch (i) {
    
               case 1: {
                   System.out.println("Число равно 1");
               }
               case 2: {
                   System.out.println("Число равно 2");
               }
               case 3: {
                   System.out.println("Число равно 3");
               }
           }
       }
    }
    

    В результате на них обрушивается водопад из всех возможных вариантов:

    Вывод:

    
    Число равно 1
    Число равно 2
    Число равно 3
    

    Оператор break прерывает работу оператора switch в момент, когда отработал один из вариантов. Не стоит о нем забывать, иначе результат может быть неожиданным :)

Комментарии (167)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Anton Zinovyev Уровень 22
23 февраля 2024
"В языке Java всегда используется только вызов по значению. Это означает, что метод получает копии значений всех своих параметров. По этой причине метод не может видоизменить содержимое ни одной из переменных, передаваемых ему в ка честве параметров." в Java Библиотека профессионала, том 1 Основы 11-издание подробно расписано с примерами почему. Автор сам не понимает о чем пишет
Ольга Уровень 15
14 февраля 2024
Подскажите пожалуйста, а как сделать так, чтоб метод incrementNumber увеличивал число на единицу к коде примера?
Петр Уровень 24
15 декабря 2023
В п.7 неправильно объяснение, боже. Автор сам не понимает тему. Он пишет: "Код выведет false, потому что приоритет у оператора сравнения == выше, чем у постфиксного инкремента ++. Поэтому сначала будет выполнено сравнение 7 == i, и только потом - операция i++." Код выведет false не потому что приоритет у сравнения выше. Он как раз ниже, чем у инкремента. Код выведет false, потому что постфиксный инкремент сначала возвращает значение, а потом увеличивает переменную. Вот для наглядности:

public class Main {

   public static void main(String[] args) {

        int i = 6;
        System.out.println(7 == i++); //false
        int j = 6;
        System.out.println(7 == ++j); //true
   }
}
Дмитрий Веремеенко Уровень 16 Expert
27 сентября 2023
Повторение - мать заикания. Полезная статья. Время от времени стоит напоминать это материал не только по ходу курса.
Denis Gritsay Уровень 35
12 сентября 2023
хорошая лекция
Anatoly Уровень 30
8 сентября 2023
хороший материал
dim11981 Уровень 47
22 августа 2023
п. 7 здесь: Operators
slavich Уровень 16 Expert
24 июля 2023
в 3 пример нужно добавить в конце класс Cat с private int age, геттером, сеттером и конструктором. тогда код скомпилируется без ошибок.

class Cat {
    private int age;

    public Cat(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
Ulukay Уровень 19
20 июля 2023
Скопировал пример с котом (где он левелапается), интересовал момент про метод

public static void incrementNumber(int x) {
       x++;
   }
Удалил все про кота и случайно по-невнимательности удалил одну закрывающую скобку метода main. В итоге добавил в самом конце скобку, что б их было четно. Получилось что то такое:

public class Main {

    public static void main(String[] args) {

        int x = 7;
        incrementNumber(x);
        System.out.println(x);
        public static void incrementNumber ( int x){
            x++;
        }
    }
}
Часа два голову ломал, что за код... почему статический метод в статическом методе? Что это за пример вообще такой!? Подумал, что сошел с ума, потому, что не могу понять... Невнимательность.
19 июля 2023
все переменные передаются в метод по значению! У примитивов значением является - число, символ или булево выражение, а у ссылочных переменных - ссылка.