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 в момент, когда отработал один из вариантов. Не стоит о нем забывать, иначе результат может быть неожиданным :)

Комментарии (170)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
Anonymous #3346123
Уровень 13
5 апреля, 09:30
Могут ли быть у разных объектов одинаковые ссылки на эти объекты,? Поскольку носителем ссылки является переменная, то парафраз вопроса такой, может ли одна и та же переменная нести в себе две\ несколько ссылок на разные объекты?
3 апреля, 09:38
Static X🤟
Anton Zinovyev
Уровень 25
23 февраля, 09:06
"В языке Java всегда используется только вызов по значению. Это означает, что метод получает копии значений всех своих параметров. По этой причине метод не может видоизменить содержимое ни одной из переменных, передаваемых ему в ка честве параметров." в Java Библиотека профессионала, том 1 Основы 11-издание подробно расписано с примерами почему. Автор сам не понимает о чем пишет
Ольга
Уровень 15
14 февраля, 10:52
Подскажите пожалуйста, а как сделать так, чтоб метод incrementNumber увеличивал число на единицу к коде примера?
Anonymous #3396816
Уровень 30
19 февраля, 19:52
public static void main(String[] args) {
        int x = 7;
        int i = incrementNumber(x);
        System.out.println(i);
    }

    public static int incrementNumber(int x) {
        return ++x;
    }
Ольга
Уровень 15
20 февраля, 07:13
Спасибо!
Sandrovichus
Уровень 14
25 марта, 14:38
у меня тоже такой вопрос возник. А как сделать так, чтобы функция над самим числом проделала операцию, но ничего не возвращала? Можно ли так вообще сделать?
Петр
Уровень 24
15 декабря 2023, 12:53
В п.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
   }
}
Ика
Уровень 28
18 декабря 2023, 14:53
Спасибо за уточнение, меня действительно смутил этот пункт, когда читал.
Anonymous #3186429
Уровень 13
28 декабря 2023, 16:07
Я с Вами согласен, что тут дело не приоритетах, но мне кажется вот такой пример нагляднее, просто добавим скобки, чтоб уж точно поднять приоритет.
public class TestPlusPlusPriority {
        public static void main(String[] args) {

            int i = 6;
            System.out.println(7 == (i++));
        }
}
Дмитрий Веремеенко
Уровень 16
Expert
27 сентября 2023, 19:43
Повторение - мать заикания. Полезная статья. Время от времени стоит напоминать это материал не только по ходу курса.
Denis Gritsay
Уровень 35
12 сентября 2023, 22:40
хорошая лекция
Anatoly Enterprise Java Developer
8 сентября 2023, 12:58
хороший материал
dim11981
Уровень 47
22 августа 2023, 18:56
п. 7 здесь: Operators
slavich
Уровень 17
Expert
24 июля 2023, 06:58
в 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;
    }
}