Java Core — это не просто "синтаксис", это то, на чём держится весь язык: классы, объекты, память, потоки, исключения. Ни Spring, ни фреймворки не помогут, если ты не знаешь базу.
class User {
String name;
int age;
void sayHello() {
System.out.println("Привет, меня зовут " + name);
}
}
User u = new User();
u.name = "Иван";
u.sayHello();class Point {
int x, y;
Point() {
this(0, 0);
}
Point(int x, int y) {
this.x = x;
this.y = y;
}
}this(...) вызывает другой конструктор — удобно задавать значения по умолчанию.superclass Animal {
void speak() {
System.out.println("звук");
}
}
class Dog extends Animal {
void speak() {
super.speak();
System.out.println("гав");
}
}super нужен, когда хочешь использовать поведение родителя, а не полностью переопределять.interface Printable {
void print();
}
class Book implements Printable {
public void print() {
System.out.println("Печать книги");
}
}void run() {
int x = 10; // stack
String name = "Java"; // heap (объект)
}🪓 Final, static, this
class Example {
static int count = 0;
final int id;
Example() {
this.id = ++count;
}
}final — нельзя переопределить/изменитьstatic — общая переменная на все объектыthis — текущий объектList<String> names = List.of("Alice", "Bob");
for (String name : names) {
System.out.println(name);
}Iterable.try {
int x = 1 / 0;
} catch (ArithmeticException e) {
System.out.println("Ошибка: деление на 0");
} finally {
System.out.println("Завершение");
}finally выполнится всегда. Можно использовать для закрытия ресурсов.⚡️ Вложенные классы и лямбды
Runnable r = () -> System.out.println("Привет из потока");
new Thread(r).start();equals() ==String a = "test";
String b = new String("test");
System.out.println(a == b); // false
System.out.println(a.equals(b)); // true
🧵 Потоки (Thread) и синхронизация
class Task extends Thread {
public void run() {
System.out.println("Поток: " + Thread.currentThread().getName());
}
}
new Task().start();start() запускает поток асинхронно. run() — просто метод, вызовется как обычный.List<String> list = new ArrayList<>();
Set<String> set = new HashSet<>();
Map<String, Integer> map = new HashMap<>();
List — упорядоченный списокSet — уникальные элементыMap — пары ключ-значениеclass Box<T> {
T value;
void set(T value) { this.value = value; }
T get() { return value; }
}Box<String>, Box<Integer> — типизируешь класс под себя.Java Core — это то, что ты используешь каждый день, даже если не замечаешь. Понимание классов, памяти, коллекций, исключений и потоков — это не “для экзамена”, это основа всей архитектуры твоего кода.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤17👍5🔥4❤🔥1👨💻1
В 2025 году Java предлагает два мощных и актуальных подхода к масштабируемому коду: виртуальные потоки (Project Loom) и реактивное программирование (Project Reactor, RxJava). Какой из них выбрать, зависит от задач, но важно понять различия.
В статье ты узнаешь:
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5🔥4👍3
Если тебе нужно запускать задачи параллельно — не создавай 1000
new Thread() руками.ThreadPool даст тебе контроль, переиспользование потоков и экономию ресурсов.
ExecutorsExecutorService pool = Executors.newFixedThreadPool(4);
for (int i = 0; i < 10; i++) {
int taskId = i;
pool.submit(() -> {
System.out.println("🔧 Задача " + taskId + " в потоке " + Thread.currentThread().getName());
});
}
pool.shutdown();
shutdown() завершает работу пула после выполнения задач.Executors.newFixedThreadPool(4); // фиксированное количество потоков
Executors.newCachedThreadPool(); // динамически растёт при нагрузке
Executors.newSingleThreadExecutor(); // один поток на всё
Fixed — стабильный.Cached — вспышки нагрузки.Single — последовательные задачи.new Thread()?new Thread(() -> doStuff()).start(); // плохо для большого числа задач
Thread — это новый объект + ресурсы ОС.pool.shutdown(); // мягкое завершение
pool.awaitTermination(10, TimeUnit.SECONDS);
pool.shutdownNow(); // жёсткая остановка
shutdown(), потом awaitTermination() — ждёшь окончания.shutdownNow() — кидает InterruptedException в задачи.ExecutorService pool = Executors.newSingleThreadExecutor();
Callable<String> task = () -> {
Thread.sleep(1000);
return "Готово!";
};
Future<String> result = pool.submit(task);
System.out.println(result.get()); // блокирует до результата
pool.shutdown();
Callable возвращает значение, в отличие от Runnable.Future.get() — ждёт выполнения.ThreadPoolExecutorExecutorService pool = new ThreadPoolExecutor(
2, 4, 60, TimeUnit.SECONDS,
new LinkedBlockingQueue<>()
);
ThreadPool — это не про скорость, а про контроль и стабильность. Не плодишь потоки — а держишь их в узде. Подходит для бэкенда, ботов, парсеров, фоновых задач и всего, что живёт в многопоточке.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤12🔥6👍1
Spring — не только
@Autowired и @Controller. Он умеет кэшировать, обрабатывать события, внедрять бин по условию, управлять конфигурацией, проксировать методы и даже сам себя обновлять.Вот то, что ты точно начнёшь использовать в реальных проектах
@PostConstruct — инициализация после DI@Component
public class MyService {
@PostConstruct
public void init() {
System.out.println("✅ Всё сконфигурировано, запускаем...");
}
}
@EventListener — реакция на внутренние события@Component
public class UserEventHandler {
@EventListener
public void onRegistered(UserRegisteredEvent event) {
System.out.println("🎉 Новый пользователь: " + event.getEmail());
}
}
// где-то в коде:
applicationEventPublisher.publishEvent(new UserRegisteredEvent(email));
@Bean
@ConditionalOnProperty(name = "feature.cool", havingValue = "true")
public CoolFeature coolFeature() {
return new CoolFeature();
}
@ConfigurationProperties — структурированная конфигурация@ConfigurationProperties(prefix = "mail")
@Component
public class MailSettings {
private String host;
private int port;
// getters/setters
}
application.yml:mail:
host: smtp.example.com
port: 587
MailSettings бин — без @Value, без хардкода.@Value@Value("${app.name:DefaultApp}")
private String appName;app.name из пропертей. Если не указано — будет "DefaultApp".@Aspect
@Component
public class LogAspect {
@Around("@annotation(Loggable)")
public Object log(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("▶️ Вызов: " + pjp.getSignature());
Object result = pjp.proceed();
System.out.println("⏹️ Результат: " + result);
return result;
}
}
@Loggable. Реальный способ вклиниваться в методы без изменения кода.@Cacheable("users")
public User getById(Long id) {
return userRepository.findById(id).orElseThrow();
}id результат будет из кеша. Настраивается в пару строк через @EnableCaching.🧵 Асинхронные методы без
Thread@Async
public void sendMailAsync(String email) {
mailSender.send(email);
}
Future) можно отследить. Главное — не забыть @EnableAsync.@Bean
@Scope("prototype")
public Connection tempConnection() {
return new Connection();
}
getBean(Connection.class) даст новый объект, а не singleton.@Autowired
private ConfigurableApplicationContext context;
public void reload() {
context.refresh();
}
Spring — не фреймворк, это платформа.
Настоящая сила — в деталях: события, прокси, AOP, конфигурации, кеш, асинхронность.
Чем лучше ты понимаешь эти фишки — тем меньше шаблонного кода и больше магии под контролем.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤13👍6🔥4
Безопасность давно перестала быть опцией — это must-have. В 2025 Java предлагает разработчику целый арсенал встроенных решений и новых подходов для защиты своих сервисов.
В статье ты узнаешь:
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3❤2🔥2👨💻1
Hibernate — это Object-Relational Mapping.
Он превращает твои Java-классы в таблицы и наоборот.
Без JDBC, без ручных SQL-запросов — читаешь и сохраняешь объекты как есть.
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue
private Long id;
private String name;
@Column(name = "email_address")
private String email;
// геттеры/сеттеры
}
@Entity превращает класс в таблицу@Id — это первичный ключ@Column — имя колонки, если отличается от поляUser u = new User();
u.setName("Alice");
u.setEmail("a@example.com");
session.save(u);
INSERT INTO users ... под капотом.List<User> users = session
.createQuery("from User where email like :e", User.class)
.setParameter("e", "%@gmail.com")
.getResultList();
from User — это не SQL, а HQL. Работает на уровне классов, не таблиц.@Entity
public class Order {
@Id @GeneratedValue
private Long id;
@ManyToOne
private User user;
private String product;
}
User — много Order. Hibernate сам создаст user_id в таблице заказов.User u = session.get(User.class, 1L);
List<Order> orders = u.getOrders(); // автоматический join
📋 Обновление и удаление
User u = session.get(User.class, 2L);
u.setName("Bob");
session.update(u);
session.delete(u);
spring.jpa.hibernate.ddl-auto=update
Hibernate — это способ писать код, а не SQL. Он мапит Java-объекты на реляционные таблицы, сам управляет транзакциями, связями, сессиями.
Но главное — он не магия, и работает только если ты понимаешь, что под капотом.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤5🔥2
Ты не обязан учить ООП по книжке. Но обязан понимать, как структурировать код, чтобы его можно было:
Вот как это делается в боевом коде
public interface Storage {
void save(String data);
}
public class FileStorage implements Storage {
public void save(String data) {
// записать в файл
}
}
public class DBStorage implements Storage {
public void save(String data) {
// сохранить в БД
}
}Storage, а не с FileStorage или DBStorage.public class App {
private final Storage storage;
public App(Storage storage) {
this.storage = storage;
}
public void run() {
storage.save("some data");
}
}public class Logger {
public void log(String message) {
System.out.println("[LOG] " + message);
}
}
public class UserService {
private final Logger logger = new Logger();
public void register(String name) {
logger.log("Регистрация пользователя " + name);
}
}extends Logger — просто вставили поведение. Гибче, проще, безопаснее.public class Order {
private final List<Product> products;
public Order(List<Product> products) {
this.products = products;
}
public BigDecimal total() {
return products.stream()
.map(Product::price)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
}public interface DiscountPolicy {
BigDecimal apply(BigDecimal price);
}
public class NoDiscount implements DiscountPolicy {
public BigDecimal apply(BigDecimal price) {
return price;
}
}
public class BlackFridayDiscount implements DiscountPolicy {
public BigDecimal apply(BigDecimal price) {
return price.multiply(new BigDecimal("0.7"));
}
}public class Checkout {
private final DiscountPolicy discount;
public Checkout(DiscountPolicy discount) {
this.discount = discount;
}
public BigDecimal finalPrice(BigDecimal basePrice) {
return discount.apply(basePrice);
}
}ООП в Java — это не “инкапсуляция — наследование — полиморфизм”, а грамотно разложенные по объектам ответственности и поведение.
Если твой код не надо переписывать, чтобы добавить новый сценарий — это оно.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍17❤10👨💻3
Методы
hashCode() и equals() в Java тесно связаны и играют ключевую роль в работе хеш-структур, таких как HashMap, HashSet, Hashtable.🔹 Метод
equals(Object obj)Этот метод определяет логическое равенство объектов. По умолчанию (
Object.equals) сравниваются ссылки (то есть ==), но обычно его переопределяют, чтобы сравнивать содержимое объектов.📜 Контракт equals:
1️⃣ Рефлексивность —
x.equals(x) должно быть true.2️⃣ Симметричность —
x.equals(y) ⇒ y.equals(x).3️⃣ Транзитивность —
x.equals(y) и y.equals(z) ⇒ x.equals(z).4️⃣ Согласованность — многократные вызовы
x.equals(y) возвращают один и тот же результат, если объекты не меняются.5️⃣ Сравнение с null —
x.equals(null) должно быть false.🔹 Метод
hashCode()Возвращает целое число, которое используется, например, для определения "корзины" (bucket) в хеш-таблицах.
📜 Контракт hashCode:
x.equals(y) — обязательно x.hashCode() == y.hashCode().x.hashCode() == y.hashCode(), это не значит, что x.equals(y).🔄 Связь между equals и hashCode:
Если вы переопределяете
equals(), вы обязательно должны переопределить и hashCode(), иначе, например, объект не будет корректно работать в HashSet или HashMap.⛔️ Пример ошибки:
Set<Person> people = new HashSet<>();
people.add(new Person("Alice"));
System.out.println(people.contains(new Person("Alice"))); // false, если hashCode не переопределен
✅ Правильный шаблон:
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Person person = (Person) obj;
return name.equals(person.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
Please open Telegram to view this post
VIEW IN TELEGRAM
❤11👍7🔥2👏1
Хотите узнать, что реально происходит в Java‑приложении? eBPF открывает доступ к ядру Linux и даёт метрики и трассировку без переписывания кода или агентов.
В статье вы найдёте:
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3👍2🔥2
Строки в Java неизменяемы — это значит, что любой метод
replace(), substring(), toUpperCase() и даже += не изменяет строку, а создаёт новую.Это кажется удобным... пока ты не врежешься в реальные проблемы.
String s = "hello";
s.toUpperCase();
System.out.println(s); // hello ❌
s.toUpperCase() вернул новую строку, но ты её никуда не сохранил.Оригинальная строка осталась неизменной.
1️⃣ . Безопасность
Строки используются в ClassLoader, Map, URL, Reflection.
Если бы кто-то мог изменить строку "com.mysql.Driver" в рантайме — ты бы загрузил не тот класс.
2️⃣ . Хеширование
String.hashCode() кешируется. Если строка изменилась бы после попадания в HashMap,
ты больше не смог бы её достать по ключу.
3️⃣ . Thread Safety
Несколько потоков могут использовать одну строку одновременно — без блокировок и синхронизации.
Иммутабельность = потокобезопасность.
String a = "test";
String b = new String("test");
System.out.println(a == b); // false ❌
System.out.println(a.equals(b)); // true ✅
== сравнивает ссылки, а не значения. Даже если строки одинаковые, объект может быть другим.String s = "";
for (int i = 0; i < 1000; i++) {
s += i;
}
+= создаёт новую строку. 1000 операций = 1000 объектов = тормоза.Правильно так:
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
sb.append(i);
}
String result = sb.toString();
String huge = "..." // большой текст
String small = huge.substring(0, 5);
small держал ссылку на huge — из-за чего вся большая строка не могла быть удалена.Java это исправили, но в старых версиях боль реальна.
String — это надёжный, безопасный и вечно новый объект.Хочешь модифицировать — используй
StringBuilder или StringBuffer.Хочешь сравнить —
equals(), не ==.Please open Telegram to view this post
VIEW IN TELEGRAM
❤10👍6🔥3
Хочешь забирать данные из API, отправлять JSON, работать с HTTP в Java — и без боли? С Java 11 всё проще, потому что появился
HttpClient, который умеет GET, POST, JSON, async — всё, что надо.Вот разбор — пошагово и с примерами
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
java.net.http, ничего не нужно скачивать.HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.github.com"))
.build();
uri() — это URL запроса. Обязательно через URI.create(...).HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());
send() — делает синхронный запрос.BodyHandlers.ofString() — тело ответа как строка.String json = """
{
"name": "Alice",
"role": "admin"
}
""";
HttpRequest postRequest = HttpRequest.newBuilder()
.uri(URI.create("https://example.com/api/users"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(json))
.build();
HttpResponse<String> postResponse = client.send(postRequest, HttpResponse.BodyHandlers.ofString());
System.out.println(postResponse.body());
.POST() + BodyPublishers.ofString(...) для телаContent-Type, чтобы сервер знал, что это JSONclient.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println);
sendAsync() — не блокирует потокCompletableFuture — можно делать цепочкиtry {
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 200) {
System.out.println("✅ Успех");
} else {
System.out.println("❌ Ошибка: " + response.statusCode());
}
} catch (Exception e) {
System.out.println("⚠️ Ошибка при запросе: " + e.getMessage());
}HttpClient можно делать любые HTTP-запросы прямо из Java-кода.Больше не нужно использовать громоздкий
HttpURLConnection или сторонние библиотеки. Всё компактно и читаемо.Please open Telegram to view this post
VIEW IN TELEGRAM
👍16❤2
Если ты устал писать
getters, setters, equals, toString, конструкторы и билдеры вручную — библиотека Lombok создана для тебя. Это мощный инструмент, который избавляет от шаблонного кода и делает Java-классы чище.Вот как он работает и почему это стоит подключить уже сегодня
Lombok — это Java-библиотека, которая с помощью аннотаций генерирует код во время компиляции. Ты не видишь этих методов в коде, но они есть в .class-файле.
Для Maven:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>
Для Gradle:
compileOnly 'org.projectlombok:lombok:1.18.30'
annotationProcessor 'org.projectlombok:lombok:1.18.30'
🟢 Шаг 3: Убираем шаблонный код
Без Lombok:
public class User {
private String name;
private int age;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
@Override
public String toString() {
return "User{name='" + name + "', age=" + age + "}";
}
}С Lombok:
import lombok.Data;
@Data
public class User {
private String name;
private int age;
}
@Data создаёт:get/set, toString(), equals(), hashCode() и конструктор по умолчанию.Часто используемые аннотации Lombok
@Getter @Setter // Только геттеры и сеттеры
@NoArgsConstructor // Пустой конструктор
@AllArgsConstructor // Конструктор со всеми полями
@RequiredArgsConstructor // Только для final / @NonNull полей
@Builder // Шаблон Builder
@ToString // Авто toString()
@EqualsAndHashCode // equals() + hashCode()
@Value // Immutable класс (все final)
import lombok.Builder;
import lombok.ToString;
@Builder
@ToString
public class Product {
private String name;
private double price;
private boolean available;
}
Product p = Product.builder()
.name("MacBook")
.price(2499.99)
.available(true)
.build();
System.out.println(p);
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14❤2😇2
Lombok кажется магией: пишешь
@Getter, @Builder, @Slf4j — и бац, всё работает. Но на самом деле он не добавляет методы во время выполнения. Всё происходит на этапе компиляции, и ты даже можешь это увидеть.@Getter
public class User {
private String name;
}
public String getName() {
return this.name;
}Lombok использует Javac-плагины и работает как annotation processor. Он подключается в javac через SPI (Service Provider Interface) и внедряется в процесс разбора исходного кода — до того, как он станет байткодом.
IntelliJ IDEA и Eclipse поддерживают Lombok через плагины. Они умеют подхватывать изменения AST от Lombok, и даже подсвечивать методы, которые физически не написаны.
@Builder
public class Book {
private String title;
private int pages;
}
public static class BookBuilder {
private String title;
private int pages;
public BookBuilder title(String title) {
this.title = title;
return this;
}
public BookBuilder pages(int pages) {
this.pages = pages;
return this;
}
public Book build() {
return new Book(title, pages);
}
}Book.builder() — точка входа.Скомпилируй Lombok-класс и деобфусцируй
.class:javac Book.java
javap -p Book.class
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9❤7🔥6
Java не стоит на месте: версия 25 выходит уже этой осенью и принесёт не просто косметические изменения, а реально новые возможности для удобного, быстрого и современного кода. Если вы считали Java «тяжеловесом» — самое время пересмотреть взгляд!
В статье вы найдёте:
Please open Telegram to view this post
VIEW IN TELEGRAM
😇7👍5
Когда у тебя API, бот, сервер или утилита — нужно ограничивать частоту запросов, чтобы никто не зафлудил систему.
Решение — Rate Limiter. Ни Spring, ни Guava не нужны. Всё делаем на чистом Java.
Идея простая: мы храним время всех недавних запросов и выкидываем те, что вышли за окно (например, 10 секунд назад).
class RateLimiter {
private final int limit;
private final long windowMs;
private final Deque<Long> timestamps = new ArrayDeque<>();
public RateLimiter(int limit, long windowSeconds) {
this.limit = limit;
this.windowMs = windowSeconds * 1000;
}
public synchronized boolean allow() {
long now = System.currentTimeMillis();
// Удаляем старые запросы
while (!timestamps.isEmpty() && now - timestamps.peek() > windowMs) {
timestamps.poll();
}
// Проверка лимита
if (timestamps.size() < limit) {
timestamps.add(now);
return true;
}
return false;
}
}limit — количество запросов, windowSeconds — время в секундах.Всё хранится в памяти. Работает моментально, идеально для локального контроля.
Представим, у тебя HTTP-сервер или обработчик:
RateLimiter limiter = new RateLimiter(5, 10); // 5 запросов на 10 сек
public void handleRequest() {
if (limiter.allow()) {
System.out.println("✅ Запрос принят");
} else {
System.out.println("❌ 429 Too Many Requests");
}
}
Чтобы не глобально, а по каждому клиенту — оборачиваем RateLimiter в Map.
Map<String, RateLimiter> userLimits = new ConcurrentHashMap<>();
public boolean allowRequest(String userId) {
userLimits.putIfAbsent(userId, new RateLimiter(10, 30));
return userLimits.get(userId).allow();
}
Так как у нас ConcurrentHashMap и synchronized внутри лимитера — решение уже потокобезопасное. Можно сразу использовать в многопоточных веб-приложениях или TCP-серверах.
Вот что будет, если послать много запросов:
for (int i = 0; i < 20; i++) {
boolean ok = limiter.allow();
System.out.println(i + " -> " + (ok ? "✅" : "❌"));
Thread.sleep(1000);
}Please open Telegram to view this post
VIEW IN TELEGRAM
❤12🔥7👍5
Maven использует жизненный цикл сборки, который делится на несколько фаз. Фазы определяют последовательность задач, которые Maven выполняет для сборки и управления проектом.
Основные фазы жизненного цикла Maven включают:
1️⃣ validate – Проверяет, что проект правильный и вся необходимая информация указана.
2️⃣ compile – Компилирует исходный код проекта.
3️⃣ test – Запускает тесты (обычно с использованием JUnit или TestNG) и проверяет, что они проходят успешно.
4️⃣ package – Собирает скомпилированный код и пакует его, например, в JAR или WAR-файл.
5️⃣ verify – Проверяет собранные артефакты и результаты тестов.
6️⃣ install – Устанавливает пакет в локальный репозиторий для использования как зависимость в других проектах.
7️⃣ deploy – Отправляет финальный пакет в удаленный репозиторий для использования в других проектах или на сервере.
Основные команды Maven:
✔️
mvn clean – Удаляет папку target, очищая проект от предыдущих сборок.✔️
mvn compile – Компилирует исходный код проекта.✔️
mvn test – Запускает тесты.✔️
mvn package – Пакует скомпилированный код в конечный артефакт (обычно JAR или WAR).✔️
mvn install – Устанавливает артефакт в локальный репозиторий.✔️
mvn deploy – Деплоит артефакт в удаленный репозиторий.✔️
mvn site – Генерирует документацию проекта на основе кода и зависимостей.Фазы выполняются последовательно, то есть если вы запускаете команду
mvn install, Maven автоматически пройдет через все предыдущие фазы – от validate до install.Примеры команд:
✔️
mvn clean install – очищает проект, компилирует, тестирует и устанавливает артефакт в локальный репозиторий.✔️
mvn package -DskipTests – собирает проект в артефакт, пропуская тесты.#java #Maven
Please open Telegram to view this post
VIEW IN TELEGRAM
👍18❤3🔥3
Java даёт способ выполнить код один раз, ещё до создания объекта. Это называется static initializer — и с ним можно делать настоящие фокусы
Когда JVM загружает класс — выполняются все static-блоки, даже если ты не создавал ни одного объекта.
Это можно использовать для:
main()public class Hello {
static {
System.out.println("Загрузка Hello");
}
public static void main(String[] args) {
System.out.println("main()");
}
}Загрузка Hello
main()
public class RunOnce {
static {
System.out.println("Код запустился без main()");
System.exit(0); // JVM завершится
}
}RunOnce.class — код выполнится, и main() даже не потребуется.interface Plugin {
void run();
}
class Registry {
static List<Plugin> plugins = new ArrayList<>();
static void register(Plugin p) {
plugins.add(p);
}
}
public class PluginA implements Plugin {
static {
Registry.register(new PluginA());
}
public void run() {
System.out.println("Плагин A запущен");
}
}PluginA, ты уже зарегистрировал его — без явного вызова конструктора или методов.class Evil {
static {
System.setSecurityManager(null); // отключаем защиту
}
}Подгружаешь
Evil.class, и твой код внезапно без ограничений.Unsafe, Objenesis или про bytecode-инъекции? Пиши тему — сделаем с практикой.Please open Telegram to view this post
VIEW IN TELEGRAM
👍14🔥5😇3❤2👏1
Классика: приходит строка
"ACTIVE" — надо получить Status.ACTIVE. Но вместо кучи if или switch — строим быстрый и красивый Map-мэппинг, который работает за O(1) и не ломается при добавлении новых enum.Вот как это сделать правильно
public enum Status {
ACTIVE("active"),
BLOCKED("blocked"),
DELETED("deleted");
private final String code;
Status(String code) { this.code = code; }
public String getCode() { return code; }
}code, который будет использоваться для маппинга (например, из JSON, БД или UI).public class StatusMapper {
private static final Map<String, Status> CODE_MAP = Arrays.stream(Status.values())
.collect(Collectors.toMap(Status::getCode, Function.identity()));
public static Status fromCode(String code) {
return CODE_MAP.get(code);
}
}Map<String, Status>, где ключ — это status.getCode(), а значение — сам enum.Status status = StatusMapper.fromCode("active");
System.out.println(status); // ACTIVEif, без null, без ошибок при добавлении новых значений.public static Status fromCode(String code) {
Status result = CODE_MAP.get(code);
if (result == null) {
throw new IllegalArgumentException("Unknown status: " + code);
}
return result;
}Enum.name() и Enum.toString() — не для бизнес-логики. Маппинг через Map — самый быстрый и читаемый способ.Please open Telegram to view this post
VIEW IN TELEGRAM
👍16❤5🔥2👏1😇1
Java — безопасный язык, пока ты не подключаешь
Unsafe. Это внутренний API из JDK, который даёт доступ к памяти как в C: ты можешь читать, писать, аллоцировать и даже обойти конструкторы. Без всяких JVM-защит.Unsafe (через костыль)Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
Unsafe unsafe = (Unsafe) f.get(null);--add-opens, но в старых версиях работает напрямую.long address = unsafe.allocateMemory(8); // 8 байт
unsafe.putLong(address, 123456789L); // запись
long value = unsafe.getLong(address); // чтение
System.out.println(value); // 123456789
unsafe.freeMemory(address); // ручной free
class Demo {
private int secret = 42;
}
Demo d = new Demo();
Field field = Demo.class.getDeclaredField("secret");
long offset = unsafe.objectFieldOffset(field);
unsafe.putInt(d, offset, 99); // меняем приватное поле
System.out.println(unsafe.getInt(d, offset)); // 99newclass NoConstructor {
private NoConstructor() {
throw new RuntimeException("Don't call me");
}
}
NoConstructor obj = (NoConstructor) unsafe.allocateInstance(NoConstructor.class);
System.out.println(obj);int[] arr = new int[10];
long base = unsafe.arrayBaseOffset(int[].class);
int scale = unsafe.arrayIndexScale(int[].class);
unsafe.putInt(arr, base + scale * 5, 99); // пишем в arr[5]
System.out.println(arr[5]); // 99
Unsafe, чтобы:Unsafe — это как ядро Java-хакерства. У него огромная сила, но и риск.Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8👍7❤4😈3😇1
☕️ JDK 24 ускоряет Java-бэкенд: от виртуальных потоков до операций с FFM
Нашёл одну свежую и реально интересную статью — обзор Performance Improvements in JDK 24 от Inside.java (март 2025). В ней рассказывается о конкретных улучшениях, которые уже влияют на скорость приложений.
В статье вы найдёте:
📌 Оптимизация «bulk operations» в Foreign Function & Memory API — быстрее копирование и заполнение сегментов
📌 MergeStore в JIT — меньше операций записи, выше скорость работы с массивами
📌 Ускоренный startup через скрытые классы для конкатенации строк
📌 +27 % ускорения хеширования с SHA‑3
📌 Доработки виртуальных потоков: снятие pinning, лучшая синхронизация
📌 Что полезного для разработчиков: всё это работает «из коробки» — без переписывания кода
📌 Как это помогает писать код лучше: меньше задержек, быстрее прод, внимание разработчика уходит в логику, а не оптимизацию
➡️ Читайте и наслаждайтесь
🗣️ JDK‑24 — это не просто новая версия, а реальный прирост скорости для вашего продакшена.
🤩 Java Фишки и трюки || #Cтатья
Нашёл одну свежую и реально интересную статью — обзор Performance Improvements in JDK 24 от Inside.java (март 2025). В ней рассказывается о конкретных улучшениях, которые уже влияют на скорость приложений.
В статье вы найдёте:
Please open Telegram to view this post
VIEW IN TELEGRAM
❤9👍7👏2
🧩 Marker + Default methods: интерфейсы как конфигурация, без аннотаций и свитчей
Ты можешь использовать интерфейсы не как API, а как декларативную конфигурацию — через маркер + дефолтные методы. Без if-else, без флагов, без switch.
📛 Маркер как флаг
➡️ Никакой логики, просто метка. Если класс его реализует — значит, он отлаживаемый.
💡 Теперь достаточно
➡️ Никаких
🛠 Дефолтные методы — поведение по умолчанию
Ты получаешь “конфигурацию по умолчанию”, которую можно переопределить:
➡️ Без config-файлов, без if (instanceof) — всё в типе.
📦 Конфигурация как набор интерфейсов
➡️ И теперь просто пишешь:
➡️ Тип сам диктует поведение. Без логики — просто наличие интерфейса.
📚 Даже enum можно конфигурировать
➡️ Enum + интерфейс = мощная типовая декларация.
🗣️ Запомни: Marker + Default methods = тип как конфигурация. Ты пишешь код, который читает сам себя. Поведение не через данные, а через тип.Меньше if, меньше флагов, больше ясности.
Ты можешь использовать интерфейсы не как API, а как декларативную конфигурацию — через маркер + дефолтные методы. Без if-else, без флагов, без switch.
📛 Маркер как флаг
public interface Debuggable {} // пустой интерфейсpublic class Service implements Debuggable {}instanceof:void log(Object o) {
if (o instanceof Debuggable) {
System.out.println("🐞 Включаем отладку");
}
}.isDebug(), никаких аннотаций — только тип.public interface HasTimeout {
default int getTimeout() {
return 1000; // мс
}
}Ты получаешь “конфигурацию по умолчанию”, которую можно переопределить:
public class FastRequest implements HasTimeout {
@Override
public int getTimeout() {
return 100;
}
}
public class NormalRequest implements HasTimeout {
// будет 1000 по умолчанию
}void send(HasTimeout req) {
System.out.println("⌛️ Таймаут: " + req.getTimeout());
}public interface RequiresAuth {
default boolean isAuthRequired() {
return true;
}
}
public interface ReturnsJson {
default String contentType() {
return "application/json";
}
}public class ApiCall implements RequiresAuth, ReturnsJson {}void handle(Object call) {
if (call instanceof RequiresAuth auth && auth.isAuthRequired()) {
System.out.println("🔐 Проверка токена");
}
if (call instanceof ReturnsJson rj) {
System.out.println("📤 JSON-ответ: " + rj.contentType());
}
}public interface Critical {}
public enum Action implements Critical {
DELETE_ALL, RESET_DB
}void execute(Enum<?> action) {
if (action instanceof Critical) {
System.out.println("🚨 ВНИМАНИЕ: опасная операция");
} else {
System.out.println("✅ Безопасно");
}
}Please open Telegram to view this post
VIEW IN TELEGRAM
🔥16❤3👍3