20 советов для java-разработчиков
Некоторые из важнейших советов для java-разработчиков, которые помогут вам повысить качество вашего кода.
1-Отдавайте предпочтение примитивам, а не классам-оболочкам, когда это возможно.
Long idNumber;
long idNumber; // long takes less memory than Long
2-Попробуйте использовать подходящий тип для ваших переменных.
Если два или более типа данных удовлетворяют ваши функциональные потребностям, используйте тот, который занимает меньше места в памяти.
int birthYear;
short birthYear; // better because birth year can not be more than 32767
int personRunningSpeedKmHour;
byte personRunningSpeedKmHour; // better because a person can not have
// more than 127 km/h as speed
3- Для проверки нечётности числа побитовый оператор AND выполняется намного быстрее, чем арифметический оператор по модулю.
public boolean isOdd(int num) {
return (num & 1) != 0;
}
// best way to check the oddity of a number
4-Избегайте избыточной инициализации (0, false, null..)
Например, boolean
, по-умолчанию, имеет значение false, поэтому не стоит излишне его инициализировать .
String name = null; // redundant
int speed = 0; // redundant
boolean isOpen = false; // redundant
String name;
int speed;
boolean isOpen;
// same values in a cleaner way
5-Объявляйте членов класса private везде, где это возможно, и всегда указывайте модификатор наиболее ограниченного доступа.
public int age; // very bad
int age; // bad
private int age; // good
6-Избегайте использования ключевого слова ‘new’ при создании строки.
String s1 = new String("AnyString") ; // bad : low instantiation
// The constructor creates a new object, and adds the literal to the heap
String s2 = "AnyString" ; // good: fast instantiation
// This shortcut refers to the item in the String pool
// and creates a new object only if the literal is not in the String pool.
7-Для объединения нескольких строк используйте StringBuilder или StringBuffer вместо использования оператора +.
Оператор +
неэффективен, поскольку компилятор java создаёт несколько промежуточных строковых объектов перед созданием окончательной объединённой строки.StringBuilder
или StringBuffer
изменяют строку без создания промежуточных строковых объектов.
String address = streetNumber +" "+ streetName +" "
+cityName+" "+cityNumber+" "+ countryName; // bad
StringBuilder address = new StringBuilder(streetNumber).append(" ")
.append(streetName).append(" ").append(cityName).append(" ")
.append(cityNumber).append(" ").append(countryName); // good
8-Используйте символы подчёркивания в числовых литералах.
int myMoneyInBank = 58356823;
int myMoneyInBank = 58_356_823; // more readable
long billsToPay = 1000000000L;
long billsToPay = 1_000_000_000L; // more readable
9-Избегайте использования циклов for с index.
Не используйте цикл for с переменной index (или counter), если вы можете заменить его расширенным циклом for (начиная с Java 5) или forEach
(начиная с Java 8). Это потому, что переменная index подвержена ошибкам, так как мы можем случайно изменить её в теле цикла, или мы можем начать индекс с 1 вместо 0.
for (int i = 0; i < names.length; i++)
{ saveInDb(names[i]); }
for (String name : names)
{ saveInDb(name); } // cleaner
10-Замените try–catch-finally на try-with-resources.
Scanner scanner = null;
try
{scanner = new Scanner(new File("test.txt"));
while (scanner.hasNext())
{System.out.println(scanner.nextLine());}}
catch (FileNotFoundException e)
{e.printStackTrace();}
finally
{if (scanner != null)
{scanner.close();}}
// error-prone as we can forget to close the scanner in the finally block
try (Scanner scanner = new Scanner(new File("test.txt")))
{while (scanner.hasNext())
{System.out.println(scanner.nextLine());}}
catch (FileNotFoundException fnfe)
{fnfe.printStackTrace();}
// cleaner and more succinct
11-Отсутствие свободных блоков захвата.
Пустой блок catch приведёт к молчаливому завершению программы и не даст никакой информации о том, что пошло не так.
try
{ productPrice = Integer.parseInt(integer); }
catch (NumberFormatException ex)
{ }
// fail silently without giving any feedback
try
{ productPrice = Integer.parseInt(integer); }
catch (NumberFormatException ex)
{unreadablePrices.add(productPrice); // handle error
log.error("Cannot read price : ", productPrice );// proper and meaningful message
}
12-Избегайте исключения нулевого указателя, насколько это возможно.
Постарайтесь избежать исключений с нулевым указателем, которые могут возникать во время выполнения, с помощью:
- Возврата пустых коллекций вместо возврата нулевых элементов
- Использования
Optional
, если это возможно - методов
requireNonNull
в java.utils.Objects - Аннотаций
NotNull, NotEmpty, NotBlank
Objects::nonNull
вStreams
- методов
requireNonNull
вjava.util.Objects
13-Добавляйте только необходимые геттеры, сеттеры и конструкторы и избегайте Lombok (YAGNI).
Добавляйте только тот код, который вам нужен.
Lombok – отличный инструмент, который может помочь вам сгенерировать некоторый шаблонный код, но у него есть некоторые недостатки, такие как несовместимость IDE, использование непубличного API и он тесно связан с компилятором java. Кроме того, начиная с java 14, records может заменить некоторые из его утилит.
14-Чтобы проверить равенство, используйте == для ссылок и equals для объектов.
// prerequisite: the person class overrides equals() and hashCode()
Person p1 = new Person("John","Doe");
Person p2 = new Person("John","Doe");
System.out.println(p1 == p2); // false
System.out.println(p1.equals(p2)); // true
Вы можете ознакомиться с более подробной информацией по этому вопросу здесь
15-Всегда осуществляйте hashCode , когда вы используете equals.
Всегда помните о переопределении hashCode
, если вы используете equals
.
Согласно API, результат, возвращаемый методом hashCode()
для двух объектов, должен быть одинаковым, если их методы equals показывают, что они эквивалентны.
16-Предпочитайте records (начиная с java14) для неизменяемых данных.
public final class Person {
private final String name;
private final long idNumber;
public Person(String name, long idNumber) {
this.name = name;
this.idNumber = idNumber;
}
public boolean equals(Object other) {
if (other == this) return true;
if (other == null) return false;
if (other.getClass() != this.getClass()) return false;
Person that = (Person) other;
return (this.name.equals(that.name)) && (this.idNumber == that.idNumber);
}
public String toString() {
return name + " " + idNumber;
}
public int hashCode() {
return Objects.hash(idNumber, name);
}
}
// this class can be transformed to a record:
record Person(String name, long idNumber) { } // cleaner and less verbose
17-Для констант используйте enum или final class вместо interface.
public final class MyValues {
private MyValues() {
// No need to instantiate the class, we can hide its constructor
}
public static final String VALUE1 = "foo";
public static final String VALUE2 = "bar";
}
18-Добавляйте пустую строку перед аннотацией.
// <-- empty line
@Repository
public class ...
19-Статические поля должны быть размещены в верхней части класса.
20-Для обработки типа даты рекомендуется java.handling.java.LocalDateTime начиная с java 8.
Чтобы ознакомиться с другими передовыми практиками java, я рекомендую эти замечательные книги: ” Clean code” и “Effective java“.