JavaRocks
2.54K subscribers
80 photos
14 videos
159 links
Базовый канал для изучения языка Java.

Наш сайт: javarocks.ru

Все необходимые туториалы и материалы.

Тесты для проверки знаний. Лучшие практики и паттерны проектирования.
Download Telegram
⌨️ Дженерики (generics) — это механизм, который позволяет создавать классы, интерфейсы и методы, работающие с различными типами данных, при этом сохраняя строгую типизацию. Они были введены в Java начиная с версии 5 для повышения безопасности типов и повторного использования кода.

Дженерики позволяют определить параметр типа, который будет заменен конкретным типом данных при создании экземпляра класса или вызове метода. Например, List<T> может использоваться как List<String>, List<Integer> и т.д.

Благодаря дженерикам, ошибки типа (например, попытка вставить объект неправильного типа) обнаруживаются на этапе компиляции, а не во время выполнения программы.

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

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


public class Box<T> {
private T item;

public void setItem(T item) {
this.item = item;
}

public T getItem() {
return item;
}
}

Box<String> stringBox = new Box<>();
stringBox.setItem("Hello");
String str = stringBox.getItem();

В этом примере класс Box<T> является обобщенным и может работать с любым типом данных, который заменит T при создании объекта.

👉 Java Rocks | #java #generics #T
Please open Telegram to view this post
VIEW IN TELEGRAM
⌨️ Byte Buddy — это мощная библиотека для Java, предназначенная для создания, модификации и управления байт-кодом на лету, без необходимости использования низкоуровневых инструментов вроде ASM. Основное применение Byte Buddy — это динамическое создание и изменение классов в рантайме, что может быть полезно для написания агентов Java, создания прокси-объектов, внедрения кода в существующие классы и тестирования.

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

Byte Buddy поддерживает широкий диапазон версий Java и интегрируется с такими библиотеками, как Spring и Hibernate.

import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import net.bytebuddy.implementation.FixedValue;

import static net.bytebuddy.matcher.ElementMatchers.named;

public class ByteBuddyExample {
public static void main(String[] args) throws Exception {
// Создаем новый класс динамически
Class<?> dynamicType = new ByteBuddy()
.subclass(Object.class) // Класс наследуется от Object
.name("com.example.HelloWorld") // Указываем имя нового класса
.method(named("toString")) // Переопределяем метод toString
.intercept(FixedValue.value("Hello from Byte Buddy!")) // Метод будет возвращать фиксированное значение
.make()
.load(ByteBuddyExample.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();

// Создаем экземпляр нового класса
Object instance = dynamicType.getDeclaredConstructor().newInstance();

// Вызываем переопределенный метод toString
System.out.println(instance.toString()); // Вывод: Hello from Byte Buddy!
}
}

👉 Java Rocks | #java #bytebuddy
Please open Telegram to view this post
VIEW IN TELEGRAM
🗑 Понимание различных сборщиков мусора в Java:

🔵 Serial Garbage Collector: Лучший вариант для однопоточных приложений с небольшими кучами. Он использует один поток для выполнения как малых, так и больших сборок мусора, что приводит к значительным паузам, но минимальной нагрузке на систему.

🔵 Parallel Garbage Collector: Подходит для приложений с высокими требованиями к пропускной способности. Использует несколько потоков для выполнения как малых, так и больших сборок мусора, уменьшая время пауз, но при этом увеличивая использование CPU.

🔵 Concurrent Mark-Sweep (CMS) Garbage Collector: Разработан для минимизации пауз за счёт выполнения основной части работы по сборке мусора параллельно с выполнением приложений. Подходит для приложений, где критически важна низкая задержка.

🔵 G1 Garbage Collector: Сбалансированный сборщик мусора, который стремится обеспечить предсказуемое время пауз, разделяя кучу на регионы и выполняя сборку мусора поэтапно. Является хорошим выбором по умолчанию для большинства приложений.

🔵 Z Garbage Collector и Shenandoah: Сборщики мусора с ультранизкой задержкой, разработанные для работы с большими кучами. Основная часть работы по сборке мусора выполняется параллельно, что позволяет минимизировать время пауз даже при очень больших кучах.

👉 Java Rocks | #java
Please open Telegram to view this post
VIEW IN TELEGRAM
⌨️ Суть лямбда-выражений

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

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

Если говорить ещё проще, лямбда-выражение — это просто другой способ создания и реализации объекта определённого типа. Рассмотрим это на примере создания нового потока.

У класса Thread есть конструктор:

public Thread(Runnable target) {
...
}


То есть в конструктор нужно передать объект типа Runnable. До лямбда-выражений мы сделали бы так:

new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Hello World");
}
}).start();

