Полезные фичи в Java для новичков: мой список

от автора

Привет, Хабр!

В Java никогда не бывает скучно, особенно когда речь заходит о вещах, которые делают нашу жизнь проще и код — чище.

Сегодня я хочу рассказать вам о четырех фичах в Java, которые сам активно использовал в своих проектах и которые, на мой взгляд, заслуживают внимания. Да, это мой личный список, и я не претендую на то, что эти фичи новы или являются последним писком моды. Однако, по моему опыту, они действительно могут упростить жизнь.

И знаете, что самое приятное? Когда коллеги начинают говорить: «А почему я об этом не знал раньше?»

И первая фича — секционные классы.

Секционные классы

Секционные классы были введены в Java 15 как предварительная функция и стали постоянными в Java 17. Основная фича секционных классов — это возможность ограничить, какие классы могут наследовать данный класс.

Секционный класс объявляется с ключевым словом sealed, а классы, которым разрешено его наследовать, указываются с помощью ключевого слова permits. Класс, наследующий секционный класс, должен быть объявлен как final, sealed или non-sealed.

Простой пример:

public sealed class Shape permits Circle, Square {     // общий функционал для всех фигур }  public final class Circle extends Shape {     // специфичный функционал для круга }  public final class Square extends Shape {     // специфичный функционал для квадрата }

Абстрактный класс Shapeможет быть расширен только классами Circle и Square. Теперь можно быть уверенными, что никакая другая фигура не сможет унаследовать Shape.

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

public sealed class Transaction permits CreditTransaction, DebitTransaction {     private double amount;      public Transaction(double amount) {         this.amount = amount;     }      public double getAmount() {         return amount;     }      // общие методы для всех транзакций }  public final class CreditTransaction extends Transaction {     public CreditTransaction(double amount) {         super(amount);     }      // специфичные методы для кредитной транзакции }  public final class DebitTransaction extends Transaction {     public DebitTransaction(double amount) {         super(amount);     }      // специфичные методы для дебетовой транзакции }

Мы уверены, что Transaction может быть только кредитной или дебетовой.

Секционные классы упрощают поддержку кода.

Записи

Записи — это особый вид классов, введённый в Java 14 как предварительная фича и окончательно утверждённый в Java 16. Записи позволяют создавать неизменяемые объекты с минимальным количеством шаблонного кода. Они автоматом генерируют конструкторы, методы equals(), hashCode(), и toString(), а также геттеры для всех полей.

Записи идеально подходят для создания DTO, моделей данных и других объектов, которые предназначены для хранения данных.

Рассмотрим несколько примеров.

Создадим запись User с полями id, firstName, lastName, и email:

public record User(Long id, String firstName, String lastName, String email) {}  public class Main {     public static void main(String[] args) {         User user = new User(1L, "Artem", "Ivan", "artem@example.com");         System.out.println(user);     } }

Код создаст неизменяемый объект User и выведет его данные в консоль. Записи позволяют избавиться от шаблонного кода.

Записи поддерживают валидацию данных при создании объекта. Добавим валидацию цены в записи Product:

public record Product(String name, double price) {     public Product {         if (price < 0) {             throw new IllegalArgumentException("Price cannot be negative");         }     } }  public class Main {     public static void main(String[] args) {         Product product = new Product("Laptop", 999.99);         System.out.println(product);     } }

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

Записи также поддерживают добавление кастомных методов. Рассмотрим пример записи Rectangle с методом area:

public record Rectangle(double length, double width) {     public double area() {         return length * width;     } }  public class Main {     public static void main(String[] args) {         Rectangle rectangle = new Rectangle(5.0, 3.0);         System.out.println("Area: " + rectangle.area());     } }

Здесь метод area вычисляет площадь прямоугольника.

Записи могут реализовывать интерфейсы. Рассмотрим запись Coordinate, реализующую интерфейс Comparable:

public record Coordinate(double x, double y) implements Comparable<Coordinate> {     @Override     public int compareTo(Coordinate other) {         return Double.compare(this.x, other.x);     } }  public class Main {     public static void main(String[] args) {         Coordinate point1 = new Coordinate(3.0, 4.0);         Coordinate point2 = new Coordinate(2.0, 5.0);         System.out.println("Comparison result: " + point1.compareTo(point2));     } }

Записи можно использовать для создания объектов, которые могут быть сравнены на основе их данных.

Что в итоге?

  1. Записи хорошо подходят для объектов, которые должны быть неизменяемыми.

