JavaRush /Java блог /Random /Кофе-брейк #207. 20 приемов работы на Java, которые помог...

Кофе-брейк #207. 20 приемов работы на Java, которые помогут вам улучшить качество кода

Статья из группы Random

20 приемов работы на Java, которые помогут вам улучшить качество кода

Источник: Medium Вашему вниманию предлагается набор рекомендаций, соблюдение которых поможет улучшить качество вашего Java-кода. Кофе-брейк #207. 20 приемов работы на Java, которые помогут вам улучшить качество кода - 1

1. По возможности отдавайте предпочтение примитивам, а не классам-оболочкам


Long idNumber;
long idNumber; // long занимает меньше памяти, чем Long

2. Попробуйте использовать подходящий тип для вашей переменной

Если два или более типов удовлетворяют вашим функциональным потребностям, используйте тот тип, который занимает меньше места в памяти.

int birthYear;
short birthYear; // лучше, потому что год рождения не может быть пятизначным


int personRunningSpeedKmHour;
byte personRunningSpeedKmHour; // лучше, потому что скорость движения человека ограничена

3. При проверке нечетности числа побитовый оператор AND намного быстрее, чем арифметический оператор по модулю


public boolean isOdd(int num) {
return (num & 1) != 0;
} 
// лучший способ проверить нечетность числа

4. Избегайте избыточной инициализации (0, false, null..)

Не инициализируйте переменные с их инициализацией по умолчанию, например, boolean по умолчанию имеет значение false, поэтому избыточно инициализировать его значением false.

String name = null; // избыточно
int speed = 0; // избыточно
boolean isOpen = false; // избыточно


String name; 
int speed;
boolean isOpen;
// те же значения в более чистом коде 

5. Объявляйте членов класса закрытыми везде, где это возможно, и всегда давайте модификатору доступа максимально ограниченный доступ


public int age; // очень плохо
int age; // плохо
private int age; // хорошо

6. Избегайте использования ключевого слова “new” при создании строки


String s1 = new String("AnyString") ; // плохая реализация 
// Конструктор создает новый объект и добавляет литерал в кучу 


String s2 = "AnyString" ; // хорошо: быстрое создание экземпляра 
// Этот ярлык ссылается на элемент в пуле строк и создает новый объект, только если литерал отсутствует в пуле строк.

7. Для объединения нескольких строк используйте StringBuilder или StringBuffer вместо использования оператора +

Оператор + неэффективен, поскольку компилятор Java создает несколько промежуточных объектов String перед созданием окончательной объединенной строки. StringBuilder или StringBuffer изменяют String без создания промежуточных объектов String.

String address = streetNumber +" "+ streetName +" "
+cityName+" "+cityNumber+" "+ countryName; // плохо


StringBuilder address = new StringBuilder(streetNumber).append(" ")
.append(streetName).append(" ").append(cityName).append(" ")
.append(cityNumber).append(" ").append(countryName); // хорошо
Учтите, что StringBuilder не потокобезопасен, не синхронизирован, но он быстрее, чем StringBuffer, который потокобезопасен и синхронизирован.

8. Используйте подчеркивание в числовых литералах


int myMoneyInBank = 58356823;
int myMoneyInBank = 58_356_823; // лучше читаемый код

long billsToPay = 1000000000L;
long billsToPay = 1_000_000_000L; // лучше читаемый код

9. Избегайте использования “for loop” с индексами

Не используйте for loop с переменной индекса (или счетчика), если вы можете заменить его расширенным циклом for (начиная с Java 5) или forEach (начиная с Java 8). Это связано с тем, что переменная индекса подвержена ошибкам, поскольку мы можем случайно изменить ее в теле цикла или начать индекс с 1 вместо 0.

for (int i = 0; i < names.length; i++) 
{ saveInDb(names[i]); }


for (String name : names) 
{ saveInDb(name); } // более чистый код

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();}}
// подвержено ошибкам, так как мы можем забыть закрыть сканер в блоке finally



try (Scanner scanner = new Scanner(new File("test.txt"))) 
{while (scanner.hasNext()) 
{System.out.println(scanner.nextLine());}} 
catch (FileNotFoundException fnfe) 
{fnfe.printStackTrace();} 
// чище и более лаконично

11. Не используйте пустые блоки catch

Пустой блок catch приведет к тому, что программа молча выйдет из строя и не даст никакой информации о том, что пошло не так.

try
{ productPrice = Integer.parseInt(integer); } 
catch (NumberFormatException ex)
{ } 
// без каких-либо сообщений об ошибке 


try 
{ productPrice = Integer.parseInt(integer); } 
catch (NumberFormatException ex) 
{unreadablePrices.add(productPrice); // обработка ошибки
log.error("Cannot read price : ", productPrice ); // правильное и осмысленное сообщение
}

12. Избегайте Null Pointer Exception, где это возможно.

Старайтесь избегать исключений Null Pointer Exception, которые могут возникнуть в следующих ситуациях:
  • Возврат пустых коллекций вместо возврата элементов Null.
  • Частое использование Optional.
  • Методы requireNonNull в java.utils.Objects.
  • Аннотации NotNull, NotEmpty, NotBlank.
  • Objects::nonNull в Streams.
  • Методы requireNonNull в java.util.Objects.

13. Добавляйте только необходимые геттеры, сеттеры, конструкторы и избегайте Lombok

Добавляйте только тот код, который вам нужен. Lombok — отличный инструмент, который может помочь вам в создании шаблонного кода, но у него есть некоторые недостатки, такие как несовместимость с IDE, использование непубличного API, и он тесно связан с java-компилятором. Кроме того, начиная с Java 14, records могут заменить некоторые его утилиты.

14. Чтобы проверить равенство, используйте == для ссылок и equals для объектов


// предварительное условие: класс person переопределяет equals() и 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
Более подробную информацию по этой теме вы можете найти на StackOverflow.

15. Всегда применяйте hashCode при реализации equals

Никогда не забывайте переопределять hashCode, если вы переопределяете equals, чтобы не “нарушить контракт”. Согласно API, результат, возвращаемый методом hashCode() для двух объектов, должен быть одинаковым, если их методы equals показывают, что они эквивалентны.

16. Отдавайте предпочтение records (начиная с Java 14) для неизменяемых данных


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);
    }
}



//  этот класс можно преобразовать в record:
record Person(String name, long idNumber) { } // чище и менее многословно

17. Для констант используйте enum или класс final вместо интерфейса

Используйте класс final и определите частный конструктор (private), чтобы скрыть общедоступный .

public final class MyValues {
  private MyValues() {
    // Нет необходимости создавать экземпляр класса, мы можем скрыть его конструктор
  }
  public static final String VALUE1 = "foo";
  public static final String VALUE2 = "bar";
}

18. Добавляйте пустую строку перед аннотацией


// <-- пустая строка
@Repository
public class ...

19. Статические поля должны быть размещены в верхней части класса

20. Начиная с Java 8 для обработки типа даты рекомендуется использовать java.handling.java.localDateTime

Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