Здесь мы создаём анонимный класс, реализующий интерфейс Runnable, с определённым методом run.
Если использовать лямбда-выражение, тот же код будет выглядеть следующим образом:

Runnable r = () -> System.out.println("Hello World");
new Thread(r).start();

Или проще:

new Thread(() -> System.out.println("Hello World")).start();


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

@FunctionalInterface
public interface Runnable {
public abstract void run();
}


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

👉 Java Rocks | #java #lambda #runnable
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Что такое ElasticSearch

Elasticsearch — открытая распределенная система управления данными и поиска по ним, основанная на поисковом движке Apache Lucene.

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

. Она идеально подходит для приложений, требующих гибкости в поиске и высокой скорости обработки запросов. Благодаря интеграции с Kibana и Logstash, ElasticSearch становится мощным инструментом для мониторинга и анализа данных в реальном времени.

📌 Функции:

▪️ Мгновенный поиск по большим объемам данных
▪️ Гибкая схема индексации и поиска
▪️ Легкость в масштабировании и интеграции

👉 Java Rocks | #java
Please open Telegram to view this post
VIEW IN TELEGRAM
⌨️ Лямбда-выражения и свой кастомный функциональный интерфейс

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

@FunctionalInterface
interface MathOperation {
int operate(int a, int b);
}

Функциональный интерфейс MathOperation содержит один абстрактный метод operate, который принимает два значения типа int и возвращает int. Аннотация @FunctionalInterface указывает на то, что интерфейс предназначен для использования в функциональном программировании и должен содержать только один абстрактный метод. Но аннотация не обязательна.

Использование лямбда-выражения:

public class LambdaExample {
public static void main(String[] args) {
// Реализация интерфейса с помощью лямбда-выражения
MathOperation addition = (a, b) -> a + b;
MathOperation subtraction = (a, b) -> a - b;
MathOperation multiplication = (a, b) -> a * b;
MathOperation division = (a, b) -> a / b;

int x = 10;
int y = 5;

System.out.println("Addition: " + operate(x, y, addition)); // 15
System.out.println("Subtraction: " + operate(x, y, subtraction)); // 5
System.out.println("Multiplication: " + operate(x, y, multiplication)); // 50
System.out.println("Division: " + operate(x, y, division)); // 2
}

// Метод, принимающий MathOperation и применяющий его к данным
private static int operate(int a, int b, MathOperation operation) {
return operation.operate(a, b);
}
}


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

Метод operate принимает два целых числа и функциональный интерфейс MathOperation, затем выполняет переданную операцию. В метод в третьем параметре можно передать непосредственно лямбда-выражение, не используя промежуточную переменную.

🖥 Что такое ElasticSearch

Elasticsearch — открытая распределенная система управления данными и поиска по ним, основанная на поисковом движке Apache Lucene.

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

. Она идеально подходит для приложений, требующих гибкости в поиске и высокой скорости обработки запросов. Благодаря интеграции с Kibana и Logstash, ElasticSearch становится мощным инструментом для мониторинга и анализа данных в реальном времени.

📌 Функции:

▪️ Мгновенный поиск по большим объемам данных
▪️ Гибкая схема индексации и поиска
▪️ Легкость в масштабировании и интеграции

👉 Java Rocks | #java #lambda #functionalinterface
Please open Telegram to view this post
VIEW IN TELEGRAM
Когда и как использовать var, чтобы код стал понятнее?

