nullВозвращение пустых коллекций вместо
null-это рекомендуемый подход для методов, возвращающих коллекции. Он упрощает обработку данных, предотвращает ошибки и делает код более предсказуемым.1. Улучшение читаемости: Код становится проще, так как не нужно проверять результат на null.
2. Предотвращение NullPointerException: Исключается вероятность ошибок, связанных с доступом к null.
3.Соответствие принципу наименьшего удивления: Методы всегда возвращают коллекцию, даже если она пуста.
4. Эффективность: Пустые коллекции создаются один раз и переиспользуются благодаря реализации через паттерн Singleton.
5. Совместимость с функциональным программированием: Пустые коллекции легко интегрируются в стримы и другие функциональные конструкции.
Пример:
public class CacheService {
private final Map<String, List<Object>> cache = new ConcurrentHashMap<>();
public List<Object> getCachedValues(String key) {
return cache.getOrDefault(key, Collections.emptyList());
}
public void addToCache(String key, Object value) {
cache.computeIfAbsent(key, k -> new ArrayList<>()).add(value);
}
}
Использование пустых коллекций вместо null делает код более устойчивым и предсказуемым. Это особенно важно в сложных многопоточных приложениях или системах с большим количеством взаимосвязанных компонентов.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13❤3
Varargs (Variable Arguments List, изменяющийся список аргументов) — это способ создания методов, которые могут принимать произвольное количество аргументов одного типа (от нуля и более). Данная возможность появилась в JDK 5.
Запись вида
При этом три точки после типа указывают, что метод в качестве аргумента может принимать как массив, так и любую последовательность аргументов, записанных через запятую, которая все равно преобразуется в одномерный массив - «под капотом» компилятор на уровне байт-кода неявно заменяет переданную последовательность массивом. Уже в методе аргумент varargs используется как одномерный массив.
Альтернативой varargs является перегрузка методов или передача в метод массива значений.
Varargs был создан с целью упрощения работы программиста, удобства и краткости кода.
📌 В качестве ограничения любой метод может использовать varargs только в единственном числе и строго последним аргументом.
Запись вида
Object... args и есть varargs. При этом три точки после типа указывают, что метод в качестве аргумента может принимать как массив, так и любую последовательность аргументов, записанных через запятую, которая все равно преобразуется в одномерный массив - «под капотом» компилятор на уровне байт-кода неявно заменяет переданную последовательность массивом. Уже в методе аргумент varargs используется как одномерный массив.
Альтернативой varargs является перегрузка методов или передача в метод массива значений.
Varargs был создан с целью упрощения работы программиста, удобства и краткости кода.
📌 В качестве ограничения любой метод может использовать varargs только в единственном числе и строго последним аргументом.
🔥8👍5
null? null не имеет хеш-кода, потому что null не является объектом. Однако, при использовании null в структурах данных, таких как HashMap или HashSet, применяется специальная логика:null в HashMap и HashSet?✔️ В
HashMap ключ null всегда попадает в первый бакет (bucket 0).✔️ В
HashSet (который использует HashMap внутри) null также хранится в этом же бакете.✔️ Проверки выполняются в
Objects.hashCode(), который для null всегда возвращает 0.
System.out.println(Objects.hashCode(null)); // 0
📌 Вывод:
null не имеет собственного хеш-кода, но в хеш-структурах ему назначается 0.Please open Telegram to view this post
VIEW IN TELEGRAM
👍17🔥2❤1
<>) упрощает работу с обобщениями (Generics), позволяя компилятору автоматически выводить тип.<>):
List<String> list = new ArrayList<String>(); // Приходилось дублировать <String>
<>):
List<String> list = new ArrayList<>(); // Компилятор сам выводит <String>
Преимущества
<>:✅ Уменьшает дублирование кода
✅ Улучшает читаемость
✅ Работает с любыми обобщёнными классами
⚡ Итог: Diamond-оператор делает код чище и проще, автоматизируя вывод типов!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14❤1🔥1👀1
List<String > planets = new ArrayList<>() {{
add ("Mercury");
add ("Venus");
add ("Earth");
add ("Mars");
add ("Jupiter");
add ("Saturn");
add ("Uranus") ;
add ("Neptune");
}};
1. Краткость
2. Читаемость
3. Удобство для небольших коллекций
1. Создание анонимного класса (увеличение потребления памяти)
2. Скрытая ссылка (возможные утечки памяти)
3. Ограничения с final классами
4. Несовместимость с оператором diamond
5. Потенциальное влияние на производительность
6. Считается антипаттерном
1.
List<String> planets = Stream.of("Mercury", "Venus", "Earth")
.collect(Collectors.toList());
2.
List<String> planets = List.of("Mercury", "Venus", "Earth");3.🖨Конструктор копирования:
List<Integer> list = Collections.unmodifiableList(new ArrayList<>(Arrays.asList(2, 3, 5)));
Несмотря на удобство, double-brace инициализация считается антипаттерном из-за проблем с производительностью и возможных утечек памяти.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15🔥1🌭1
Перегрузка методов (Method Overloading) – это создание нескольких методов с одним именем, но разными параметрами (различаются количество или типы аргументов).
Пример:
class MathUtils {
int sum(int a, int b) {
return a + b;
}
double sum(double a, double b) { // Перегруженный метод
return a + b;
}
}
Переопределение методов (Method Overriding) – это изменение поведения унаследованного метода в подклассе.
Пример:
class Animal {
void sound() {
System.out.println("Some sound");
}
}
class Dog extends Animal {
@Override
void sound() { // Переопределение метода
System.out.println("Bark");
}
}
⚡ Вывод:
✔️Перегрузка – это создание нескольких версий метода в одном классе.
✔️Переопределение – это изменение поведения метода родителя в подклассе.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14❤1🔥1
Array vs ArrayListВыбор между
Array и ArrayList зависит от специфики задачи, которую требуется решить. 📌Помните о следующих особенностях этих типов:
✔️
Array имеет фиксированный размер и память для него выделяется в момент объявления, а размер ArrayLists может динамически изменяться.✔️ Массивы работают гораздо быстрее, а в
ArrayList намного проще добавлять/удалять элементы.✔️ При работе с
Array велика вероятность получить ошибку ArrayIndexOutOfBoundsException.
✔️ У
ArrayList только одно измерение, а вот массивы могут быть многомерными.
import java.util.ArrayList;
public class arrayVsArrayList {
public static void main(String[] args) {
// объявление Array
int[] myArray = new int[6];
// обращение к несуществующему индексу
myArray[7]= 10; // ArrayIndexOutOfBoundsException
// объявление ArrayList
ArrayList<Integer> myArrayList = new ArrayList<>();
// простое добавление и удаление элементов
myArrayList.add(1);
myArrayList.add(2);
myArrayList.add(3);
myArrayList.add(4);
myArrayList.add(5);
myArrayList.remove(0);
// получение элементов ArrayList
for(int i = 0; i < myArrayList.size(); i++) {
System.out.println("Element: " + myArrayList.get(i));
}
// многомерный Array
int[][][] multiArray = new int [3][3][3];
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14❤1👎1
ArrayList vs LinkedListОба класса реализуют
List, но имеют разные внутренние структуры и производительность.ArrayList использует динамический массив, а LinkedList использует двусвязный список.✔️ Используйте
ArrayList, если важен быстрый доступ по индексу и добавление в конец.✔️ Используйте
LinkedList, если часто удаляете/вставляете элементы в середину.📌
ArrayList чаще предпочтительнее, так как LinkedList требует больше памяти и редко даёт преимущества. 🚀Please open Telegram to view this post
VIEW IN TELEGRAM
❤10🔥3👍2🤔2
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import java.io.IOException;
public class PDFCreationExample {
public static void main(String[] args) throws IOException {
try (PDDocument document = new PDDocument()) {
PDPage page = new PDPage();
document.addPage(page);
try (PDPageContentStream contentStream = new PDPageContentStream(document, page)) {
// Добавляем заголовок
contentStream.beginText();
contentStream.setFont(PDType1Font.HELVETICA_BOLD, 16);
contentStream.newLineAtOffset(50, 750);
contentStream.showText("Отчет о продажах");
contentStream.endText();
// Добавляем таблицу
drawTable(contentStream, 50, 700, new String[][] {
{"Продукт", "Количество", "Цена"},
{"Яблоки", "100", "50"},
{"Бананы", "150", "40"},
{"Апельсины", "75", "60"}
});
// Добавляем изображение
PDImageXObject image = PDImageXObject.createFromFile("path/to/image.jpg", document);
contentStream.drawImage(image, 50, 500, 200, 150);
}
document.save("Отчет_о_продажах.pdf");
}
}
private static void drawTable(PDPageContentStream contentStream, float x, float y, String[][] content) throws IOException {
// Метод для рисования таблицы (код опущен для краткости)
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍10❤3🌚1
HashMap?HashMap – одна из самых эффективных структур, но её можно ещё ускорить.HashMap увеличивается при заполнении на 75%, что может приводить к перераспределению. Укажите new HashMap<>(1000) для больших данных.computeIfAbsent() – сокращает проверку наличия ключа перед вставкой.synchronized HashMap – вместо этого применяйте ConcurrentHashMap.Map<String, Integer> map = new HashMap<>(1000);
map.computeIfAbsent("key", k -> 42);
HashMap под свои задачи, особенно если храните большие объёмы данных.#java #hashmap #performance
Please open Telegram to view this post
VIEW IN TELEGRAM
👍19❤1
import javassist.*;
public class LoggingExample {
public static void main(String[] args) throws Exception {
// Получаем пул классов
ClassPool pool = ClassPool.getDefault();
// Получаем класс, который хотим модифицировать
CtClass ctClass = pool.get("com.example.MyClass");
// Получаем все методы класса
CtMethod[] methods = ctClass.getDeclaredMethods();
for (CtMethod method : methods) {
// Добавляем логирование в начало каждого метода
method.insertBefore("System.out.println(\"Вызван метод: " + method.getName() + "\");");
// Добавляем логирование в конец каждого метода
method.insertAfter("System.out.println(\"Метод " + method.getName() + " завершен\");");
}
// Заменяем оригинальный класс модифицированным
ctClass.toClass();
// Теперь при использовании MyClass все его методы будут логироваться
// Например:
// MyClass obj = new MyClass();
// obj.someMethod();
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14❤1
IntegerВ Java тип
int (и его обёртка Integer) имеют фиксированный размер 32 бита. Если происходит переполнение (overflow), Java не выбрасывает ошибку, а просто "заворачивает" число.
public class OverflowTest {
public static void main(String[] args) {
int max = Integer.MAX_VALUE; // 2147483647
int result = max * 2; // Переполнение!
System.out.println("Max: " + max); // Max: 2147483647
System.out.println("Result: " + result); // Result: -2
}
}
Почему? Потому что переполнение не вызывает ошибку — результат выходит за границу
int и сбрасывается.Math.multiplyExact():
public class SafeMultiply {
public static void main(String[] args) {
try {
int safeResult = Math.multiplyExact(Integer.MAX_VALUE, 2);
System.out.println(safeResult);
} catch (ArithmeticException e) {
System.out.println("Переполнение!");
}
}
}
Теперь при переполнении выбросится
ArithmeticException.Please open Telegram to view this post
VIEW IN TELEGRAM
❤9👍3❤🔥1
Позволяют писать код более кратко и читаемо, особенно при работе с функциональными интерфейсами.
🖌Lambda-выражения — это анонимные функции, которые могут принимать аргументы и возвращать значения. Они похожи на методы, но не имеют имени и могут быть определены прямо в теле метода. Это позволяет упростить код, удалив ненужную обертку.
// Без Lambda
File directory = new File("./src/main/java");
String[] list = directory.list(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".java");
}
});
// С Lambda
File directory = new File("./src/main/java");
String[] list = directory.list((dir, name) -> name.endsWith(".java"));
1.
2.
3.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3❤2
💻 AssertJ — это библиотека для написания fluent-assertions в тестах, которая предоставляет удобный и читаемый синтаксис для проверок. Основные возможности:
1.
2.
3.
4.
// Проверки строк
assertThat("Hello Java")
.startsWith("Hello")
.endsWith("Java")
.hasSize(10)
.contains(" ");
// Проверки коллекций
assertThat(userList)
.hasSize(3)
.extracting(User::getName)
.containsExactly("Alice", "Bob", "Charlie");
// Проверки исключений
assertThatThrownBy(() -> service.process(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Parameter cannot be null");
1.
assertThat(localDate)
.isAfter("2023-01-01")
.isBeforeOrEqualTo("2023-12-31");
2.
assertThat(optionalValue)
.isPresent()
.contains("expected");
3.
assertThat(book)
.matches(b -> b.getPages() > 100, "толстая книга")
.matches(b -> b.getAuthor() != null, "имеет автора");
1.💬 Более информативные сообщения об ошибках
2.💬 Поддержка цепочек проверок
3.💬 Встроенные проверки для коллекций
4.💬 Удобная работа с исключениями
5.💬 Поддержка Java 8+ features
Please open Telegram to view this post
VIEW IN TELEGRAM
👍22❤3🔥1
import org.jgrapht.Graph;
import org.jgrapht.alg.shortestpath.DijkstraShortestPath;
import org.jgrapht.graph.DefaultWeightedEdge;
import org.jgrapht.graph.SimpleWeightedGraph;
public class RoadNetworkExample {
public static void main(String[] args) {
// Создаем взвешенный граф
Graph roadNetwork =
new SimpleWeightedGraph<>(DefaultWeightedEdge.class);
// Добавляем города (вершины)
roadNetwork.addVertex("Москва");
roadNetwork.addVertex("Санкт-Петербург");
roadNetwork.addVertex("Нижний Новгород");
roadNetwork.addVertex("Казань");
// Добавляем дороги (ребра) с расстояниями
roadNetwork.setEdgeWeight(roadNetwork.addEdge("Москва", "Санкт-Петербург"), 700);
roadNetwork.setEdgeWeight(roadNetwork.addEdge("Москва", "Нижний Новгород"), 400);
roadNetwork.setEdgeWeight(roadNetwork.addEdge("Нижний Новгород", "Казань"), 400);
roadNetwork.setEdgeWeight(roadNetwork.addEdge("Санкт-Петербург", "Казань"), 1500);
// Находим кратчайший путь
DijkstraShortestPath dijkstraAlg =
new DijkstraShortestPath<>(roadNetwork);
var path = dijkstraAlg.getPath("Москва", "Казань");
System.out.println("Кратчайший путь: " + path.getVertexList());
System.out.println("Общее расстояние: " + path.getWeight() + " км");
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
⚡9👍6❤1
☕️ Фишка Java: Optional для Null-Safety
⚙️ Работа с null-значениями традиционно была источником ошибок в Java. Класс Optional предоставляет более элегантный способ обработки потенциально отсутствующих значений.
💬 Традиционный подход:
User user = getUserById(id);
if (user != null) {
Address address = user.getAddress();
if (address != null) {
String city = address.getCity();
if (city != null) {
System.out.println(city.toUpperCase());
}
}
}
💻 С использованием Optional:
Optional.ofNullable(getUserById(id))
.map(User::getAddress)
.map(Address::getCity)
.ifPresent(city -> System.out.println(city.toUpperCase()));
💻 Основные методы Optional:
1.⏺ ofNullable() - создает Optional из значения, которое может быть null
2.⏺ map() - преобразует значение, если оно присутствует
3.⏺ orElse() - предоставляет значение по умолчанию
4.⏺ ifPresent() - выполняет действие, если значение есть
5.⏺ orElseThrow() - бросает исключение, если значения нет
🗂 Примеры:
1.🔐 Безопасное получение вложенных свойств:
String cityName = Optional.ofNullable(order)
.map(Order::getCustomer)
.map(Customer::getAddress)
.map(Address::getCity)
.orElse("Unknown");
2.🗂 Комбинация нескольких Optional:
Optional<Double> totalPrice = Optional.ofNullable(order1)
.flatMap(o1 -> Optional.ofNullable(order2)
.map(o2 -> o1.getPrice() + o2.getPrice()));
3.🗂 Работа с коллекциями:
List<String> names = Optional.ofNullable(userList)
.orElse(Collections.emptyList())
.stream()
.map(User::getName)
.filter(Objects::nonNull)
.collect(Collectors.toList());
🗂 Преимущества использования Optional:
1.⏺ Явное указание на возможность отсутствия значения
2.⏺ Устранение проверок на null в коде
3.⏺ Четкая цепочка преобразований
4.⏺ Более читаемый и выразительный код
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14❤2
☕️ Лямбда-выражения и Stream API
💻 Лямбда-выражения и Stream API кардинально изменили подход к обработке данных в Java, позволив писать более декларативный и выразительный код.
🗂 Пример без лямбд:
List<String> names = Arrays.asList("John", "Alice", "Bob");
Collections.sort(names, new Comparator() {
@Override
public int compare(String a, String b) {
return a.compareTo(b);
}
});
🗂 С лямбда-выражением:
List<String> names = Arrays.asList("John", "Alice", "Bob");
names.sort((a, b) -> a.compareTo(b));
🔵 Stream API позволяет выполнять сложные операции над коллекциями:
List<String> filteredNames = names.stream()
.filter(name -> name.length() > 3)
.map(String::toUpperCase)
.sorted()
.collect(Collectors.toList());
🗂 Ключевые преимущества:
1.⏺ Упрощение работы с коллекциями
2.⏺ Возможность цепочечных вызовов методов
3.⏺ Параллельная обработка через parallelStream()
4.⏺ Ленивое выполнение операций
🗂 Примеры:
1.🔅 Фильтрация и преобразование:
List<Product> expensiveProducts = products.stream()
.filter(p -> p.getPrice() > 1000)
.map(p -> p.withDiscount(0.1))
.collect(Collectors.toList());
2.🟡 Группировка данных:
Map<String, List<Employ>> employeesByDepartment = employees.stream()
.collect(Collectors.groupingBy(Employee::getDepartment));
3.💬 Статистические операции:
IntSummaryStatistics stats = salaries.stream()
.mapToInt(Integer::intValue)
.summaryStatistics();
🗂 Особенности работы:
-💬 Stream не изменяет исходную коллекцию
-💬 Многие операции возвращают новый Stream
-💬 Терминальные операции завершают цепочку
-💬 Оптимизированная работа с памятью
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🔥4❤2
🗂 MapStruct — это генератор кода для маппинга между Java-бинами, который создает реализации mapper-ов на этапе компиляции.
1.🗣 Автоматический маппинг полей с одинаковыми именами
2.🗣 Высокая производительность (нет рефлексии в runtime)
3.🗣 Поддержка сложных преобразований
4.🗣 Интеграция с Spring и CDI
@Mapper(componentModel = "spring")
public interface UserMapper {
@Mapping(target = "fullName", expression = "java(user.getFirstName() + \" \" + user.getLastName())")
@Mapping(target = "status", constant = "ACTIVE")
UserDto toDto(User user);
@Mapping(target = "firstName", source = "fullName.split(\" \")[0]")
@Mapping(target = "lastName", source = "fullName.split(\" \")[1]")
User toEntity(UserDto dto);
}
-💬 Генерация чистого Java-кода без зависимостей
-💬 Поддержка коллекций и потоков
-💬 Преобразование типов
-💬 Работа с вложенными объектами
-💬 Кастомные методы маппинга
@Service
@RequiredArgsConstructor
public class UserService {
private final UserMapper userMapper;
public UserDto createUser(UserRequest request) {
User user = userMapper.toEntity(request);
// бизнес-логика
return userMapper.toDto(user);
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4👍3🔥3
Quartz - это мощная библиотека с открытым исходным кодом для планирования и выполнения задач по расписанию в Java-приложениях. Она предоставляет гибкие возможности для определения сложных расписаний выполнения задач и поддерживает кластеризацию.
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import java.time.LocalDateTime;
public class BackupSchedulerExample {
public static void main(String[] args) throws SchedulerException {
// Создаем планировщик
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// Определяем задачу
JobDetail job = JobBuilder.newJob(DatabaseBackupJob.class)
.withIdentity("databaseBackupJob", "backupGroup")
.build();
// Создаем триггер для запуска задачи каждый день в 2:00
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("dailyBackupTrigger", "backupGroup")
.withSchedule(CronScheduleBuilder.dailyAtHourAndMinute(2, 0))
.build();
// Планируем задачу с триггером
scheduler.scheduleJob(job, trigger);
// Запускаем планировщик
scheduler.start();
System.out.println("Планировщик резервного копирования запущен.");
System.out.println("Следующее резервное копирование запланировано на: "
+ trigger.getNextFireTime());
// Оставляем планировщик работать
try {
Thread.sleep(60000); // Ждем 1 минуту для демонстрации
} catch (InterruptedException e) {
e.printStackTrace();
}
// Останавливаем планировщик
scheduler.shutdown();
}
// Класс, представляющий задачу резервного копирования
public static class DatabaseBackupJob implements Job {
@Override
public void execute(JobExecutionContext context) {
System.out.println("Выполняется резервное копирование базы данных: "
+ LocalDateTime.now());
// Здесь был бы реальный код для резервного копирования
}
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7👍6🔥1🗿1
Начиная с Java 16, проверка типов с помощью
instanceof стала гораздо удобнее благодаря Pattern Matching. Раньше, после проверки объекта на принадлежность к определённому классу, нужно было выполнять явное приведение типа. Теперь это можно сделать в одной строке.Пример до Java 16:
if (obj instanceof String) {
String str = (String) obj;
System.out.println(str.length());
}
Пример с Pattern Matching:
if (obj instanceof String str) {
System.out.println(str.length());
}
Теперь после
instanceof можно сразу же использовать объект нужного типа в коде, что делает программу более читабельной и компактной.#java #PatternMatching #instanceof
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15🔥3❤1