Pascal4eg / Java

 Java | Фишки и трюки

SOLID — принципы объектно‑ориентированного программирования

SOLID — это аббревиатура пяти основных принципов проектирования в объектно‑ориентированном программировании — Single responsibility, Open-closed, Liskov substitution, Interface segregation и Dependency inversion.

В переводе на русский: принципы единственной ответственности, открытости / закрытости, подстановки Барбары Лисков, разделения интерфейса и инверсии зависимостей.

Аббревиатура SOLID была предложена Робертом Мартином, автором нескольких книг, широко известным в сообществе разработчиков. Следование принципам позволяет строить на базе ООП масштабируемые и сопровождаемые программные продукты с понятной бизнес‑логикой. Код, который написан с соблюдением принципов SOLID, проще понимать, поддерживать, расширять или изменять его функциональность.

...

Читать дальше

Класс PrintStream

try {
    // Создание объекта PrintStream для вывода данных в консоль
    PrintStream printStream = System.out;

    // Использование методов print и println
    printStream.print("Hello, ");
    printStream.println("world!");

    // Использование метода printf
    printStream.printf("Formatted number: %d, Floating-point: %.2f%n", 42, 3.14159);

    // Создание объекта PrintStream для записи данных в файл
    PrintStream filePrintStream = new PrintStream(new FileOutputStream("output.txt"));

    // Вывод данных в файл
    filePrintStream.println("Data written to file.");
    filePrintStream.printf("File size: %d bytes", 1024);

    // Закрытие потока вывода в файл
    filePrintStream.close();
} catch (IOException e) {
    e.printStackTrace();
}

PrintStream является классом, предназначенным для удобного вывода различных типов данных в поток вывода. Он является подклассом OutputStream и предоставляет методы для вывода данных различных примитивных типов, строк и объектов в удобном для чтения текстовом формате.

...

Читать дальше

Проблема N+1 (N+1 Issue)

@Entity
public class Author {
    ...
    @OneToMany(mappedBy = "author")
    private List<Book> books;
}

@Entity
public class Book {
    ...
    @ManyToOne
    @JoinColumn(name = "author_id")
    private Author author;
}
...

List<Author> authors = entityManager.createQuery(
        "SELECT a FROM Author a", Author.class).getResultList();

for (Author author : authors){
    // Каждый вызов author.getBooks() приведет к дополнительному
    //запросу к базе данных
    List<Book> books = author.getBooks();
    // Дополнительная логика обработки
}

Проблема N+1 (N+1 Issue) в JPA (Java Persistence API) возникает, когда при получении списка сущностей с их связанными сущностями (например, при использовании отношения OneToMany или ManyToOne), для каждой основной сущности выполняется дополнительный запрос для загрузки связанной сущности. Это приводит к выполнению N+1 запросов к базе данных, где N - количество основных сущностей.

...

Читать дальше

JPA Entity Graph

@NamedEntityGraph(
        name = "person-with-address",
        attributeNodes = {
                @NamedAttributeNode("name"),
                @NamedAttributeNode(value = "address", subgraph = "address-subgraph")
        },
        subgraphs = {
                @NamedSubgraph(name = "address-subgraph", attributeNodes = {
                        @NamedAttributeNode("city")
                })
        }
)
@Entity
public class Person {
    private String name;
    @ManyToOne
    private Address address;
}

@Entity
public class Address {
    private String city;
}
...

EntityGraph<Person> entityGraph = entityManager.getEntityGraph("person-with-address");
Map<String, Object> properties = new HashMap<>();
properties.put("jakarta.persistence.fetchgraph", entityGraph);
Person person = entityManager.find(Person.class, 1L, properties);

JPA Entity Graph - это механизм, предоставляемый JPA, который позволяет явно указывать, какие атрибуты сущности должны быть загружены или проигнорированы во время выполнения запросов к базе данных. Это может быть полезно для управления жадной загрузкой (eager loading) и ленивой загрузкой (lazy loading) связанных сущностей.

...

Читать дальше

Параметр fetch

@Entity
@Table(name="post")
class Post {
    @Column(name="id")
    public Integer id;

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    public List<Comment> comments;
}

Параметр fetch в аннотациях @ManyToOne, @ManyToMany, @OneToOne, @OneToMany определяет как будет загружаться связанная сущность: вместе с загрузкой родительской сущности или в момент обращения к аннотированному полю.

...

Читать дальше

Память кучи

В Java память кучи (heap memory) является областью памяти, где хранятся объекты и массивы. Куча управляется сборщиком мусора (garbage collector), который автоматически освобождает память, занятую объектами, которые больше не используются.

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

...

Читать дальше

DataInputStream и DataOutputStream

try {
    // Запись данных в файл с использованием DataOutputStream
    DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));
    dos.writeInt(42);
    dos.writeDouble(3.14);
    dos.writeUTF("Привет, мир!");
    dos.close();

    // Чтение данных из файла с использованием DataInputStream
    DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));
    int intValue = dis.readInt();
    double doubleValue = dis.readDouble();
    String stringValue = dis.readUTF();
    System.out.println("int: " + intValue); // int: 42
    System.out.println("double: " + doubleValue); // double: 3.14
    System.out.println("string: " + stringValue); // string: Привет, мир!
    dis.close();
} catch (IOException e) {
    e.printStackTrace();
}

DataInputStream и DataOutputStream предоставляют методы для чтения и записи примитивных данных из и в поток ввода/вывода. Эти классы добавляют функциональность к обычным потокам ввода/вывода, позволяя удобно считывать и записывать данные различных типов, таких как целые числа, числа с плавающей запятой, символы и т.д., без необходимости вручную преобразовывать их в байты.

Читать дальше

Стековая память

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

Стековая память в Java используется для распределения статической памяти и выполнения потока - каждый поток исполнения в Java имеет свой собственный стек, создаваемый вместе с потоком. Этот стек содержит кадры стека, каждый из которых представляет вызов метода. Каждый кадр содержит примитивные значения, специфичные для метода (переданные в метод и объявленные в нем), и ссылки на объекты, находящиеся в куче.

...

Читать дальше

Класс Console

import java.io.Console;

public class Con {
    private static final String PASSWORD = "123";

    public static void main(String[] args) {
        Console console = System.console();
        String name = console.readLine("Enter your name: ");
        char[] pass = console.readPassword("Enter password: ");
        if (PASSWORD.equals(new String(pass))) {
            console.printf("Welcome, %s", name);
        } else {
            console.printf("access denied");
        }
    }
}

В JDK 6 и более поздних версиях мы можем использовать класс Console из пакета java.io для чтения и записи в консоль.

Если нам нужно прочитать конфиденциальную информацию, например пароль, мы можем использовать метод readPassword(), чтобы запросить у пользователя пароль и прочитать пароль из консоли с отключенным эхом.

Читать дальше

Функциональное программирование (ФП)

Функциональное программирование (ФП) - это парадигма программирования, которая базируется на работе с функциями как основными строительными блоками программ. В ФП данные рассматриваются как неизменяемые и функции рассматриваются как математические функции, которые принимают входные данные и возвращают результат без видимых побочных эффектов. Вот основные концепции функционального программирования:

...

Читать дальше