  2. Используем записи, чтобы сократить количество шаблонного кода и улучшить читаемость.

  3. Добавляем логику валидации в компактные конструкторы, чтобы гарантировать создание корректных объектов.

Лямбда-выражения

Для большинства лямбда – это совсем не новость, а уже ежедневная практика, но было бы странно не вписать ее в этот список. Лямбда-выражения были введены аж в Java 8 и представляют собой сокращенный способ написания анонимных функций. Они позволяют создавать небольшие фрагменты кода, которые могут быть переданы и выполнены позже.

Синтаксис лямбда-выражений следующий:

(parameters) -> expression

или

(parameters) -> { statements; }

Пример простого лямбда-выражения:

(int a, int b) -> a + b

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

Одним из наиболее частых применений лямбда-выражений является работа с коллекциями, особенно в сочетании с API потоков.

Фильтрация списка чисел, чтобы оставить только четные:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6); List<Integer> evenNumbers = numbers.stream()     .filter(n -> n % 2 == 0)     .collect(Collectors.toList());  System.out.println(evenNumbers); // [2, 4, 6]

Лямбда-выражения делают сортировку коллекций более лаконичной.

Сортировка списка строк по длине:

List<String> strings = Arrays.asList("short", "very long string", "medium"); strings.sort((s1, s2) -> Integer.compare(s1.length(), s2.length()));  System.out.println(strings); // [short, medium, very long string]

Лямбда-выражения отлично подходят для обработки событий в графических интерфейсах.

Обработка нажатия кнопки в JavaFX:

Button button = new Button("Click me"); button.setOnAction(event -> System.out.println("Button clicked!"));

До появления лямбда-выражений, для создания небольших анонимных функций использовались анонимные классы. Сравним два подхода.

Пример с анонимным классом:

Runnable runnable = new Runnable() {     @Override     public void run() {         System.out.println("Running in a thread");     } };  new Thread(runnable).start();

Пример с лямбда-выражением:

Runnable runnable = () -> System.out.println("Running in a thread"); new Thread(runnable).start();

Вот так, как видно из примеров, лямбды упростили написание кода.

Вар-аргументы

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

Объявление метода с вар-аргументами выглядит так:

public void methodName(Type... parameterName) {     // тело метода }

Здесь Type... указывает на тип аргументов, а parameterName — имя переменной, которая внутри метода будет доступна как массив.

Вар-аргумент должен быть последним параметром в методе.

Рассмотрим несколько примеров

Метод для суммирования чисел:

public static int sum(int... numbers) {     int sum = 0;     for (int number : numbers) {         sum += number;     }     return sum; }  public static void main(String[] args) {     System.out.println(sum(1, 2, 3)); // 6     System.out.println(sum(4, 5));    // 9     System.out.println(sum());        // 0 }

Метод sum принимает переменное количество целых чисел и возвращает их сумму. Можно передать любое количество аргументов, включая ноль.

Метод для создания строки из нескольких строк:

public static String concatenate(String... strings) {     StringBuilder result = new StringBuilder();     for (String str : strings) {         result.append(str);     }     return result.toString(); }  public static void main(String[] args) {     System.out.println(concatenate("Hello", " ", "world", "!")); // "Hello world!"     System.out.println(concatenate("Java", " ", "is", " ", "fun")); // "Java is fun" }

Метод concatenate принимает переменное количество строк и возвращает их объединение. Удобно, когда нужно собрать несколько строк в одну.

Метод для обработки ошибок:

public static void logErrors(String... errors) {     for (String error : errors) {         System.err.println("Error: " + error);     } }  public static void main(String[] args) {     logErrors("File not found", "Access denied", "Network error"); }

logErrors принимает переменное количество сообщений об ошибках и выводит их на стандартный поток ошибок.

Использование вар-аргументов оправдано в следующих случаях:

  1. Когда количество аргументов, передаваемых в метод, неизвестно заранее.

  2. Когда нужно уменьшить количество шаблонного кода.


Заключение

Вот и подошел к концу мой обзор крутых фич в Java. Надеюсь, вам было так же интересно читать, как мне — рассказывать об этих штуках. Пусть ваш код будет чистым, жизнь — лёгкой, а коллеги завидуют вашей крутости.

Больше фич коллеги из OTUS рассматривают в рамках курса Java Developer. Advanced. По ссылке ниже можете зарегистрироваться на бесплатный вебинар курса и оценить полезность курса самостоятельно.


ссылка на оригинал статьи https://habr.com/ru/articles/833462/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *