Java | Вопросы собесов
11.5K subscribers
31 photos
1 video
1.04K links
Download Telegram
🤔 Что знаешь про модели памяти в Java?

Модель памяти Java (Java Memory Model, JMM) определяет, как взаимодействуют потоки через память и как изменения, сделанные одним потоком, становятся видимыми для других потоков. Модель памяти Java является фундаментальной частью многопоточной среды в Java, обеспечивающей корректность и предсказуемость поведения многопоточных программ.

🚩Основные аспекты

🟠Взаимодействие потоков и памяти:

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

🟠Чтение и запись переменных
Когда поток читает переменную, он может читать ее из своей локальной копии или из основной памяти. Когда поток записывает переменную, он может записывать ее в свою локальную копию или непосредственно в основную память.

🚩Гарантии JMM

🟠Последовательная согласованность (Sequential Consistency)
Последовательная согласованность гарантирует, что действия всех потоков будут выполняться в том порядке, в котором они были написаны в коде, если нет явных указаний на обратное.

🟠Видимость (Visibility)
Видимость означает, что изменения, сделанные одним потоком, становятся видимыми для других потоков. В JMM видимость изменений обеспечивается с помощью синхронизации.

🟠Произвольный порядок выполнения (Out-of-Order Execution)
JMM допускает оптимизации, такие как переупорядочивание инструкций, чтобы улучшить производительность, но гарантирует, что видимость и порядок выполнения будут сохраняться, как описано в спецификации.

