История технологии сегодня — 25 мая
ℹ️ Кто родился в этот день
Джек Стейнбергер (англ. Jack Steinberger; 25 мая 1921, Бад-Киссинген, Германия — 12 декабря 2020, Женева, Швейцария) — американский физик, известный работами по физике элементарных частиц, нобелевский лауреат (1988) за открытие и исследование мюонного нейтрино и антинейтрино.
Пи́тер Зе́еман (нид. Pieter Zeeman; 25 мая 1865, Зоннемайре, Нидерланды — 9 октября 1943, Амстердам) — нидерландский физик, лауреат Нобелевской премии по физике 1902 года (совместно с Хендриком Лоренцем) за открытие и теоретическое объяснение расщепления спектральных линий в магнитном поле (эффекта Зеемана).
Аугу́сто Ульдери́ко Сикаре́ (исп. Augusto Ulderico Cicaré, 25 мая 1937 — 26 января 2022) — аргентинский изобретатель, инженер и авиаконструктор, основатель и первый президент компании Cicaré Helicópteros S.A. Сикаре создал свой первый вертолёт Cicaré CH-1 в 1958 году. CH-1 был первым вертолётом, разработанным в Южной Америке. В 1972 году был представлен третий летательный аппарат — Cicaré CH-3. В конце 1960-х изобретатель разработал 4-тактный V-образный двигатель для автомобилей DKW, протестированный аргентинским гонщиком Хуаном Мануэлем Фанхио. Также была разработана спортивная версия, но банкротство DKW привело к закрытию проекта. Сикаре разработал прототипы вертолётов итальянской фирмы «Heli-Sport» CH-7 Angel и 2-местный CH-7 Kompress, совместно с Деннисом Феттерсом Mini-500, Voyager-500.
🌐 Знаковые события
1939 — первые в стране испытания системы автоматического взлёта и посадки тяжёлого самолёта ТБ-1.
#Biography #Birth_Date #Events #25мая
Джек Стейнбергер (англ. Jack Steinberger; 25 мая 1921, Бад-Киссинген, Германия — 12 декабря 2020, Женева, Швейцария) — американский физик, известный работами по физике элементарных частиц, нобелевский лауреат (1988) за открытие и исследование мюонного нейтрино и антинейтрино.
Пи́тер Зе́еман (нид. Pieter Zeeman; 25 мая 1865, Зоннемайре, Нидерланды — 9 октября 1943, Амстердам) — нидерландский физик, лауреат Нобелевской премии по физике 1902 года (совместно с Хендриком Лоренцем) за открытие и теоретическое объяснение расщепления спектральных линий в магнитном поле (эффекта Зеемана).
Аугу́сто Ульдери́ко Сикаре́ (исп. Augusto Ulderico Cicaré, 25 мая 1937 — 26 января 2022) — аргентинский изобретатель, инженер и авиаконструктор, основатель и первый президент компании Cicaré Helicópteros S.A. Сикаре создал свой первый вертолёт Cicaré CH-1 в 1958 году. CH-1 был первым вертолётом, разработанным в Южной Америке. В 1972 году был представлен третий летательный аппарат — Cicaré CH-3. В конце 1960-х изобретатель разработал 4-тактный V-образный двигатель для автомобилей DKW, протестированный аргентинским гонщиком Хуаном Мануэлем Фанхио. Также была разработана спортивная версия, но банкротство DKW привело к закрытию проекта. Сикаре разработал прототипы вертолётов итальянской фирмы «Heli-Sport» CH-7 Angel и 2-местный CH-7 Kompress, совместно с Деннисом Феттерсом Mini-500, Voyager-500.
1939 — первые в стране испытания системы автоматического взлёта и посадки тяжёлого самолёта ТБ-1.
#Biography #Birth_Date #Events #25мая
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
[Совет по Java #041]
Тема: Integer кэширует значения от -128 до 127.
Проблема: JVM кэширует объекты
Решение: Всегда сравнивайте объекты
Объяснение: Кэш
Оператор
Для смешанного сравнения
#Java #советы
Тема: Integer кэширует значения от -128 до 127.
Проблема: JVM кэширует объекты
Integer для небольшого диапазона значений (по умолчанию от -128 до 127). При автоупаковке (autoboxing) или вызове Integer.valueOf() для числа в этом диапазоне возвращается один и тот же объект из кэша. Для чисел вне диапазона каждый раз создается новый объект. Использование оператора == для сравнения Integer проверяет равенство ссылок, а не значений.Решение: Всегда сравнивайте объекты
Integer, Long, Short, Byte, Character через метод equals() или используйте примитивные типы (int). Для безопасного сравнения с возможным null применяйте Objects.equals(a, b). Кэш можно расширить параметром -XX:AutoBoxCacheMax=size, но это не решает концептуальной проблемы. Для Long кэш работает только для значений от -128 до 127, для Character — от 0 до 127.public class IntegerCache {
public static void main(String[] args) {
//В пределах кэша (-128..127)
Integer a1 = 100;
Integer b1 = 100;
System.out.println("100 == 100: " + (a1 == b1)); // true (один объект)
System.out.println("100 equals 100: " + a1.equals(b1)); // true
//Вне кэша
Integer a2 = 200;
Integer b2 = 200;
System.out.println("200 == 200: " + (a2 == b2)); // false (разные объекты!)
System.out.println("200 equals 200: " + a2.equals(b2)); // true
//Разные способы создания
Integer a3 = Integer.valueOf(127); // из кэша
Integer b3 = new Integer(127); // новый объект (deprecated)
System.out.println("valueOf(127) == new Integer(127): " + (a3 == b3)); // false
//Опасность в коллекциях
var map = new java.util.HashMap<Integer, String>();
map.put(200, "value");
System.out.println("map.get(200): " + map.get(200)); // работает, т.к. внутри equals
//Правильное сравнение
Integer x = 300;
Integer y = 300;
if (x.equals(y)) {
System.out.println("300 equals 300 — корректно");
}
//null-safe сравнение
Integer nullable = null;
System.out.println("Objects.equals: " + Objects.equals(nullable, 300));
}
}Объяснение: Кэш
Integer реализован в методе Integer.valueOf() и используется при автоупаковке. Его размер можно настроить, но полагаться на кэш — плохая практика. Оператор
== для объектов сравнивает ссылки, и для чисел вне диапазона кэша они гарантированно разные. Проблема усугубляется тем, что код работает в разработке (где числа обычно маленькие) и ломается в production (где диапазон шире). equals() сравнивает значения и всегда работает корректно. Для смешанного сравнения
Integer и int происходит распаковка (unboxing), и == работает правильно: Integer a = 200; int b = 200; a == b будет true, потому что a распаковывается в int. Но для единообразия всегда используйте equals().#Java #советы
👍5
Что выведет код?
#Tasks
public class Task250526 {
public static void main(String[] args) {
Short a = 100;
Short b = 100;
Short c = 200;
Short d = 200;
System.out.println(a == b);
System.out.println(c == d);
System.out.println(c.equals(d));
}
}#Tasks
👍3
Варианты ответа:
Anonymous Quiz
41%
true true true
47%
true false true
12%
false false true
0%
false true false
👍4
Что такое ThreadFactory? 🤓
Ответ:
ThreadFactory — это интерфейс для создания новых потоков с возможностью кастомизации.
Единственный метод: Thread newThread(Runnable r). Используется в ExecutorService (например, Executors.newFixedThreadPool(10, myThreadFactory)).
Позволяет задавать: имена потоков (для упрощения отладки), приоритеты, демонический статус, UncaughtExceptionHandler.
Хорошая практика — создавать потоки с понятными именами (например, "db-pool-%d"). Утилита Executors.defaultThreadFactory() возвращает стандартную фабрику.
#собеседование
Ответ:
ThreadFactory — это интерфейс для создания новых потоков с возможностью кастомизации.
Единственный метод: Thread newThread(Runnable r). Используется в ExecutorService (например, Executors.newFixedThreadPool(10, myThreadFactory)).
Позволяет задавать: имена потоков (для упрощения отладки), приоритеты, демонический статус, UncaughtExceptionHandler.
Хорошая практика — создавать потоки с понятными именами (например, "db-pool-%d"). Утилита Executors.defaultThreadFactory() возвращает стандартную фабрику.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
История технологии сегодня — 26 мая
ℹ️ Кто родился в этот день
Бори́с Серге́евич Петропа́вловский (14 (26) мая 1898, Курск — 6 ноября 1933, Ленинград) — российский и советский военный инженер-артиллерист, участник Первой мировой и Гражданской войн, один из организаторов разработок ракетной техники в СССР, руководитель Газодинамической лаборатории, главный инженер Ленинградского отделения Реактивного научно-исследовательского института (РНИИ). Именем Б. С. Петропавловского был назван кратер на обратной стороне Луны.
🌐 Знаковые события
1868 — Альфред Нобель подал заявку на американский патент на изобретение динамита.
#Biography #Birth_Date #Events #26мая
Бори́с Серге́евич Петропа́вловский (14 (26) мая 1898, Курск — 6 ноября 1933, Ленинград) — российский и советский военный инженер-артиллерист, участник Первой мировой и Гражданской войн, один из организаторов разработок ракетной техники в СССР, руководитель Газодинамической лаборатории, главный инженер Ленинградского отделения Реактивного научно-исследовательского института (РНИИ). Именем Б. С. Петропавловского был назван кратер на обратной стороне Луны.
1868 — Альфред Нобель подал заявку на американский патент на изобретение динамита.
#Biography #Birth_Date #Events #26мая
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Раздел 9. Исключения, логирование, отладка
Глава 2. Логирование (Logging)
MDC (Mapped Diagnostic Context) – привязка контекстной информации к логам
В многопоточном серверном приложении один и тот же логгер обрабатывает запросы от множества клиентов параллельно. Стандартный вывод логов представляет собой линейную последовательность сообщений от разных потоков, где запросы перемешаны хаотично. Без дополнительного контекста невозможно отследить, какие сообщения относятся к конкретному пользователю или HTTP-запросу.
Рассмотрим типичный лог без MDC:
По имени потока можно различить запросы, но имена потоков переиспользуются пулом и не несут бизнес-семантики. Для анализа проблемы конкретного пользователя или запроса требуется ручной поиск по временным меткам и косвенным признакам.
Архитектура MDC
MDC — это карта ключ-значение, привязанная к текущему потоку выполнения через
Основные операции:
Контекст MDC автоматически подставляется в лог-сообщения через conversion specifier
Базовое использование
Конфигурация Logback для вывода MDC:
Результат:
Все сообщения, выведенные в рамках одного запроса, содержат идентификаторы пользователя и заказа. Это позволяет фильтровать логи grep-ом или в системах агрегации по конкретным значениям MDC.
#Java #для_новичков #beginner #logging #Log4j2 #Logback #SLF4J
Глава 2. Логирование (Logging)
MDC (Mapped Diagnostic Context) – привязка контекстной информации к логам
В многопоточном серверном приложении один и тот же логгер обрабатывает запросы от множества клиентов параллельно. Стандартный вывод логов представляет собой линейную последовательность сообщений от разных потоков, где запросы перемешаны хаотично. Без дополнительного контекста невозможно отследить, какие сообщения относятся к конкретному пользователю или HTTP-запросу.
Рассмотрим типичный лог без MDC:
2024-01-15 10:23:14 [http-nio-8080-exec-3] INFO OrderService - Processing order
2024-01-15 10:23:14 [http-nio-8080-exec-1] INFO PaymentService - Charging card
2024-01-15 10:23:14 [http-nio-8080-exec-3] WARN InventoryService - Low stock
2024-01-15 10:23:15 [http-nio-8080-exec-2] ERROR OrderService - Payment failed
По имени потока можно различить запросы, но имена потоков переиспользуются пулом и не несут бизнес-семантики. Для анализа проблемы конкретного пользователя или запроса требуется ручной поиск по временным меткам и косвенным признакам.
Архитектура MDC
MDC — это карта ключ-значение, привязанная к текущему потоку выполнения через
ThreadLocal. SLF4J предоставляет статический API класса org.slf4j.MDC, который делегирует реализации (Logback или Log4j2) фактическое хранение контекста. Каждый поток имеет собственную изолированную копию MDC, что гарантирует отсутствие перекрестного загрязнения между параллельными запросами.Основные операции:
MDC.put(String key, String value) — добавляет пару ключ-значение в контекст текущего потокаMDC.get(String key) — извлекает значение по ключуMDC.remove(String key) — удаляет конкретный ключMDC.clear() — очищает весь контекст текущего потокаКонтекст MDC автоматически подставляется в лог-сообщения через conversion specifier
%X{key} в PatternLayout.Базовое использование
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
public class OrderService {
private static final Logger logger = LoggerFactory.getLogger(OrderService.class);
public void processOrder(String orderId, String userId) {
// Установка контекста в начале операции
MDC.put("orderId", orderId);
MDC.put("userId", userId);
MDC.put("operation", "processOrder");
try {
logger.info("Starting order processing");
validateOrder(orderId);
chargePayment(orderId, userId);
updateInventory(orderId);
logger.info("Order processing completed");
} catch (Exception e) {
logger.error("Order processing failed", e);
throw e;
} finally {
// Обязательная очистка контекста
MDC.clear();
}
}
}
Конфигурация Logback для вывода MDC:
<property name="LOG_PATTERN"
value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} [%X{userId}] [%X{orderId}] - %msg%n"/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${LOG_PATTERN}</pattern>
</encoder>
</appender>
Результат:
2024-01-15 10:23:14.123 [http-nio-8080-exec-3] INFO OrderService [user-42] [order-789] - Starting order processing
2024-01-15 10:23:14.145 [http-nio-8080-exec-3] INFO PaymentService [user-42] [order-789] - Charging payment
2024-01-15 10:23:14.167 [http-nio-8080-exec-3] INFO OrderService [user-42] [order-789] - Order processing completed
Все сообщения, выведенные в рамках одного запроса, содержат идентификаторы пользователя и заказа. Это позволяет фильтровать логи grep-ом или в системах агрегации по конкретным значениям MDC.
#Java #для_новичков #beginner #logging #Log4j2 #Logback #SLF4J
👍1
MDC в веб-приложении: Servlet Filter
В веб-приложении контекст запроса устанавливается в фильтре сервлетов и очищается при завершении обработки. Это гарантирует, что все компоненты, участвующие в обработке запроса — контроллеры, сервисы, репозитории — имеют доступ к единому контексту без явной передачи параметров через сигнатуры методов.
Ключевой момент:
Конфигурация Logback с MDC:
#Java #для_новичков #beginner #logging #Log4j2 #Logback #SLF4J
В веб-приложении контекст запроса устанавливается в фильтре сервлетов и очищается при завершении обработки. Это гарантирует, что все компоненты, участвующие в обработке запроса — контроллеры, сервисы, репозитории — имеют доступ к единому контексту без явной передачи параметров через сигнатуры методов.
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.UUID;
@Component
public class LoggingContextFilter extends OncePerRequestFilter {
private static final String REQUEST_ID_HEADER = "X-Request-Id";
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
// Генерация или извлечение идентификатора запроса
String requestId = request.getHeader(REQUEST_ID_HEADER);
if (requestId == null || requestId.isBlank()) {
requestId = UUID.randomUUID().toString();
}
// Извлечение контекста аутентификации
String userId = extractUserId(request);
String sessionId = request.getSession(false) != null ?
request.getSession().getId() : "anonymous";
// Установка MDC
MDC.put("requestId", requestId);
MDC.put("userId", userId != null ? userId : "anonymous");
MDC.put("sessionId", sessionId);
MDC.put("method", request.getMethod());
MDC.put("uri", request.getRequestURI());
// Проброс requestId в ответ для клиентской трассировки
response.setHeader(REQUEST_ID_HEADER, requestId);
try {
filterChain.doFilter(request, response);
} finally {
// Очистка обязательна, иначе поток из пула вернется с загрязненным контекстом
MDC.clear();
}
}
private String extractUserId(HttpServletRequest request) {
// Извлечение из SecurityContext или токена
return SecurityContextHolder.getContext().getAuthentication() != null ?
SecurityContextHolder.getContext().getAuthentication().getName() : null;
}
}
Ключевой момент:
MDC.clear() находится в блоке finally, что гарантирует очистку даже при исключении. Без этого поток из пула вернется с загрязненным MDC, и следующий запрос, обработанный этим потоком, унаследует чужой контекст.Конфигурация Logback с MDC:
<property name="LOG_PATTERN"
value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} [%X{requestId}] [%X{userId}] [%X{method} %X{uri}] - %msg%n"/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${LOG_PATTERN}</pattern>
</encoder>
</appender>
#Java #для_новичков #beginner #logging #Log4j2 #Logback #SLF4J
👍3
Распределенная трассировка: propagation MDC
В микросервисной архитектуре запрос проходит через несколько сервисов. Для сквозной трассировки идентификатор запроса должен передаваться между сервисами. Это достигается через HTTP-заголовки или сообщения брокера.
Принимающий сервис извлекает
MDC и асинхронное выполнение
Решение — явное копирование контекста:
В Spring для
MDC.clear() vs MDC.remove()
JSON-формат и MDC
При структурированном логировании в JSON MDC-значения автоматически включаются как отдельные поля:
Результат:
Это позволяет системам агрегации индексировать MDC-поля и выполнять точные фильтры без парсинга строк.
#Java #для_новичков #beginner #logging #Log4j2 #Logback #SLF4J
В микросервисной архитектуре запрос проходит через несколько сервисов. Для сквозной трассировки идентификатор запроса должен передаваться между сервисами. Это достигается через HTTP-заголовки или сообщения брокера.
@Service
public class OrderClient {
private final RestTemplate restTemplate;
public OrderDto getOrder(String orderId) {
String requestId = MDC.get("requestId");
HttpHeaders headers = new HttpHeaders();
headers.set("X-Request-Id", requestId); // Propagation
HttpEntity<Void> entity = new HttpEntity<>(headers);
ResponseEntity<OrderDto> response = restTemplate.exchange(
"http://order-service/orders/" + orderId,
HttpMethod.GET,
entity,
OrderDto.class
);
return response.getBody();
}
}
Принимающий сервис извлекает
X-Request-Id из заголовка и устанавливает в свой MDC через тот же фильтр. Таким образом, все логи по цепочке запросов содержат единый идентификатор, позволяя восстановить полный путь в системах агрегации.MDC и асинхронное выполнение
ThreadLocal привязка MDC создает проблему при асинхронном выполнении: при передаче задачи в другой поток (через CompletableFuture, @Async, пул потоков) контекст MDC не переносится автоматически.// Антипаттерн: MDC теряется при асинхронном выполнении
CompletableFuture.runAsync(() -> {
// MDC пуст — задача выполняется в другом потоке
logger.info("Async task"); // Нет requestId, userId
});
Решение — явное копирование контекста:
Map<String, String> contextMap = MDC.getCopyOfContextMap();
CompletableFuture.runAsync(() -> {
MDC.setContextMap(contextMap); // Восстановление контекста
try {
logger.info("Async task with context");
processAsync();
} finally {
MDC.clear();
}
});
В Spring для
@Async методов можно использовать TaskDecorator:@Configuration
public class AsyncConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setTaskDecorator(new MdcTaskDecorator());
executor.initialize();
return executor;
}
}
public class MdcTaskDecorator implements TaskDecorator {
@Override
public Runnable decorate(Runnable runnable) {
Map<String, String> contextMap = MDC.getCopyOfContextMap();
return () -> {
try {
MDC.setContextMap(contextMap);
runnable.run();
} finally {
MDC.clear();
}
};
}
}
MDC.clear() vs MDC.remove()
MDC.clear() удаляет все ключи из контекста текущего потока. Это предпочтительный метод при завершении обработки запроса, так как гарантирует полную очистку.MDC.remove(String key) удаляет конкретный ключ. Используется, когда часть контекста больше не нужна, но остальная должна сохраняться. Однако в большинстве сценариев проще и безопаснее использовать clear() в блоке finally.JSON-формат и MDC
При структурированном логировании в JSON MDC-значения автоматически включаются как отдельные поля:
<encoder class="net.logstash.logback.encoder.LogstashEncoder"/>
Результат:
{
"@timestamp": "2024-01-15T10:23:14.123+00:00",
"message": "Order processing completed",
"logger_name": "com.example.OrderService",
"level": "INFO",
"thread_name": "http-nio-8080-exec-3",
"requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"userId": "user-42",
"sessionId": "session-xyz",
"method": "POST",
"uri": "/api/orders"
}Это позволяет системам агрегации индексировать MDC-поля и выполнять точные фильтры без парсинга строк.
#Java #для_новичков #beginner #logging #Log4j2 #Logback #SLF4J
👍5
Что выведет код?
#Tasks
import com.fasterxml.jackson.databind.ObjectMapper;
public class Task260526 {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
String json = "{\"name\":\"Buddy\",\"breed\":\"Labrador\"}";
Animal260526 animal = mapper.readValue(json, Animal260526.class);
System.out.println(animal.getClass().getSimpleName());
}
}
interface Animal260526 {
String getName();
}
class Dog260526 implements Animal260526 {
public String name;
public String breed;
public Dog260526() {}
@Override
public String getName() { return name; }
}
#Tasks
👍2
👍2
Что такое short-circuit операторы? 🤓
Ответ:
Логические операторы && (И) и || (ИЛИ) являются короткозамкнутыми (short-circuit).
Это означает, что второй операнд вычисляется только при необходимости.
Для &&: если левый операнд false, всё выражение false, правый не вычисляется.
Для ||: если левый операнд true, всё выражение true, правый не вычисляется.
Это позволяет безопасно писать: if (obj != null && obj.isValid()). В отличие от & и |, которые всегда вычисляют оба операнда.
#собеседование
Ответ:
Логические операторы && (И) и || (ИЛИ) являются короткозамкнутыми (short-circuit).
Это означает, что второй операнд вычисляется только при необходимости.
Для &&: если левый операнд false, всё выражение false, правый не вычисляется.
Для ||: если левый операнд true, всё выражение true, правый не вычисляется.
Это позволяет безопасно писать: if (obj != null && obj.isValid()). В отличие от & и |, которые всегда вычисляют оба операнда.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
История технологии сегодня — 27 мая
ℹ️ Кто родился в этот день
Джон Дуглас Кокрофт (англ. John Douglas Cockcroft; 27 мая 1897 — 18 сентября 1967) — британский физик-ядерщик, лауреат Нобелевской премии по физике за 1951 год «за исследовательскую работу по расщеплению атомных ядер с помощью искусственно ускоряемых атомных частиц», совместно с Эрнестом Уолтоном.
🌐 Знаковые события
1930 — Ричард Дрю запатентовал «прозрачную целлофановую липкую ленту» — скотч. Новинку использовали для защиты стекла автомашины при покраске.
1988 — компания Microsoft выпустила Windows 2.1x.
#Biography #Birth_Date #Events #27мая
Джон Дуглас Кокрофт (англ. John Douglas Cockcroft; 27 мая 1897 — 18 сентября 1967) — британский физик-ядерщик, лауреат Нобелевской премии по физике за 1951 год «за исследовательскую работу по расщеплению атомных ядер с помощью искусственно ускоряемых атомных частиц», совместно с Эрнестом Уолтоном.
1930 — Ричард Дрю запатентовал «прозрачную целлофановую липкую ленту» — скотч. Новинку использовали для защиты стекла автомашины при покраске.
1988 — компания Microsoft выпустила Windows 2.1x.
#Biography #Birth_Date #Events #27мая
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
[Совет по Java #042]
Тема:
Проблема: Метод
Если передан ключ, не являющийся
Решение: Для ключей, не реализующих
Объяснение: Сигнатура
При использовании лямбд с несколькими параметрами может потребоваться явное указание типа (как в примере
#Java #советы
Тема:
Comparator.comparing(Function) требует, чтобы ключ сравнения был Comparable.Проблема: Метод
Comparator.comparing(Function<? super T, ? extends U> keyExtractor) предполагает, что тип U (ключ, по которому выполняется сравнение) реализует интерфейс Comparable<U>. Если передан ключ, не являющийся
Comparable (например, пользовательский класс без реализации Comparable, или тип, который его не реализует), код не скомпилируется с ошибкой "inferred type does not conform to equality bounds".Решение: Для ключей, не реализующих
Comparable, используйте перегруженную версию Comparator.comparing(Function keyExtractor, Comparator keyComparator). Она принимает дополнительный компаратор для сравнения ключей. Также можно использовать Comparator.comparingInt, comparingLong, comparingDouble для примитивных типов, которые не требуют Comparable. public class ComparatorComparing {
static class Person {
String name;
int age;
LocalDate birthDate;
Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return name + "(" + age + ")";
}
}
// Класс без Comparable
static class ExternalId {
String prefix;
int number;
ExternalId(String prefix, int number) {
this.prefix = prefix;
this.number = number;
}
@Override
public String toString() {
return prefix + "-" + number;
}
}
public static void main(String[] args) {
List<Person> people = Arrays.asList(
new Person("Alice", 30),
new Person("Bob", 25),
new Person("Charlie", 35)
);
//Работает: String реализует Comparable
people.sort(Comparator.comparing(p -> p.name));
System.out.println("Sorted by name: " + people);
//Работает: int примитив через comparingInt
people.sort(Comparator.comparingInt(p -> p.age));
System.out.println("Sorted by age: " + people);
//Ошибка: ExternalId не реализует Comparable
List<ExternalId> ids = Arrays.asList(
new ExternalId("A", 10),
new ExternalId("B", 5),
new ExternalId("A", 20)
);
// ids.sort(Comparator.comparing(id -> id)); // не скомпилируется!
//Решение 1: явный компаратор для ключа
ids.sort(Comparator.comparing(
(ExternalId id) -> id.prefix,
Comparator.naturalOrder() // для строк
));
System.out.println("Sorted by prefix: " + ids);
//Решение 2: составной компаратор через thenComparing
ids.sort(Comparator
.comparing((ExternalId id) -> id.prefix)
.thenComparingInt(id -> id.number));
System.out.println("Sorted by prefix then number: " + ids);
//Решение 3: собственный компаратор для ключа
Comparator<ExternalId> byNumberDesc = Comparator.comparing(
(ExternalId id) -> id.number,
(n1, n2) -> n2 - n1 // обратный порядок
);
ids.sort(byNumberDesc);
System.out.println("Sorted by number desc: " + ids);
}
}Объяснение: Сигнатура
Comparator.comparing(Function keyExtractor) имеет ограничение <U extends Comparable<? super U>>, которое требует, чтобы тип ключа реализовывал Comparable. Это ограничение гарантирует, что для ключей существует "естественный порядок". Для ключей без естественного порядка (например, пользовательские типы, массивы, или типы с специфической логикой сравнения) необходимо предоставить компаратор явно.При использовании лямбд с несколькими параметрами может потребоваться явное указание типа (как в примере
(ExternalId id) -> id.prefix), чтобы компилятор мог вывести типы.#Java #советы
👍4
Что выведет код?
#Tasks
import java.util.*;
public class Task270526 {
public static void main(String[] args) {
List<Person> people = Arrays.asList(
new Person("Alice", 25),
new Person("Bob", 30),
new Person("Charlie", 20)
);
Comparator<Person> comparator = Comparator.comparing(p -> p.age);
people.sort(comparator);
System.out.println(people);
}
static class Person {
String name;
int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return name + ":" + age;
}
}
}
#Tasks
👍3
Варианты ответа:
Anonymous Quiz
10%
[Alice:25, Bob:30, Charlie:20]
75%
[Charlie:20, Alice:25, Bob:30]
15%
Ошибка компиляции
0%
Исключение ClassCastException
👍4
Что такое instance initializer (нестатический блок)? Как он работает? 🤓
Ответ:
Нестатический блок инициализации — это { ... } внутри класса, без ключевого слова static.
Он выполняется при создании каждого экземпляра, перед конструктором, но после вызова конструктора суперкласса.
Если есть несколько блоков, они выполняются в порядке объявления сверху вниз. Используется для общих инициализаций, которые нужны для всех конструкторов, или для инициализации анонимных классов.
Например: class A { { System.out.println("init"); } A() {...} }.
#собеседование
Ответ:
Нестатический блок инициализации — это { ... } внутри класса, без ключевого слова static.
Он выполняется при создании каждого экземпляра, перед конструктором, но после вызова конструктора суперкласса.
Если есть несколько блоков, они выполняются в порядке объявления сверху вниз. Используется для общих инициализаций, которые нужны для всех конструкторов, или для инициализации анонимных классов.
Например: class A { { System.out.println("init"); } A() {...} }.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
История технологии сегодня — 28 мая
ℹ️ Кто родился в этот день
Милутин Мила́нкович (28 мая 1879, Даль (ныне Хорватия) — 12 декабря 1958, Белград) — австро-венгерский, сербский гражданский инженер, климатолог, геофизик, астрофизик и популяризатор науки.
Известен теорией ледниковых периодов, подразумевающей, что из-за периодических изменений параметров своей орбиты Земля проходит через повторяющиеся ледниковые периоды, в настоящее время известные как циклы Миланковича. Кроме того, дал оценку климатическим условиям на других планетах земной группы. Милутин Миланкович также модифицировал юлианский календарь, разработал новоюлианский календарь.
Мариа́н Смолухо́вский (фон Смолан-Смолуховский, пол. Marian Smoluchowski; 28 мая 1872, Фордер-Брюль, близ Вены — 5 сентября 1917, Краков) — австро-венгерский физик-теоретик польского происхождения.
Уравнения Смолуховского, разработанные им теоретические основы и вычислительные методы стали фундаментом статистической физики и особенно важной сегодня её отрасли, называемой теорией стохастических процессов, развиваемой как физиками, так и математиками. Применения уравнений Смолуховского простираются от физики (как макроскопических, так и субатомных систем) и химии до биологии и технических наук. Многочисленны и практические применения модели Смолуховского, например — индустриальное очищение воды, коагуляция молока, возникновение гелевых барьеров, агрегация гранулоцитов, адгезия лейкоцитов, рост нанотрубок и многое другое.
🌐 Знаковые события
1742 — в Лондоне сооружён первый крытый плавательный бассейн.
#Biography #Birth_Date #Events #28мая
Милутин Мила́нкович (28 мая 1879, Даль (ныне Хорватия) — 12 декабря 1958, Белград) — австро-венгерский, сербский гражданский инженер, климатолог, геофизик, астрофизик и популяризатор науки.
Известен теорией ледниковых периодов, подразумевающей, что из-за периодических изменений параметров своей орбиты Земля проходит через повторяющиеся ледниковые периоды, в настоящее время известные как циклы Миланковича. Кроме того, дал оценку климатическим условиям на других планетах земной группы. Милутин Миланкович также модифицировал юлианский календарь, разработал новоюлианский календарь.
Мариа́н Смолухо́вский (фон Смолан-Смолуховский, пол. Marian Smoluchowski; 28 мая 1872, Фордер-Брюль, близ Вены — 5 сентября 1917, Краков) — австро-венгерский физик-теоретик польского происхождения.
Уравнения Смолуховского, разработанные им теоретические основы и вычислительные методы стали фундаментом статистической физики и особенно важной сегодня её отрасли, называемой теорией стохастических процессов, развиваемой как физиками, так и математиками. Применения уравнений Смолуховского простираются от физики (как макроскопических, так и субатомных систем) и химии до биологии и технических наук. Многочисленны и практические применения модели Смолуховского, например — индустриальное очищение воды, коагуляция молока, возникновение гелевых барьеров, агрегация гранулоцитов, адгезия лейкоцитов, рост нанотрубок и многое другое.
1742 — в Лондоне сооружён первый крытый плавательный бассейн.
#Biography #Birth_Date #Events #28мая
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Раздел 10. Логирование и мониторинг в Java
Глава 2. Логирование (Logging)
Логирование в «Библиотеке»
Часть 1. Подключение и настройка Logback
В
Конфигурация:
Создайте файл
Ключевые моменты:
Условное включение через
#Java #для_новичков #beginner #logging #Log4j2 #Logback #SLF4J #практика
Глава 2. Логирование (Logging)
Логирование в «Библиотеке»
Часть 1. Подключение и настройка Logback
В
pom.xml (если Maven) или убедитесь, что Logback на classpath:<<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.14</version>
</dependency>
<<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.9</version>
</dependency>
Конфигурация:
logback.xmlСоздайте файл
src/main/resources/logback.xml:<?xml version="1.0" encoding="UTF-8"?>
<<configuration>
<!-- Переменная для профиля -->
<springProperty scope="context" name="PROFILE" source="spring.profiles.active" defaultValue="default"/>
<!-- Для не-Spring проекта используйте системное свойство -->
<property name="PROFILE" value="${PROFILE:-default}"/>
<!-- Консоль: INFO и выше -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
</appender>
<!-- Файл ошибок: ERROR и выше -->
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/errors.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/errors.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxHistory>30</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n%ex</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
</appender>
<!-- Файл отладки: DEBUG и выше, только при профиле dev -->
<appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/debug.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/debug.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>7</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} [%X{operation}] - %msg%n</pattern>
</encoder>
</appender>
<!-- Корневой логгер -->
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="ERROR_FILE"/>
</root>
<!-- Логгер приложения -->
<logger name="library" level="INFO">
<!-- DEBUG-файл подключается условно -->
</logger>
<!-- Условное включение DEBUG-файла через профиль -->
<if condition='property("PROFILE").contains("dev")'>
<then>
<root level="DEBUG">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="ERROR_FILE"/>
<appender-ref ref="DEBUG_FILE"/>
</root>
<logger name="library" level="DEBUG"/>
</then>
</if>
</configuration>
Ключевые моменты:
ThresholdFilter отсекает уровни ниже заданногоRollingFileAppender с TimeBasedRollingPolicy — ротация по дате и размеруУсловное включение через
<if> требует janino в зависимостях:<<dependency>
<groupId>org.codehaus.janino</groupId>
<artifactId>janino</artifactId>
<version>3.1.11</version>
</dependency>
#Java #для_новичков #beginner #logging #Log4j2 #Logback #SLF4J #практика
👍4