Надеюсь данная публикация будет полезна не только начинающим.
Цель данной публикации:
Показать наиболее часто встречающиеся ошибки начинающих и некоторые приемы их исправления. Понятно, что некоторые ошибки могут быть сложными и происходить по тем или иным причинам. Цель публикации в некоторой степени проанализировать их и помочь выявить на раннем этапе. Надеюсь данная публикация будет полезна начинающим.
Подводные камни Java
Все языки программирования имеют свои достоинства и недостатки. Это обусловлено многими причинами. Язык Java не исключение. Я попытался собрать некоторые очевидные и не очевидные трудности, с которыми сталкивается начинающий программист Java. Уверен, что опытные программисты тоже найдут в моей статье что-то полезного. Практика, внимательность и полученный опыт программирования, помогут избавить вас от многих ошибок. Но некоторые ошибки и трудности лучше рассмотреть заранее. Я приведу несколько примеров с кодом и объяснениями. Многие объяснения вам станут понятны из комментариев к коду. Практика дает очень многое, так как некоторые правила не столь очевидны. Некоторые лежат на поверхности, некоторые скрыты в библиотеках языка или в виртуальной машине java. Помните, что java это не только язык программирования с набором библиотек, это еще и виртуальная машина java.
Для статьи я специально написал работающий код с подробными комментариями. Для написания статьи использовалась java 8. Для тестирования код java помещен в отдельные пакеты.
Пример: «package underwaterRocks.simple;»
С какими трудностями сталкиваются начинающие?
Опечатки
Бывает так, что начинающие программисты делают опечатки, которые трудно обнаружить с первого взгляда.
Пример кода:
Файл: «Simple.java»
/*
учебные пример
; после условия и блок
*/
package underwaterRocks.simple;
/**
*
* @author Ar20L80
*/
public class Simple {
public static void main(String[] args) {
int ival = 10;
if(ival>0);
{
System.out.println("Этот блок не зависит от условия");
}
}
}
Объяснение: «Точка с запятой означает конец оператора. В данном случае; — это конец пустого оператора. Это логическая ошибка. Такую ошибку бывает трудно обнаружить.
Компилятор сочтет, что всё правильно. Условие if(ival>0); в данном случае не имеет смысла. Потому как означает: если ival больше нуля, ничего не делать и продолжить.»
Присвоение в условии вместо сравнения
В условии присвоение переменной.
Это не ошибка, но использование такого приема должно быть оправдано.
boolean myBool = false;
if(myBool = true) System.out.println(myBool);
В данном коде if(myBool = true) означает :«Присвоить переменной myBool значение true,
если выражение истинно, выполнить условие следующее за скобками.»
В данном коде условие будет всегда истинно. И System.out.println(myBool); будет выполнено всегда, независимо от условия.
== — это сравнение на равенство.
= — это присвоение, вы можете проговорить a = 10; как: «а присвоить значение 10».
Условие в скобках возвращает логическое значение.
Не важно в каком порядке вы запишите. Вы можете сравнить так: (0 == a) или (5 == a)
Если вы забудете один знак равенства, например так (0 = a) или (5 = a), то компилятор сообщит вам об ошибке. Вы присваиваете значение, а не сравниваете.
Вы также можете записать в удобочитаемой форме какой-то интервал.
Например: вам нужно написать: a больше 5 и меньше 10.
Вы пишите так: (a>4 && a<10), но с таким же успехом вы можете написать: (4<a && a<10),
теперь вы видите, что a находится в интервале между 4 и 10, исключая эти значения. Это более наглядно. Сразу видно, что а находится в интервале между 4 и 10, исключая эти значения.
Пример в коде(интервал ]3,9[ ):
if(3<a&&a<9) выполнить;
Логическая ошибка
if(условие){} if(условие){} else{} — else относится к ближайшему if.
Часто это бывает причиной ошибок начинающих.
Неправильное сравнение строкНачинающие довольно часто используют == вместо .equals для сравнения строк.
Инициализация переменных
Рассмотрим инициализацию переменных примитивного типа.
Примитивы (byte, short, int, long, char, float, double, boolean).
Начальные значения.
byte 0
short 0
int 0
long 0L
float 0.0f
double 0.0d
char '\u0000'
String (or any object) null
boolean false (зависит от jvm)
Примечание:
Локальные переменные немного отличаются;
Компилятор никогда не присваивает значение по умолчанию неинициализированной локальной переменной.
Если вы не можете инициализировать свою локальную переменную там, где она объявлена,
не забудьте присвоить ей значение, прежде чем пытаться её использовать.
Доступ к неинициализированной локальной переменной приведет к ошибке времени компиляции.
Подтверждение этого примечания в коде:
Файл: «MyInitLocal.java»
/*
учебные пример
инициализация переменных класса и локальных переменных
*/
package underwaterRocks.myInit;
/**
*
* @author Ar20L80
*/
public class MyInitLocal {
float classes_f;
int classes_gi;
public static void main(String[] args) {
float f;
int i;
MyInitLocal myInit = new MyInitLocal();
/* в этом месте переменные уже инициализированы параметрами по умолчанию.*/
System.out.println("myInit.classes_f = " + myInit.classes_f);
System.out.println("myInit.classes_gi = " + myInit.classes_gi);
// System.out.println("f = " + f); // ошибка. Локальная переменная не инициализирована
// System.out.println("f = " + i); // ошибка. Локальная переменная не инициализирована
}
}
Диапазоны значений:
byte (целые числа, 1 байт, [-128, 127])
short (целые числа, 2 байта, [-32768, 32767])
int (целые числа, 4 байта, [-2147483648, 2147483647])
long (целые числа, 8 байт, [-922372036854775808,922372036854775807])
float (вещественные числа, 4 байта)
double (вещественные числа, 8 байт)
char (символ Unicode, 2 байта, 16 бит, [0, 65535])
boolean (значение истина/ложь, используется int, зависит от JVM)
char: The char data type is a single 16-bit Unicode character. It has a minimum value of '\u0000' (or 0) and a maximum value of '\uffff' (or 65,535 inclusive).
Документация Oracle >>
Попытаемся инициализировать переменную типа long числом: 922372036854775807.
У нас ничего не выйдет. Потому как, это целочисленный литерал типа int.
Правильная инициализация литералом типа long: 922372036854775807L;
Пример кода:
Файл: «MyInitLocalLong.java»
/*
учебные пример
Инициализация long локально
*/
package underwaterRocks.myInit;
/**
*
* @author Ar20L80
*/
public class MyInitLocalLong {
public static void main(String[] args) {
// long al = 922372036854775807; //ошибка integer number too large
long bl = 922372036854775807L; // так правильно
}
}
На что следует обращать внимание при инициализации переменной.
На диапазон значений переменной данного типа. На то, что переменная инициализируется литералом определенного типа. На явное и неявное приведение типов. На совместимость типов.
При использовании оболочек типа Integer, следует обратить внимание на авто упаковку и авто распаковку данных типов.
Неправильное использование double
Здесь нужно пояснить. Речь идет не о неправильном использовании типа double.
Используем мы правильно. Только результат может удивить начинающего программиста.
/*
учебный пример
*/
package underwaterRocks.tstDouble;
/**
*
* @author vvm
*/
public class MinusDouble {
public static void main(String[] args) {
double a = 4.64;
double b = 2.64;
System.out.println("a-b = "+(a-b));
}
}
/*
Вывод программы
run:
a-b = 1.9999999999999996
*/
Примечание о типе double. Плавающая точка позволяет считать с заданной относительной погрешностью и огромным диапазоном. В научных расчетах часто нужна относительная погрешность.
Неправильное сравнение double
Рассмотрим тип double.
Пример кода:
Файл: «MyDouble.java»
/*
учебные пример
Сравнение double
Осторожно - double.
*/
package underwaterRocks.myDouble;
/**
*
* @author Ar20L80
*/
public class MyDouble {
public static void main(String[] args) {
double dx = 1.4 - 0.1 - 0.1 - 0.1 - 0.1;
System.out.println("dx = " + dx); // dx = 0.9999999999999997
System.out.print("Сравнение (dx == 1.0):");
System.out.println(dx == 1.0); // false, потому что 1.0 не равно 0.9999999999999997
/*как правильно сравнивать double*/
final double EPSILON = 1E-14;
double xx = 1.4 - 0.1 - 0.1 - 0.1 - 0.1;
double xy = 1.0;
/* сравниваем xx c xy */
if (Math.abs(xx - xy) < EPSILON)
System.out.println(xx + " это примерно равно " + xy + " EPSILON = " + EPSILON);
}
}
Тип double удобен там, где не нужна высокая точность. Для финансовых операций этот тип не годится. Хотя некоторые, не очень честные компании, использую тип double, для округления в нужную им сторону. Для финансовых операций используется класс BigDecimal в финансовых расчётах, так как вещественные примитивные типы не годятся для этой цели по причинам потери точности и ошибках результатах округления. Однако, более точные результаты дает использование класса BigInteger.
Конструктор класса
Конструктор класса совпадает с именем класса и ничего не возвращает, даже void.
Пример кода:
Файл: «MyConstructor.java»
/*
учебные пример
Конструктор ничего не возвращает, даже void
То что с void - обычный метод класса
*/
package underwaterRocks.myConstructor;
/**
*
* @author Ar20L80
*/
public class MyConstructor {
public MyConstructor(){
System.out.println("Я конструктор без void");
}
public void MyConstructor(){
System.out.println("Я конструктор c void");
}
public static void main(String[] args) {
MyConstructor myconst = new MyConstructor();
myconst.MyConstructor(); // вызов обычного метода
}
}
Как мы видим в коде два метода с одинаковыми именами: MyConstructor() и MyConstructor(). Один из методов ничего не возвращает. Это и есть конструктор нашего класса. Другой метод с void — это обычный метод класса. В случае, когда вы не создали конструктор или создали, по вашему мнению конструктор класса с void, то компилятор создаст конструктор по умолчанию и вы будете удивлены, почему ваш конструктор не работает.
Деление на ноль
Как вы думаете, какой будет результат выполнения такого кода.
Файл: «DivisionByZero.java»
/*учебные пример*/
package divisionByZero;
import static java.lang.Double.POSITIVE_INFINITY;
/**
*
* @author Ar20L80
*/
public class DivisionByZero {
public static void main(String[] args) {
try{
float f = 12.2f;
double d = 8098098.8790d;
System.out.println(f/0);
System.out.println(d/0);
System.out.println(POSITIVE_INFINITY == f/0);
System.out.println(POSITIVE_INFINITY == d/0);
}
catch (NumberFormatException ex) {
System.out.println("NumberFormatException");
}
catch (ArithmeticException ex) {
System.out.println("ArithmeticException");
}
}
}
Выполнение кода выведет:
Infinity
Infinity
true
true
Деление целого типа на ноль даст ArithmeticException.
В классе java.lang.Double определена константа POSITIVE_INFINITY;
public static final float POSITIVE_INFINITY = 1.0d / 0.0d;
Она преобразуется в строку равную Infinity.
Порядок инициализации
Файл: «InitClass.java»
/*
учебные пример
инициализация класса
*/
package myInitClass;
/**
*
* @author Ar20L80
*/
public class InitClass {
InitClass(){ // конструктор класса
System.out.print("Конструктор");
}
{ // блок инициализации
System.out.print("3 ");
}
public static void main(String[] args) {
System.out.print("2");
new InitClass();
}
static { // статический блок инициализации
System.out.print("1");
}
}
Вначале выполняются все статические блоки, затем блоки инициализации, затем конструктор класса.
Выведется: «123 Конструктор»
Локальная переменная скрывает переменную класса
Хотя современные IDE легко обнаруживают такую ошибку, хотелось бы рассмотреть такую ошибку подробнее. Начнем с классического присвоения переменной в конструкторе. Пример правильный. Тут никакой ошибки нет.
public class MyClass {
private int val = 0;
public MyClass(int val) {
this.val = val;
}
}
Однако, что произойдет, если вы используете такой прием в методе, а не в конструкторе класса? В обычном методе использовать такой прием не рекомендуется. Вопрос относится к правильному проектированию класса.
Простое объяснение: В методе переменная с тем же именем, что и переменная класса, является локальной по отношению к методу. Вы можете обращаться к переменной класса используя this.val. Однако такое обращение из метода, при неправильном проектировании класса только вызовет побочные эффекты и может ухудшить читаемость кода.
Приведение типов в арифметических выражениях выполняется автоматически
Это может стать причиной досадных ошибок.
// byte a = 1;
// byte b = 1;
// byte с = a + b; // ошибка
// byte a = (byte) 1;
// byte b = (byte) 1;
// byte с = a + b; // ошибка
// одно из возможных решений - явное преобразование в арифметических выражениях.
byte a = 1;
byte b = 1;
byte c = (byte) (a + b);
// одно из возможных решений - использование final
// final byte a = 1;
// final byte b = 1;
// byte c = a + b; // автоматического приведения не будет, поскольку a и b final
Одно из возможных решений при работе со строкой:
byte bHundr = Byte.parseByte("100"); // явное приведение строки к типу byte
Еще одна ошибка приведена в следующем коде.
for (byte i = 1; i <= 128; i++) {
System.out.println(i);
}
В данном случае получится бесконечный цикл.
Выводы
Многие ошибки не очевидны с первого взгляда. Даже опытные программисты их совершают, но в меньшем количестве. Внимательность, практический опыт, использование отладчика и чтение документации позволят вам избежать многих ошибок.
Надеюсь, статья вам понравилась и оказалась полезной. Буду рад вашим комментариям, замечаниям, предложениям, пожеланиям. Продолжение следует. Вернее дополнение следует.
Лицензия
«Я разрешаю читать эту статью, разрешаю использовать эту статью, позволяю улучшать эту статью». Статья распространяется на условиях GNU FDL.
Ссылки
Рекомендации об оформлении кода на Javа от Oracle >>>
Инициализация переменных
Рассмотрим инициализацию переменных примитивного типа.
Примитивы (byte, short, int, long, char, float, double, boolean).
Начальные значения.
byte 0
short 0
int 0
long 0L
float 0.0f
double 0.0d
char '\u0000'
String (or any object) null
boolean false (зависит от jvm)
Примечание:
Локальные переменные немного отличаются;
Компилятор никогда не присваивает значение по умолчанию неинициализированной локальной переменной.
Если вы не можете инициализировать свою локальную переменную там, где она объявлена,
не забудьте присвоить ей значение, прежде чем пытаться её использовать.
Доступ к неинициализированной локальной переменной приведет к ошибке времени компиляции.
Подтверждение этого примечания в коде:
Файл: «MyInitLocal.java»
/*
учебные пример
инициализация переменных класса и локальных переменных
*/
package underwaterRocks.myInit;
/**
*
* @author Ar20L80
*/
public class MyInitLocal {
float classes_f;
int classes_gi;
public static void main(String[] args) {
float f;
int i;
MyInitLocal myInit = new MyInitLocal();
/* в этом месте переменные уже инициализированы параметрами по умолчанию.*/
System.out.println("myInit.classes_f = " + myInit.classes_f);
System.out.println("myInit.classes_gi = " + myInit.classes_gi);
// System.out.println("f = " + f); // ошибка. Локальная переменная не инициализирована
// System.out.println("f = " + i); // ошибка. Локальная переменная не инициализирована
}
}
Диапазоны значений:
byte (целые числа, 1 байт, [-128, 127])
short (целые числа, 2 байта, [-32768, 32767])
int (целые числа, 4 байта, [-2147483648, 2147483647])
long (целые числа, 8 байт, [-922372036854775808,922372036854775807])
float (вещественные числа, 4 байта)
double (вещественные числа, 8 байт)
char (символ Unicode, 2 байта, 16 бит, [0, 65535])
boolean (значение истина/ложь, используется int, зависит от JVM)
char: The char data type is a single 16-bit Unicode character. It has a minimum value of '\u0000' (or 0) and a maximum value of '\uffff' (or 65,535 inclusive).
Документация Oracle >>
Попытаемся инициализировать переменную типа long числом: 922372036854775807.
У нас ничего не выйдет. Потому как, это целочисленный литерал типа int.
Правильная инициализация литералом типа long: 922372036854775807L;
Пример кода:
Файл: «MyInitLocalLong.java»
/*
учебные пример
Инициализация long локально
*/
package underwaterRocks.myInit;
/**
*
* @author Ar20L80
*/
public class MyInitLocalLong {
public static void main(String[] args) {
// long al = 922372036854775807; //ошибка integer number too large
long bl = 922372036854775807L; // так правильно
}
}
На что следует обращать внимание при инициализации переменной.
На диапазон значений переменной данного типа. На то, что переменная инициализируется литералом определенного типа. На явное и неявное приведение типов. На совместимость типов.
При использовании оболочек типа Integer, следует обратить внимание на авто упаковку и авто распаковку данных типов.
Неправильное использование double
Здесь нужно пояснить. Речь идет не о неправильном использовании типа double.
Используем мы правильно. Только результат может удивить начинающего программиста.
/*
учебный пример
*/
package underwaterRocks.tstDouble;
/**
*
* @author vvm
*/
public class MinusDouble {
public static void main(String[] args) {
double a = 4.64;
double b = 2.64;
System.out.println("a-b = "+(a-b));
}
}
/*
Вывод программы
run:
a-b = 1.9999999999999996
*/
Примечание о типе double. Плавающая точка позволяет считать с заданной относительной погрешностью и огромным диапазоном. В научных расчетах часто нужна относительная погрешность.
Неправильное сравнение double
Рассмотрим тип double.
Пример кода:
Файл: «MyDouble.java»
/*
учебные пример
Сравнение double
Осторожно - double.
*/
package underwaterRocks.myDouble;
/**
*
* @author Ar20L80
*/
public class MyDouble {
public static void main(String[] args) {
double dx = 1.4 - 0.1 - 0.1 - 0.1 - 0.1;
System.out.println("dx = " + dx); // dx = 0.9999999999999997
System.out.print("Сравнение (dx == 1.0):");
System.out.println(dx == 1.0); // false, потому что 1.0 не равно 0.9999999999999997
/*как правильно сравнивать double*/
final double EPSILON = 1E-14;
double xx = 1.4 - 0.1 - 0.1 - 0.1 - 0.1;
double xy = 1.0;
/* сравниваем xx c xy */
if (Math.abs(xx - xy) < EPSILON)
System.out.println(xx + " это примерно равно " + xy + " EPSILON = " + EPSILON);
}
}
Тип double удобен там, где не нужна высокая точность. Для финансовых операций этот тип не годится. Хотя некоторые, не очень честные компании, использую тип double, для округления в нужную им сторону. Для финансовых операций используется класс BigDecimal в финансовых расчётах, так как вещественные примитивные типы не годятся для этой цели по причинам потери точности и ошибках результатах округления. Однако, более точные результаты дает использование класса BigInteger.
Конструктор класса
Конструктор класса совпадает с именем класса и ничего не возвращает, даже void.
Пример кода:
Файл: «MyConstructor.java»
/*
учебные пример
Конструктор ничего не возвращает, даже void
То что с void - обычный метод класса
*/
package underwaterRocks.myConstructor;
/**
*
* @author Ar20L80
*/
public class MyConstructor {
public MyConstructor(){
System.out.println("Я конструктор без void");
}
public void MyConstructor(){
System.out.println("Я конструктор c void");
}
public static void main(String[] args) {
MyConstructor myconst = new MyConstructor();
myconst.MyConstructor(); // вызов обычного метода
}
}
Как мы видим в коде два метода с одинаковыми именами: MyConstructor() и MyConstructor(). Один из методов ничего не возвращает. Это и есть конструктор нашего класса. Другой метод с void — это обычный метод класса. В случае, когда вы не создали конструктор или создали, по вашему мнению конструктор класса с void, то компилятор создаст конструктор по умолчанию и вы будете удивлены, почему ваш конструктор не работает.
Деление на ноль
Как вы думаете, какой будет результат выполнения такого кода.
Файл: «DivisionByZero.java»
/*учебные пример*/
package divisionByZero;
import static java.lang.Double.POSITIVE_INFINITY;
/**
*
* @author Ar20L80
*/
public class DivisionByZero {
public static void main(String[] args) {
try{
float f = 12.2f;
double d = 8098098.8790d;
System.out.println(f/0);
System.out.println(d/0);
System.out.println(POSITIVE_INFINITY == f/0);
System.out.println(POSITIVE_INFINITY == d/0);
}
catch (NumberFormatException ex) {
System.out.println("NumberFormatException");
}
catch (ArithmeticException ex) {
System.out.println("ArithmeticException");
}
}
}
Выполнение кода выведет:
Infinity
Infinity
true
true
Деление целого типа на ноль даст ArithmeticException.
В классе java.lang.Double определена константа
POSITIVE_INFINITY;
public static final float POSITIVE_INFINITY = 1.0d / 0.0d;
Она преобразуется в строку равную Infinity.
Порядок инициализации
Файл: «InitClass.java»
/*
учебные пример
инициализация класса
*/
package myInitClass;
/**
*
* @author Ar20L80
*/
public class InitClass {
InitClass(){ // конструктор класса
System.out.print("Конструктор");
}
{ // блок инициализации
System.out.print("3 ");
}
public static void main(String[] args) {
System.out.print("2");
new InitClass();
}
static { // статический блок инициализации
System.out.print("1");
}
}
Вначале выполняются все статические блоки, затем блоки инициализации, затем конструктор класса.
Выведется: «123 Конструктор»
Локальная переменная скрывает переменную класса
Хотя современные IDE легко обнаруживают такую ошибку, хотелось бы рассмотреть такую ошибку подробнее. Начнем с классического присвоения переменной в конструкторе. Пример правильный. Тут никакой ошибки нет.
public class MyClass {
private int val = 0;
public MyClass(int val) {
this.val = val;
}
}
Однако, что произойдет, если вы используете такой прием в методе, а не в конструкторе класса? В обычном методе использовать такой прием не рекомендуется. Вопрос относится к правильному проектированию класса.
Простое объяснение: В методе переменная с тем же именем, что и переменная класса, является локальной по отношению к методу. Вы можете обращаться к переменной класса используя this.val. Однако такое обращение из метода, при неправильном проектировании класса только вызовет побочные эффекты и может ухудшить читаемость кода.
Приведение типов в арифметических выражениях выполняется автоматически
Это может стать причиной досадных ошибок.
// byte a = 1;
// byte b = 1;
// byte с = a + b; // ошибка
// byte a = (byte) 1;
// byte b = (byte) 1;
// byte с = a + b; // ошибка
// одно из возможных решений - явное преобразование в арифметических выражениях.
byte a = 1;
byte b = 1;
byte c = (byte) (a + b);
// одно из возможных решений - использование final
// final byte a = 1;
// final byte b = 1;
// byte c = a + b; // автоматического приведения не будет, поскольку a и b final
Одно из возможных решений при работе со строкой:
byte bHundr = Byte.parseByte("100"); // явное приведение строки к типу byte
Еще одна ошибка приведена в следующем коде.
for (byte i = 1; i <= 128; i++) {
System.out.println(i);
}
В данном случае получится бесконечный цикл.
Выводы
Многие ошибки не очевидны с первого взгляда. Даже опытные программисты их совершают, но в меньшем количестве. Внимательность, практический опыт, использование отладчика и чтение документации позволят вам избежать многих ошибок.
Надеюсь, статья вам понравилась и оказалась полезной. Буду рад вашим комментариям, замечаниям, предложениям, пожеланиям. Продолжение следует. Вернее дополнение следует.
Лицензия
«Я разрешаю читать эту статью, разрешаю использовать эту статью, позволяю улучшать эту статью». Статья распространяется на условиях GNU FDL.
Ссылки
Рекомендации об оформлении кода на Javа от Oracle >>>
Комментарии (21)
poxvuibr
09.02.2019 17:25Вот из-за таких проблем как в первом примере с точкой запятой после if — надо всегда ставить открывающую скобку на той же строчке, что if и всегда ставить после if фигурные скобки, даже если дальше только одна строка.
nicholas_k
09.02.2019 17:30boolean myBool = false;
if(myBool = true) System.out.println(myBool);
Не надо в условии bool сравнивать с boolViceCily
10.02.2019 07:19Также, в большинстве случаев стоит работать с final явно. Либо переходить на Котлин.
roman901
09.02.2019 18:15+3А можно спросить, что из этого ошибки, если это всё — вполне описанное поведение языка?
Придирка к опечаткам уровня «не там поставил точку с запятой» — выглядят совсем странными.
Ar20L80 Автор
09.02.2019 19:00-4nicholas_k, Благодарю за комментарий. Нет не надо «Не надо в условии bool сравнивать с bool». Только вы о чем? Пожалуйста, прочитайте внимательно. Речь идет о присвоении переменной значения true в условии if. Это не ошибка, но такой прием следует использовать с осторожностью. Лучше вообще не использовать.
roman901, Благодарю за комментарий. Цель публикации не придирки к опечаткам. Дан конкретный пример, где опечатку бывает сложно с первого взгляда определить.
nicholas_k
09.02.2019 20:49+1Возможно я недостаточно внимательно прочел, поправьте, если я неправ.
Насколько я понял, имелась в виду ошибка, когда вместо
мы пишемif(bool == true){}
if(bool = true){}
Дело в том, что такая ошибка возможна только с типом bool(Boolean), с любым другим не скомпилируется. Но дело в том, что выражение
совершенно эквивалентно выражениюif(bool == true){}
.if(bool){}
При таком раскладе мы не только пишем меньше кода, но и получаем более читабельный код, особенно если используем общепринятое именование булевых переменных по типу isSomethingChecked.
Igor_ku
09.02.2019 19:08Довольно странные у вас получились ошибки.
Присвоение в условии вместо сравнения, Инициализация переменных
и опечатку в виде пустого if вообще распознаёт Idea. Ну а все остальные либо специфика языка, либо довольно понятные ошибки. Для начинающего java'ста это наверное самые малые проблемы, которые только можно придумать :)
Ar20L80 Автор
09.02.2019 21:55-2nicholas_k, Спасибо за комментарий. Нет вы всё поняли правильно. Это я не достаточно ясно написал. Постараюсь дополнить. Речь идет не о if(bool == true){}, а именно о присвоении переменной значения переменной в условии. Пример: (bOol = true), переменной bOol присваиваем значение true, оператор () возвращает значение переменной, после присвоения. И тд.
Suvitruf
09.02.2019 22:04+7Упоминание Java 8 улыбнуло, учитывая, что примеры из статьи отдают началом 2000-х.
Ar20L80 Автор
09.02.2019 23:49-3PS. Правильно поставленный вопрос, уже половина ответа. Как говорится: «Торг здесь не уместен».
poxvuibr
10.02.2019 12:03Насчёт того, что можно сделать метод, название которого такое же как у класса и перепутать его с конструктором. Первое, что говорят про методы в java это то, что название метода должно начинаться с маленькой буквы. Первое, что говорят про классы это то, что название класса должно начинаться с большой буквы. Поэтому как правило проблема описанная в статье на практике не встречается.
pmcode
10.02.2019 13:25+1Видимо программисты, которые напарываются на такие «подводные камни», вместо IDE пользуются блокнотом.
akurilov
10.02.2019 15:20+4На хабре конкурс статей на тему "как я пытался hello world в первый раз" что ли?
million
10.02.2019 21:59У вас опечатка: char (символ Unicode, 2 байта, [0, 65536]) -> 65535
Будьте внимательны, раз уж про ошибки пишите :)
alksily
Спасибо за статью, лишний раз напомнить себе о внимательности не помешает. Кроме того многое из описанного так же может и будет попадаться и в других языках.