Слышали про var? Его добавили в Java 10, чтобы облегчить нам жизнь. Но когда его лучше использовать, а когда стоит быть осторожнее?💡

Когда использовать var:

🔵 Когда всё понятно с контекста: Если тип переменной очевиден 👀, то зачем писать лишнее?

var list = new ArrayList<String>(); // Это список, и это сразу видно


🔵 Когда тип слишком громоздкий: Если объявление слишком длинное и перегружает код, var упрощает задачу:

var map = new HashMap<String, List<Integer>>(); // Чисто и просто


🔵 Короткие методы: В небольших методах с чёткой логикой, var помогает сделать код компактнее и читабельнее.

А вот где лучше избегать:

🔵 Если тип неочевиден: Когда сложно сразу понять, что это за переменная, лучше явно указать тип, чтобы не путать коллег.
var result = process(); // И что за процесс тут? 


Итог: var — отличный инструмент, но используйте его с умом. Вопрос к вам: а вы уже используете var в своих проектах? Если да, поделитесь опытом в комментариях! 👇

👉 Java Rocks | #java
Please open Telegram to view this post
VIEW IN TELEGRAM
🤫 Некоторые популярные методы аутентификации

🔵 Базовая аутентификация:
Предполагает отправку имени пользователя и пароля с каждым запросом, но может быть менее безопасной без шифрования.
Подходит для простых приложений, где безопасность и шифрование не являются приоритетом, или при использовании защищенных соединений.

🔵 Аутентификация с помощью токенов:
Использует сгенерированные токены, такие как JSON Web Tokens (JWT), которые обмениваются между клиентом и сервером, обеспечивая повышенную безопасность без необходимости отправки учетных данных с каждым запросом.
Идеально подходит для более безопасных и масштабируемых систем.

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

🔵 Аутентификация с использованием API-ключей:
Назначает уникальные ключи пользователям или приложениям, которые отправляются в заголовках или параметрах; несмотря на простоту, может не обладать всеми преимуществами безопасности, как методы на основе токенов или OAuth.
Удобна для простого контроля доступа в менее чувствительных средах или для предоставления доступа к определённым функциям без необходимости предоставления разрешений, привязанных к конкретному пользователю.

💬 Какой метод аутентификации вы считаете наиболее эффективным с точки зрения обеспечения безопасности и удобства использования в ваших приложениях?

👉 Java Rocks | #java
Please open Telegram to view this post
VIEW IN TELEGRAM
⌨️ Что такое класс Object? Какие в нем есть методы?

Object это базовый класс для всех остальных объектов в Java. Любой класс наследуется от Object и, соответственно, наследуют его методы:

public boolean equals(Object obj) – служит для сравнения объектов по значению;

int hashCode() – возвращает hash код для объекта;

String toString() – возвращает строковое представление объекта;

Class getClass() – возвращает класс объекта во время выполнения;

protected Object clone() – создает и возвращает копию объекта;

void notify() – возобновляет поток, ожидающий монитор;

void notifyAll() – возобновляет все потоки, ожидающие монитор;

void wait() – остановка вызвавшего метод потока до момента пока другой поток не вызовет метод notify() или notifyAll() для этого объекта;

void wait(long timeout) – остановка вызвавшего метод потока на определённое время или пока другой поток не вызовет метод notify() или notifyAll() для этого объекта;

void wait(long timeout, int nanos) – остановка вызвавшего метод потока на определённое время или пока другой поток не вызовет метод notify() или notifyAll() для этого объекта;

protected void finalize() – может вызываться сборщиком мусора в момент удаления объекта при сборке мусора.

👉 Java Rocks | #java #object #methods
Please open Telegram to view this post
VIEW IN TELEGRAM
🎮 Cross-platform Game Development Framework

Это кроссплатформенная среда для разработки Java-игр на основе OpenGL, которая предоставляет надежную и проверенную временем платформу для быстрого прототипирования и создания игр.

▪️ Github

👉 Java Rocks | #java
Please open Telegram to view this post
VIEW IN TELEGRAM