public class VisibilityExample {
private static boolean flag = false;
private static int counter = 0;

public static void main(String[] args) throws InterruptedException {
Thread writer = new Thread(() -> {
counter = 42;
flag = true;
});

Thread reader = new Thread(() -> {
while (!flag) {
// Ждем пока флаг не станет true
}
System.out.println("Counter: " + counter);
});

writer.start();
reader.start();

writer.join();
reader.join();
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1💊1
🤔 Какие шаблоны проектирования знаешь?

1. Порождающие: Singleton, Factory, Builder, Prototype.
2. Структурные: Adapter, Decorator, Composite, Proxy.
3. Поведенческие: Observer, Strategy, Command, State, Chain of Responsibility.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7👍3
🤔 Что такое as-if-serial semantics?

As-If-Serial Semantics – это принцип оптимизации компилятором, при котором код может перестраиваться, но результат его выполнения остаётся таким же, как если бы инструкции выполнялись строго по порядку.

Обычный код
int a = 10;
int b = 20;
int c = a + b;
System.out.println(c);


Что может сделать компилятор?
int c = 30;
System.out.println(c);


🚩Что можно менять? (Безопасные оптимизации)

Менять порядок инструкций, если это не влияет на результат.
Удалять лишние переменные и вычисления.
Заменять выражения константами (10 + 20 → 30).
int x = 5;
int y = 10;
x = x + 1; // x = 6
System.out.println(y);


Компилятор может поменять местами y и x
int y = 10;
int x = 6;
System.out.println(y);


🚩Что нельзя менять? (Гарантированный порядок исполнения)

int x = 10;
int y = x + 5;
x = 20;
System.out.println(y);


Если поменять порядок
x = 20;
int y = x + 5; // Неверно! y теперь 25, а должно быть 15


🚩Как `As-If-Serial` влияет на многопоточность?

В многопоточной среде компилятор может менять порядок команд внутри одного потока, но он не знает о другом потоке!
Опасный пример без volatile
boolean ready = false;
int data = 0;

void writer() {
data = 42;
ready = true;
}

void reader() {
if (ready) {
System.out.println(data); // Может напечатать 0 из-за перестановки!
}
}


Решение – volatile для ready
volatile boolean ready = false;


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
🤔 Где используется аннотация Bean?

Аннотация
@Bean используется для явного определения бина в методах класса конфигурации (@Configuration), обычно для сторонних библиотек или ручной настройки зависимостей.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
🤔 Какая сложность поиска метода по ключу в коллекции TreMap?

В TreeMap поиск элемента по ключу выполняется за O(log n).

🚩Почему сложность `O(log n)`?

TreeMap основан на красно-чёрном дереве (Red-Black Tree).
Красно-чёрное дерево – это самобалансирующееся бинарное дерево.
В худшем случае, глубина дерева ≈ log₂(n), поэтому:
Поиск (get(key)) выполняется за O(log n).
Вставка (put(key, value)) тоже O(log n), так как требует балансировки.
import java.util.TreeMap;

public class TreeMapExample {
public static void main(String[] args) {
TreeMap<Integer, String> treeMap = new TreeMap<>();
treeMap.put(10, "Ten");
treeMap.put(20, "Twenty");
treeMap.put(30, "Thirty");

System.out.println(treeMap.get(20)); // Поиск за O(log n)
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
🤔 Для чего нужен BiConsumer<T, U>?

Принимает два аргумента и ничего не возвращает. Используется для операций, основанных на двух параметрах, например, при работе с Map.forEach.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥1
🤔 Какие шаги нужно выполнить для прочтения текстового файла?

Для прочтения текстового файла в Java нужно выполнить несколько шагов.

1⃣Выбор метода чтения файла
В Java есть несколько способов читать текстовые файлы:
1. Использование класса FileReader.
2. Использование BufferedReader для построчного чтения.
3. Использование java.nio.file.Files для чтения всех строк файла.
4. Применение Scanner для гибкого чтения данных.

2⃣Открытие файла
Нужно указать путь к файлу (абсолютный или относительный) и передать его в выбранный класс. Например:
FileReader reader = new FileReader("file.txt");


3⃣Чтение данных
Выберите подходящий метод для обработки содержимого файла:
- Построчное чтение.
- Чтение символов.
- Чтение всех строк сразу (например, через Files.readAllLines).

4⃣Закрытие ресурса
Для освобождения системных ресурсов после работы с файлом нужно закрыть поток. Это делается вручную или с помощью конструкции try-with-resources.

🚩Примеры реализации

Построчное чтение с BufferedReader
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class FileReadExample {
public static void main(String[] args) {
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line); // Вывод строки
}
} catch (IOException e) {
System.out.println("Ошибка: " + e.getMessage());
}
}
}


Чтение файла с помощью Files
import java.nio.file.Files;
import java.nio.file.Paths;
import java.io.IOException;
import java.util.List;

public class FileReadExample {
public static void main(String[] args) {
try {
List<String> lines = Files.readAllLines(Paths.get("file.txt"));
for (String line : lines) {
System.out.println(line);
}
} catch (IOException e) {
System.out.println("Ошибка: " + e.getMessage());
}
}
}


Чтение через Scanner
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class FileReadExample {
public static void main(String[] args) {
try (Scanner scanner = new Scanner(new File("file.txt"))) {
while (scanner.hasNextLine()) {
System.out.println(scanner.nextLine()); // Построчное чтение
}
} catch (FileNotFoundException e) {
System.out.println("Файл не найден: " + e.getMessage());
}
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
🤔 Как разрешаются проблемы дефицита памяти и исключения OutOfMemoryError?

OutOfMemoryError возникает, когда JVM не может выделить память. Причины и решения:
- Утечка памяти — объекты остаются в памяти без необходимости → использовать профилировщики.
- Неправильные настройки Heap → увеличить размер -Xmx, -Xms.
- Плохая логика (бесконечные коллекции, рекурсия) → анализ и оптимизация кода.
- Неосвобождённые ресурсы → использовать try-with-resources.
Важно отлаживать утечки и оптимизировать структуру данных.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
🤔 Массив — статическая структура данных или динамическая?

🟠Почему массив – статическая структура?
Фиксированный размер – при создании массива его длина задаётся раз и навсегда.
Нельзя изменить размер – нельзя добавить или удалить элементы после создания массива.
int[] numbers = new int[5]; // Размер 5, изменить нельзя!


🟠Что делать, если нужен динамический массив?
В Java есть динамические структуры данных, например ArrayList.
import java.util.ArrayList;
import java.util.List;

public class DynamicArrayExample {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();

list.add(1);
list.add(2);
list.add(3);

System.out.println(list); // [1, 2, 3]
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
🤔 Что такое связка try-catch-finally?

Это конструкция для обработки исключений:
- try — блок кода, где может произойти ошибка.
- catch — перехватывает и обрабатывает исключение.
- finally — выполняется всегда, независимо от того, было ли исключение.
finally используется для освобождения ресурсов, закрытия файлов, соединений и т.д.

Особенности класса String?
- Неизменяемый (immutable) — нельзя изменить строку после создания.
- Хранится в String Pool при использовании литералов.
- Имеет переопределённые equals и hashCode, что делает его удобным для коллекций.
- Часто используется и оптимизирован под производительность.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
🤔 Что должно быть если объект equals нал?

Метод equals() в Java предназначен для проверки равенства двух объектов. Если объект, переданный в метод equals(), равен null, метод должен возвращать `false`, так как объект не может быть равен null по определению. Рассмотрим этот случай более подробно.

🚩Почему важно обрабатывать `null` в `equals()`?

🟠Контракт метода `equals()`
Согласно спецификации Java, метод equals() должен возвращать false, если объект, переданный в метод, равен null. Это необходимо для корректного сравнения объектов.
Симметричность: Если a.equals(b) возвращает true, то b.equals(a) также должно возвращать true.
Для null: Вызов x.equals(null) всегда должен возвращать false.

🟠Предотвращение `NullPointerException`
Если метод equals() не проверяет, является ли объект null, попытка доступа к его полям или методам вызовет NullPointerException.

🚩Как правильно реализовать метод `equals()`?

Вот стандартный способ реализации метода equals()
@Override
public boolean equals(Object obj) {
// Проверяем, равен ли объект null
if (obj == null) {
return false;
}

// Проверяем, является ли объект тем же самым
if (this == obj) {
return true;
}

// Проверяем, принадлежит ли объект тому же классу
if (getClass() != obj.getClass()) {
return false;
}

// Приводим объект к текущему типу
MyClass other = (MyClass) obj;

// Сравниваем необходимые поля
return this.field.equals(other.field);
}


🚩Что происходит, если игнорировать проверку `null`?

Если вы не проверяете null, код вроде следующего приведет к ошибке
MyClass obj1 = new MyClass("Hello");
MyClass obj2 = null;

System.out.println(obj1.equals(obj2)); // Если нет проверки null -> NullPointerException


Пример с проверкой null
class MyClass {
private String value;

public MyClass(String value) {
this.value = value;
}

@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (this == obj) {
return true;
}
if (getClass() != obj.getClass()) {
return false;
}
MyClass other = (MyClass) obj;
return value.equals(other.value);
}
}

public class Main {
public static void main(String[] args) {
MyClass obj1 = new MyClass("Hello");
MyClass obj2 = null;

System.out.println(obj1.equals(obj2)); // false
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🤔1
🤔 В чём разница между наследованием и полиморфизмом?

Наследование — это механизм переиспользования кода через иерархию классов.
Полиморфизм — это способность обрабатывать объекты через общий интерфейс, независимо от их конкретного типа.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
🤔 Роль `serialVersionUID` в сериализации

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

🚩Почему `serialVersionUID` важен?

🟠Гарантия совместимости при десериализации
Когда объект сериализуется (превращается в поток байтов), вместе с ним сохраняется и serialVersionUID. При десериализации JVM сравнивает serialVersionUID сохранённого объекта с serialVersionUID текущего класса. Если они не совпадают, выбрасывается исключение InvalidClassException, так как структура класса могла измениться.

🟠Предотвращение ошибок при изменениях класса
Если класс изменяется (например, добавляется новое поле), но serialVersionUID остаётся неизменным, JVM считает, что класс всё ещё совместим с более старой версией, и десериализация проходит успешно.

🟠Явное управление версиями
Если serialVersionUID не указан явно, JVM генерирует его автоматически на основе структуры класса. Это может привести к неожиданным проблемам, если класс изменится, так как автоматически вычисленный serialVersionUID изменится.

🚩Как использовать `serialVersionUID`?

import java.io.*;

class Person implements Serializable {
private static final long serialVersionUID = 1L; // Версия класса
private String name;
private int age;

public Person(String name, int age) {
this.name = name;
this.age = age;
}

@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + "}";
}
}


🚩Что будет, если не указать `serialVersionUID`?

Если не определить serialVersionUID, JVM сгенерирует его автоматически. Однако:
Он будет зависеть от структуры класса.
Малейшее изменение в коде (даже порядок методов) изменит serialVersionUID.
Это может привести к InvalidClassException при десериализации.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
🤔 Зачем нужен Hibernate?

Hibernate — это ORM-фреймворк, который:
- связывает объекты Java с таблицами БД;
- управляет транзакциями, кэшированием и связями между сущностями;
- предоставляет HQL (Hibernate Query Language) и Criteria API;
- упрощает доступ к данным и избавляет от ручного написания SQL.
Hibernate реализует спецификацию JPA и часто используется в связке с Spring Data.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
🤔 Какие шаги нужно выполнить для прочтения текстового файла?

Для прочтения текстового файла в Java нужно выполнить несколько шагов.

1⃣Выбор метода чтения файла
В Java есть несколько способов читать текстовые файлы:
1. Использование класса FileReader.
2. Использование BufferedReader для построчного чтения.
3. Использование java.nio.file.Files для чтения всех строк файла.
4. Применение Scanner для гибкого чтения данных.

2⃣Открытие файла
Нужно указать путь к файлу (абсолютный или относительный) и передать его в выбранный класс. Например:
FileReader reader = new FileReader("file.txt");


3⃣Чтение данных
Выберите подходящий метод для обработки содержимого файла:
- Построчное чтение.
- Чтение символов.
- Чтение всех строк сразу (например, через Files.readAllLines).

4⃣Закрытие ресурса
Для освобождения системных ресурсов после работы с файлом нужно закрыть поток. Это делается вручную или с помощью конструкции try-with-resources.

🚩Примеры реализации

Построчное чтение с BufferedReader
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class FileReadExample {
public static void main(String[] args) {
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line); // Вывод строки
}
} catch (IOException e) {
System.out.println("Ошибка: " + e.getMessage());
}
}
}


Чтение файла с помощью Files
import java.nio.file.Files;
import java.nio.file.Paths;
import java.io.IOException;
import java.util.List;

public class FileReadExample {
public static void main(String[] args) {
try {
List<String> lines = Files.readAllLines(Paths.get("file.txt"));
for (String line : lines) {
System.out.println(line);
}
} catch (IOException e) {
System.out.println("Ошибка: " + e.getMessage());
}
}
}


Чтение через Scanner
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class FileReadExample {
public static void main(String[] args) {
try (Scanner scanner = new Scanner(new File("file.txt"))) {
while (scanner.hasNextLine()) {
System.out.println(scanner.nextLine()); // Построчное чтение
}
} catch (FileNotFoundException e) {
System.out.println("Файл не найден: " + e.getMessage());
}
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
🤔 Назови основные классы потоков ввода/вывода.

- Байтовые потоки: FileInputStream, FileOutputStream, BufferedInputStream, BufferedOutputStream, DataInputStream, DataOutputStream;
- Символьные потоки: FileReader, FileWriter, BufferedReader, BufferedWriter, PrintWriter.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3👍1
🤔 Обеспечит ли Stream API RandomAcess?

Нет, Stream API не поддерживает RandomAccess, потому что он работает с потоком данных, а не с индексированными структурами.

🚩Почему Stream API не поддерживает `RandomAccess`?

🟠Stream – это поток данных
который не обязательно хранится в памяти в виде структуры, поддерживающей случайный доступ.
🟠Нет индексов
в отличие от List, Stream не позволяет получить элемент по индексу (get(index) отсутствует).
🟠Обход последовательный
элементы проходятся один за другим, что делает случайный доступ невозможным.

ListRandomAccess)
List<Integer> list = new ArrayList<>(List.of(1, 2, 3, 4, 5));
System.out.println(list.get(2)); // Быстрое получение элемента по индексу


Stream (без RandomAccess)
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
stream.skip(2).findFirst().ifPresent(System.out::println); // Ищем 3-й элемент


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
🤔 Как у класса заполнить атрибуты?

Атрибуты класса (поля) можно заполнить:
- через конструктор;
- через сеттеры;
- через аннотации Spring (
@Autowired, @Value);
- через внедрение зависимостей или маппинг объектов.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
🤔 Чем полезны неизменяемые (Immutable) объекты в Java?

Неизменяемые (immutable) объекты не могут быть изменены после создания.
Если нужно изменить данные – создаётся новый объект.

🚩Почему неизменяемые объекты полезны?

🟠Потокобезопасность (Thread Safety)
Неизменяемые объекты можно безопасно использовать в многопоточной среде – их не нужно синхронизировать.
String message = "Hello";
String newMessage = message.replace("H", "J");

System.out.println(message); // Hello
System.out.println(newMessage); // Jello


🟠Отсутствие неожиданных изменений (безопасность данных)
Если объект неизменяемый, его нельзя случайно изменить.
class BankAccount {
private final String accountNumber;

public BankAccount(String accountNumber) {
this.accountNumber = accountNumber;
}

public String getAccountNumber() {
return accountNumber;
}
}


🟠Упрощает отладку и поддержку кода
Изменяемые объекты могут менять состояние в неожиданный момент.
List<String> list = new ArrayList<>();
list.add("Java");

modifyList(list); // Метод может изменить список!

System.out.println(list); // Ожидаем ["Java"], но может быть что угодно!


🟠Можно использовать в качестве ключей в `HashMap` и `HashSet`
Хешкод неизменяемого объекта не изменится, а значит, он корректно работает в HashMap.
Map<String, String> map = new HashMap<>();
map.put("key", "value");

System.out.println(map.get("key")); // Всегда "value", так как String неизменяемый


🟠Совместимость с кэшем (например, в Hibernate, Spring)
Неизменяемые объекты можно безопасно кешировать, так как они не меняются.

🚩Как создать неизменяемый класс?

Все поля private final.
Нет сеттеров.
Если есть массивы или списки – копируем их перед возвратом.
final class Person {
private final String name;
private final int age;

public Person(String name, int age) {
this.name = name;
this.age = age;
}

public String getName() {
return name;
}

public int getAge() {
return age;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
🤔 Как из одного сервлета вызвать другой сервлет?

1. С помощью объекта RequestDispatcher, вызвав его методы forward() или include().
2. Через отправку запроса с использованием sendRedirect() для внешнего перенаправления.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6
🤔 Что такое Appender в log4j?

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

🚩Зачем нужен Appender?

Appender позволяет гибко управлять тем, куда и как сохраняются логи. В зависимости от требований приложения, вы можете:
Писать логи в файл.
Выводить их в консоль.
Отправлять их в удалённые хранилища или базы данных.

🚩Основные виды Appender в Log4j

🟠ConsoleAppender
Логи выводятся в консоль.
Полезно для разработки и отладки.

     <Appender type="Console" name="ConsoleAppender">
<Target>System.out</Target>
</Appender>


🟠FileAppender
Логи записываются в файл.
Используется для длительного хранения логов.

     <Appender type="File" name="FileAppender">
<FileName>logs/app.log</FileName>
<Append>true</Append>
</Appender>


🟠RollingFileAppender
Расширение FileAppender с возможностью ротации логов (ограничение размера файла, создание новых файлов при переполнении).

     <Appender type="RollingFile" name="RollingFileAppender">
<FileName>logs/app.log</FileName>
<FilePattern>logs/app-%d{yyyy-MM-dd}.log</FilePattern>
<Policies>
<SizeBasedTriggeringPolicy size="10MB"/>
</Policies>
</Appender>


🟠DailyRollingFileAppender
Логи записываются в файл, который ротационно создаётся каждый день.

     <Appender type="DailyRollingFile" name="DailyRollingAppender">
<FileName>logs/app.log</FileName>
<DatePattern>.yyyy-MM-dd</DatePattern>
</Appender>


🟠SocketAppender
Отправляет логи через сеть (TCP или UDP).
Используется для централизованного логирования.

🟠JDBCAppender
Записывает логи в базу данных.

     <Appender type="JDBC" name="JDBCAppender">
<ConnectionSource>
<DriverManagerConnectionSource>
<DriverClass>org.h2.Driver</DriverClass>
<Url>jdbc:h2:mem:logdb</Url>
<User>sa</User>
</DriverManagerConnectionSource>
</ConnectionSource>
<TableName>log_table</TableName>
</Appender>


🚩Конфигурация Appender в log4j2

Вот пример конфигурации с использованием нескольких Appender
XML-конфигурация
<Configuration>
<Appenders>
<Console name="ConsoleAppender" target="SYSTEM_OUT">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level: %msg%n"/>
</Console>
<File name="FileAppender" fileName="logs/app.log">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level: %msg%n"/>
</File>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="ConsoleAppender"/>
<AppenderRef ref="FileAppender"/>
</Root>
</Loggers>
</Configuration>


Java-конфигурация
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Main {
private static final Logger logger = LogManager.getLogger(Main.class);

public static void main(String[] args) {
logger.info("This is an info log");
logger.error("This is an error log");
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5