В Java цикл for-each позволяет перебирать элементы массивов, коллекций и других итерируемых объектов без необходимости использовать индексы или итераторы. Однако, для того чтобы вы могли использовать for-each для перебора элементов своего собственного класса, этот класс должен реализовать интерфейс
В результате можно использовать for-each для перебора элементов этого класса, как если бы это был обычный массив или коллекция.
Вы можете адаптировать этот пример для своих собственных классов, реализуя интерфейс
Iterable и предоставить метод iterator(), возвращающий объект, реализующий интерфейс Iterator.В результате можно использовать for-each для перебора элементов этого класса, как если бы это был обычный массив или коллекция.
Вы можете адаптировать этот пример для своих собственных классов, реализуя интерфейс
Iterable и предоставив соответствующий итератор, чтобы использовать for-each для вашего класса.👍5❤3👨💻2
Дан список людей с именем и городом проживания. Нужно сгруппировать их по городам.
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
record Person(String name, String city) {}
public class StreamExample {
public static void main(String[] args) {
List<Person> people = List.of(
new Person("Alice", "New York"),
new Person("Bob", "Los Angeles"),
new Person("Charlie", "New York"),
new Person("David", "Los Angeles"),
new Person("Edward", "San Francisco")
);
Map<String, List<Person>> peopleByCity = people.stream()
.collect(Collectors.groupingBy(Person::city));
peopleByCity.forEach((city, peopleInCity) -> {
System.out.println(city + ": " + peopleInCity.stream()
.map(Person::name)
.collect(Collectors.joining(", ")));
});
// Вывод:
// San Francisco: Edward
// New York: Alice, Charlie
// Los Angeles: Bob, David
}
}
#java #stream #grouping
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍14🔥4❤3
В микросервисной архитектуре наблюдаемость — не роскошь, а умение выжить в проде. Как сделать качественный мониторинг без затратных решений? Ответ в новой статье от Anderson Kuntz Meurer.
@RestController к метрикам — HTTP‑статы, latency, ошибки.Please open Telegram to view this post
VIEW IN TELEGRAM
❤2
Хочешь встроить JavaScript в Java-приложение?
Без браузера, без WebView, просто для вычислений, шаблонов, скриптов или конфигов?
Это возможно — через встроенные скриптовые движки. Работает с JDK 8+, на проде, без зависимостей (или с GraalVM).
Java включает JS-движок (Nashorn до Java 14), а после — можно подключить GraalVM JavaScript.
Через
javax.script.ScriptEngine ты можешь:import javax.script.*;
public class Demo {
public static void main(String[] args) throws Exception {
ScriptEngine engine = new ScriptEngineManager().getEngineByName("javascript");
engine.eval("print('Привет из JavaScript');");
}
}
engine.put("name", "Neo");
engine.eval("print('Hello, ' + name);"); // Hello, NeoТы можешь прокидывать данные из Java в JS — и наоборот.
engine.eval("function add(a, b) { return a + b; }");
Invocable inv = (Invocable) engine;
Object result = inv.invokeFunction("add", 5, 7);
System.out.println(result); // 12String expr = "price * qty + tax";
Bindings vars = engine.createBindings();
vars.put("price", 100);
vars.put("qty", 2);
vars.put("tax", 50);
Object result = engine.eval(expr, vars);
System.out.println(result); // 250
Очень удобно для настройки расчётов пользователем без пересборки кода.
<dependency>
<groupId>org.graalvm.js</groupId>
<artifactId>js</artifactId>
<version>23.1.1</version>
</dependency>
Context context = Context.create("js");
Value result = context.eval("js", "2 + 2");
System.out.println(result.asInt()); // 4GraalVM даёт современный JS с поддержкой всего ES6+.
Хочешь дать пользователю конфиги на JS? Или динамически описывать поведение? Или быстро собрать вычислитель формул?Ты можешь запускать JavaScript напрямую в JVM — просто, безопасно и эффективно.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤8🔥4🗿1
Посты на какие темы вы хотели бы увидеть на нашем канале? Пишите в комметариях.
❤10
enum-ах — антипаттерн, который работаетChain of Responsibility — это когда у тебя есть цепочка проверок или действий, которые обрабатываются по очереди, пока не будет «готово» или «отказ».
В Java обычно это: интерфейс + куча обработчиков.
Но можно сделать проще: на `enum` с абстрактными методами.
enum UserValidator {
CHECK_NAME {
boolean validate(User u) {
return u.name != null && !u.name.trim().isEmpty();
}
},
CHECK_AGE {
boolean validate(User u) {
return u.age >= 18;
}
},
CHECK_EMAIL {
boolean validate(User u) {
return u.email != null && u.email.contains("@");
}
};
abstract boolean validate(User u);
}Каждый
enum — это как мини-обработчик.Ты прямо внутри перечисления задаёшь поведение.
Код не размазан по 10 классам и не требует интерфейсов.
User user = new User("Neo", 30, "neo@matrix.io");
boolean valid = Arrays.stream(UserValidator.values())
.allMatch(v -> v.validate(user));true — пользователь валиден.Arrays.stream(UserValidator.values())
.filter(v -> !v.validate(user))
.forEach(v -> System.out.println("⛔️ Ошибка в: " + v.name()));
Optional<UserValidator> failed = Arrays.stream(UserValidator.values())
.filter(v -> !v.validate(user))
.findFirst();
if (failed.isPresent()) {
System.out.println("Провал на шаге: " + failed.get().name());
}
class User {
String name;
int age;
String email;
User(String name, int age, String email) {
this.name = name;
this.age = age;
this.email = email;
}
}enum с методами — это рабочий компромисс, когда не хочется поднимать тяжёлый Chain of Responsibility.Просто, читаемо, удобно. Особенно для валидаций, фильтров, конвертаций и тестов.Please open Telegram to view this post
VIEW IN TELEGRAM
1❤17🤔5❤🔥1👨💻1
Media is too big
VIEW IN TELEGRAM
Это видео показывает, как создать простой графический калькулятор на Java с использованием Swing. Подойдёт новичкам: шаг за шагом разбирается создание кнопок, полей ввода и обработка событий. Отличный старт для изучения GUI-разработки на Java.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3❤2
Java позволяет создавать интерфейсы без методов. Они ничего не делают.
Но если ты дашь этот интерфейс классу — ты отмечаешь объект как "особенный".
Это и есть ghost interface — маркерный интерфейс, флаг через тип.
📛 Пример: метка для доступа
public interface AdminAccess {
// ничего не требует, просто существует
}public class User {}
public class AdminUser extends User implements AdminAccess {}AdminUser не обязан ничего переопределять.Но теперь ты можешь понять, что это админ, просто глядя на тип.
instanceofvoid check(User u) {
if (u instanceof AdminAccess) {
System.out.println("✅ Доступ разрешён");
} else {
System.out.println("⛔️ Нет прав");
}
}Смотри, тебе нужно различать обычные запросы и те, что требуют валидации.
Не хочешь городить
if (request.needsValidation())? — решается в один тип.public interface RequiresValidation {}
public class LoginRequest implements RequiresValidation {}
public class PingRequest {}void handle(Object req) {
if (req instanceof RequiresValidation) {
System.out.println("🔍 Проверка данных");
} else {
System.out.println("🚀 Без валидации");
}
}💾 Другой кейс — запрет на сохранение
public interface ReadOnly {}
public class ConfigFile implements ReadOnly {}
public class LogFile {}void save(Object file) {
if (file instanceof ReadOnly) {
throw new RuntimeException("❌ Это read-only");
}
System.out.println("💾 Сохраняем файл...");
}boolean readonly, без .getPermissions() — просто instanceof.public interface JsonSerializable {}
public interface RequiresAuth {}
public class ApiRequest implements JsonSerializable, RequiresAuth {}if (req instanceof JsonSerializable) {
System.out.println("📤 Преобразуем в JSON");
}
if (req instanceof RequiresAuth) {
System.out.println("🔐 Проверяем токен");
}public interface Internal {}
public enum Command implements Internal {
REBOOT, SHUTDOWN
}void dispatch(Enum<?> cmd) {
if (cmd instanceof Internal) {
System.out.println("🔐 Внутренняя команда");
} else {
System.out.println("🌍 Публичная");
}
}instanceof.Пиши логику по типу, не по данным.Please open Telegram to view this post
VIEW IN TELEGRAM
🔥10👍6❤3👨💻3
.jar и следить за ним изнутриНужно посмотреть, какие классы грузятся в рантайме?
Или вставить лог прямо в чужой метод, не трогая исходник?
Java Agent запускается до `main()` и даёт доступ ко всему, что загружается в JVM.
public class SpyAgent {
public static void premain(String args, Instrumentation inst) {
System.out.println("👁 Агент стартовал");
}
}premain() будет вызван раньше `main()` обычного приложения.Параметры:
args — аргументы, переданные агентуInstrumentation — интерфейс для перехвата и изменения классовinst.addTransformer(new ClassFileTransformer() {
@Override
public byte[] transform(ClassLoader loader, String className,
Class<?> classBeingRedefined, ProtectionDomain domain,
byte[] classfileBuffer) {
if (className.contains("Service")) {
System.out.println("🎯 Загружается: " + className);
}
return null;
}
});Если хочешь, можешь их изменить и отдать «новую» версию класса.
Создаём
MANIFEST.MF:Premain-Class: SpyAgent
Can-Redefine-Classes: true
Собираем
.jar с этим манифестом:jar cmf MANIFEST.MF spy-agent.jar SpyAgent.class
java -javaagent:spy-agent.jar -jar victim.jar
premain(), и только потом запустит main() из victim.jar.🔁 Пример: вставляем поведение с ByteBuddy
new AgentBuilder.Default()
.type(named("com.example.Target"))
.transform((builder, type, cl, module) ->
builder.method(named("process"))
.intercept(MethodDelegation.to(LoggerInterceptor.class))
).installOn(inst);
public class LoggerInterceptor {
@RuntimeType
public static void intercept() {
System.out.println("📦 Метод process() вызван");
}
}Ты не меняешь исходник — всё происходит на лету, при загрузке.
spy-agent/
├── SpyAgent.java
├── LoggerInterceptor.java
├── MANIFEST.MF
.jar.Please open Telegram to view this post
VIEW IN TELEGRAM
❤8👍6👨💻5
Хочешь подменить метод в чужом классе, не трогая исходники? Или генерировать новый класс динамически? В Java это делается через байткод-инжиниринг — на уровне JVM-инструкций.
ASM: низкоуровневый контроль
public class AddPrintAdapter extends MethodVisitor {
public AddPrintAdapter(MethodVisitor mv) {
super(Opcodes.ASM9, mv);
}
@Override
public void visitCode() {
super.visitCode();
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
mv.visitLdcInsn("🔥 Метод вызван");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream",
"println", "(Ljava/lang/String;)V", false);
}
}System.out.println() в начало любого метода. Работа с visitCode() — прямой доступ к байткоду.ClassReader reader = new ClassReader("com.example.Foo");
ClassWriter writer = new ClassWriter(reader, 0);
ClassVisitor visitor = new ClassVisitor(Opcodes.ASM9, writer) {
@Override
public MethodVisitor visitMethod(int access, String name, String desc,
String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
if (name.equals("run")) {
return new AddPrintAdapter(mv);
}
return mv;
}
};
reader.accept(visitor, 0);
byte[] modifiedClass = writer.toByteArray();run, встроили println() — и получили новый .class.new ByteBuddy()
.subclass(Object.class)
.name("com.example.DynamicClass")
.defineMethod("hello", void.class, Modifier.PUBLIC)
.intercept(MethodDelegation.to(HelloInterceptor.class))
.make()
.load(ClassLoader.getSystemClassLoader());
hello() прямо во время выполнения. Без .java-файлов, всё в памяти.public class HelloInterceptor {
@RuntimeType
public static void intercept() {
System.out.println("👋 Hello from dynamic method");
}
}hello() будет выполнен этот перехватчик. Никаких аннотаций, никакой магии — только Java.Please open Telegram to view this post
VIEW IN TELEGRAM
👨💻8👍4
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