Очень странно… 83 просмотра и 42 голоса
https://t.me/Java_for_beginner_dev/2477
Это реально столько активных пользователя?😭
Ау где остальные?👋
https://t.me/Java_for_beginner_dev/2477
Это реально столько активных пользователя?
Ау где остальные?
Please open Telegram to view this post
VIEW IN TELEGRAM
Telegram
Java for Beginner
Вы еще читаете этот канал? 🤨
Да! Каждый день, все интересно, стараюсь не пропускать 🙂 / Да, периодически встречается что-то интересное 🤷♀️ / Редко, но заглядываю 🤫 / Канал больше не интересен, практически не захожу 👎 / Я сам(а) не понимаю зачем нахожусь…
Да! Каждый день, все интересно, стараюсь не пропускать 🙂 / Да, периодически встречается что-то интересное 🤷♀️ / Редко, но заглядываю 🤫 / Канал больше не интересен, практически не захожу 👎 / Я сам(а) не понимаю зачем нахожусь…
Что такое лямбда-выражения в Java? 🤓
Ответ:
Лямбда-выражения в Java — это краткий способ записи анонимных функций, которые можно передавать как аргументы в методы или сохранять в переменные. Они появились в Java 8 и позволяют писать более компактный и читаемый код, особенно при работе с функциональными интерфейсами (интерфейсами с одним абстрактным методом, например, Runnable, Comparator, Predicate).
Синтаксис лямбда-выражения:
(параметры) -> { тело_лямбды }
Если параметр один, скобки () можно опустить.
Если тело состоит из одной строки, фигурные скобки {} и return можно не писать.
#собеседование
Ответ:
Синтаксис лямбда-выражения:
(параметры) -> { тело_лямбды }
Если параметр один, скобки () можно опустить.
Если тело состоит из одной строки, фигурные скобки {} и return можно не писать.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
С 31.05 по 06.06
Предыдущий пост(с 24.05 по 30.05)
Следующая неделя
Воскресный мотивационный пост:
«Ты не программируешь — ты притворяешься, что учишься»
Выбранная голосованием тема:
Архитектурный шаблон MVC в Java Spring: теория, правила, ошибки
Запись встреч:
Многопоточка во всей красе. Часть 1.
Обучающие статьи:
Типы changesets и стратегии развертывания в Liquibase
Откаты (Rollback) и теги в Liquibase
Интеграция Liquibase с другими инструментами
Глубокое изучение типа данных boolean в Java
Ссылочные типы данных в Java
Пост под которым нет поздравлений:
Сегодня каналу исполнился год!🥳
Авторская статья (которая кому-то не понравилась):
Пагинация, которую начинаешь ненавидеть😵
Полезные статьи и видео:
Создаём HTTP-сервер на Java NIO
Большой гайд. Пишем микросервисы на Java и Spring Boot, заворачиваем в Docker, запускаем на EKS, мониторим на Grafana
ИСТОРИЯ НЕЙРОСЕТЕЙ - ОТ ПЕРЦЕПТРОНА ДО CHATGPT
Как и всегда, задачи можно найти под тегом - #Tasks, вопросы с собеседований - #собеседование
#memory
Предыдущий пост(с 24.05 по 30.05)
Следующая неделя
Воскресный мотивационный пост:
«Ты не программируешь — ты притворяешься, что учишься»
Выбранная голосованием тема:
Архитектурный шаблон MVC в Java Spring: теория, правила, ошибки
Запись встреч:
Многопоточка во всей красе. Часть 1.
Обучающие статьи:
Типы changesets и стратегии развертывания в Liquibase
Откаты (Rollback) и теги в Liquibase
Интеграция Liquibase с другими инструментами
Глубокое изучение типа данных boolean в Java
Ссылочные типы данных в Java
Пост под которым нет поздравлений:
Сегодня каналу исполнился год!
Авторская статья (которая кому-то не понравилась):
Пагинация, которую начинаешь ненавидеть
Полезные статьи и видео:
Создаём HTTP-сервер на Java NIO
Большой гайд. Пишем микросервисы на Java и Spring Boot, заворачиваем в Docker, запускаем на EKS, мониторим на Grafana
ИСТОРИЯ НЕЙРОСЕТЕЙ - ОТ ПЕРЦЕПТРОНА ДО CHATGPT
Как и всегда, задачи можно найти под тегом - #Tasks, вопросы с собеседований - #собеседование
#memory
Please open Telegram to view this post
VIEW IN TELEGRAM
Настройка OAuth2 для Gmail
Для Gmail предпочтительно использовать OAuth2.
Пример конфигурации:
Примечание: Зарегистрируйте приложение в Google Cloud Console и используйте библиотеку google-auth-library-oauth2-http для получения accessToken.
Создание сервиса отправки почты
Создадим сервис EmailService для отправки писем.
Конфигурация асинхронности:
#Java #middle #on_request #JavaMailSender
Для Gmail предпочтительно использовать OAuth2.
Пример конфигурации:
@Configuration
public class MailConfig {
@Bean
public JavaMailSender javaMailSender() {
JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
mailSender.setHost("smtp.gmail.com");
mailSender.setPort(587);
mailSender.setUsername("your.email@gmail.com");
Properties props = mailSender.getJavaMailProperties();
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.starttls.enable", "true");
props.put("mail.smtp.auth.mechanisms", "XOAUTH2");
// Настройка OAuth2 токена через Google API Client Library
// Подробности: https://developers.google.com/identity/protocols/oauth2
return mailSender;
}
}
Примечание: Зарегистрируйте приложение в Google Cloud Console и используйте библиотеку google-auth-library-oauth2-http для получения accessToken.
Создание сервиса отправки почты
Создадим сервис EmailService для отправки писем.
@Service
public class EmailService {
@Autowired
private JavaMailSender mailSender;
@Autowired
private TemplateEngine templateEngine;
private static final Logger logger = LoggerFactory.getLogger(EmailService.class);
public void sendSimpleEmail(String to, String subject, String text) {
SimpleMailMessage message = new SimpleMailMessage();
message.setTo(to);
message.setSubject(subject);
message.setText(text);
mailSender.send(message);
}
public void sendHtmlEmail(String to, String subject, String htmlBody) throws MessagingException {
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
helper.setTo(to);
helper.setSubject(MimeUtility.encodeText(subject, "UTF-8", null));
helper.setText(htmlBody, true);
mailSender.send(message);
}
public void sendEmailWithAttachment(String to, String subject, String text, File attachment) throws MessagingException {
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
helper.setTo(to);
helper.setSubject(MimeUtility.encodeText(subject, "UTF-8", null));
helper.setText(text);
FileSystemResource file = new FileSystemResource(attachment);
helper.addAttachment(attachment.getName(), file);
mailSender.send(message);
}
@Async
public CompletableFuture<Void> sendSimpleEmailAsync(String to, String subject, String text IMPORTANT: text) {
SimpleMailMessage message = new SimpleMailMessage();
message.setTo(to);
message.setSubject(MimeUtility.encodeText(subject, "UTF-8", null));
message.setText(text);
mailSender.send(message);
return CompletableFuture.completedFuture(null);
}
public void sendTemplatedEmail(String to, String subject, String username) throws MessagingException {
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
Context context = new Context();
context.setVariable("username", username);
String htmlBody = templateEngine.process("email-template", context);
helper.setTo(to);
helper.setSubject(MimeUtility.encodeText(subject, "UTF-8", null));
helper.setText(htmlBody, true);
mailSender.send(message);
}
}
Конфигурация асинхронности:
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(100);
executor.initialize();
return executor;
}
}
#Java #middle #on_request #JavaMailSender
Примеры кода
Простой текст:
HTML-письмо:
Вложение:
Обработка ошибок и логирование
JavaMailSender может выбрасывать исключения, которые нужно обрабатывать.
Основные исключения:
Пример отлова:
Повторные попытки
Используйте @Retryable из Spring Retry:
Зависимость:
Мониторинг и метрики
Для продакшен-приложений полезно отслеживать метрики отправки писем с помощью Spring Actuator:
Зависимость:
Безопасность и защита данных
Никогда не храните пароли в открытом виде в git-репозиториях.
Рекомендации:
Используйте переменные окружения или секреты (например, Kubernetes Secrets).
Применяйте Spring Cloud Vault или HashiCorp Vault.
Используйте шифрование с Jasypt.
Настройте OAuth2 для Gmail.
Пример с переменными окружения:
#Java #middle #on_request #JavaMailSender
Простой текст:
SimpleMailMessage message = new SimpleMailMessage();
message.setTo("user@example.com");
message.setSubject("Тестовое письмо");
message.setText("Привет из Spring Boot!");
mailSender.send(message);
HTML-письмо:
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
helper.setTo("user@example.com");
helper.setSubject(MimeUtility.encodeText("HTML письмо", "UTF-8", null));
helper.setText("<h1>Привет!</h1><p>Это HTML письмо.</p>", true);
mailSender.send(message);
Вложение:
File file = new File("/path/to/file.pdf");
FileSystemResource resource = new FileSystemResource(file);
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
helper.setTo("user@example.com");
helper.setSubject(MimeUtility.encodeText("Письмо с вложением", "UTF-8", null));
helper.setText("Смотри вложение!");
helper.addAttachment("file.pdf", resource);
mailSender.send(message);
Обработка ошибок и логирование
JavaMailSender может выбрасывать исключения, которые нужно обрабатывать.
Основные исключения:
MailAuthenticationException
MailSendException
MessagingException
Пример отлова:
try {
mailSender.send(message);
} catch (MailException e) {
logger.error("Ошибка отправки письма", e);
throw e;
}
Повторные попытки
Используйте @Retryable из Spring Retry:
@Retryable(value = MailException.class, maxAttempts = 3)
public void sendSimpleEmail(String to, String subject, String text) {
SimpleMailMessage message = new SimpleMailMessage();
message.setTo(to);
message.setSubject(subject);
message.setText(text);
mailSender.send(message);
}
Зависимость:
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
Мониторинг и метрики
Для продакшен-приложений полезно отслеживать метрики отправки писем с помощью Spring Actuator:
@Service
public class EmailService {
@Autowired
private JavaMailSender mailSender;
@Autowired
private MeterRegistry meterRegistry;
public void sendSimpleEmail(String to, String subject, String text) {
SimpleMailMessage message = new SimpleMailMessage();
message.setTo(to);
message.setSubject(subject);
message.setText(text);
try {
mailSender.send(message);
meterRegistry.counter("email.sent.success").increment();
} catch (MailException e) {
meterRegistry.counter("email.sent.failure").increment();
throw e;
}
}
}
Зависимость:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
Безопасность и защита данных
Никогда не храните пароли в открытом виде в git-репозиториях.
Рекомендации:
Используйте переменные окружения или секреты (например, Kubernetes Secrets).
Применяйте Spring Cloud Vault или HashiCorp Vault.
Используйте шифрование с Jasypt.
Настройте OAuth2 для Gmail.
Пример с переменными окружения:
spring.config.import=optional:configserver:http://config-server
spring.mail.password=${MAIL_PASSWORD}
#Java #middle #on_request #JavaMailSender
Тестирование отправки почты
Интеграционные тесты с Testcontainers:
Зависимость:
Unit-тестирование:
Интеграция с очередями
Для отложенной отправки используйте RabbitMQ(ну или другой брокер сообщений):
Зависимость:
Распространенные ошибки и подводные камни
Неверная конфигурация SMTP (порт, шифрование).
Проблемы с двухфакторной авторизацией (особенно Gmail).
Ограничения на массовую рассылку (например, Gmail: ~500 писем/день для бесплатных аккаунтов).
Проблемы с кодировкой (например, кириллица в теме письма).
Отсутствие MIME-типа у вложений.
Блокировка сервером (например, Mail.ru требует DKIM и SPF).
Решение для кодировки:
#Java #middle #on_request #JavaMailSender
Интеграционные тесты с Testcontainers:
@Testcontainers
@SpringBootTest
public class EmailServiceTest {
@Container
private static final GreenMailContainer greenMail = new GreenMailContainer();
@Autowired
private EmailService emailService;
@Test
void shouldSendEmail() {
emailService.sendSimpleEmail("test@example.com", "Test Subject", "Test Body");
assertEquals(1, greenMail.getReceivedMessages().length);
}
}
Зависимость:
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>greenmail</artifactId>
<version>2.2.0</version>
<scope>test</scope>
</dependency>
Unit-тестирование:
@MockBean
private JavaMailSender mailSender;
@Test
void shouldSendMail() {
SimpleMailMessage message = new SimpleMailMessage();
emailService.sendSimpleEmail("to", "subject", "body");
verify(mailSender, times(1)).send(any(SimpleMailMessage.class));
}
Интеграция с очередями
Для отложенной отправки используйте RabbitMQ(ну или другой брокер сообщений):
@Service
public class EmailService {
@Autowired
private JavaMailSender mailSender;
@Autowired
private RabbitTemplate rabbitTemplate;
public void sendEmailToQueue(String to, String subject, String text) {
EmailMessage email = new EmailMessage(to, subject, text);
rabbitTemplate.convertAndSend("emailQueue", email);
}
@RabbitListener(queues = "emailQueue")
public void processEmail(EmailMessage email) {
SimpleMailMessage message = new SimpleMailMessage();
message.setTo(email.getTo());
message.setSubject(email.getSubject());
message.setText(email.getText());
mailSender.send(message);
}
@Data
static class EmailMessage {
private String to;
private String subject;
private String text;
}
}
Зависимость:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
Распространенные ошибки и подводные камни
Неверная конфигурация SMTP (порт, шифрование).
Проблемы с двухфакторной авторизацией (особенно Gmail).
Ограничения на массовую рассылку (например, Gmail: ~500 писем/день для бесплатных аккаунтов).
Проблемы с кодировкой (например, кириллица в теме письма).
Отсутствие MIME-типа у вложений.
Блокировка сервером (например, Mail.ru требует DKIM и SPF).
Решение для кодировки:
helper.setSubject(MimeUtility.encodeText("Тема на кириллице", "UTF-8", null));
#Java #middle #on_request #JavaMailSender
Сегодня продолжаем изучение многопоточки
В связи с техническими нюансами, встречу по многопоточке пришлось отменить.
Но мы же не могли оставить Вас без продолжения?😏
Поэтому @rKiraLis39 записал (за что ему огромное спасибо) для Вас видео в котором мы узнали:
⏺ Что такое атомарные операции в потоках
⏺ Что такое волатильность и как ее использовать
⏺ Как взаимодействовать с Executor'ами и как их настраивать
⏺ И много еще интересного
Ссылка на Youtube
Ссылка на Рутьюб
Смотрите, ставьте лайки, подписывайтесь на каналы!
В связи с техническими нюансами, встречу по многопоточке пришлось отменить.
Но мы же не могли оставить Вас без продолжения?
Поэтому @rKiraLis39 записал (за что ему огромное спасибо) для Вас видео в котором мы узнали:
Ссылка на Youtube
Ссылка на Рутьюб
Смотрите, ставьте лайки, подписывайтесь на каналы!
Please open Telegram to view this post
VIEW IN TELEGRAM
«Обучение Java — марафон, а не прыжок с трамплина»
Так вышло, что мое знакомство с Java и программированием в целом, началось еще в 2021 году.
Тогда, окрыленный надеждами на новую, интересную работу, я потратил приличное количество времени на изучение Java Core. Но как часто бывает, реальность продиктовала свои условия, я не смог осилить обучение и бросил его.
Периодически возвращаясь я понял, что придется начинать сначала.
И когда я смог подогнать жизненные условия к тому, чтобы бросить все и посвятить себя только обучению, которое в итоге привело меня сюда, я понял важную вещь - обучение программированию (да наверно любой другой сложной концепции) — это долгая, часто тяжелая дорога, где не будет "легко", но "результат" стоит того.
Вот, что важно понимать если ты только принял решение вступить на этот путь:
🟥 Начнем с массового, современного увлечения курсами, буткемпами, менторством, тренингами и подобной требухой.
Пойми простую вещь - кто обещает «легко и быстро» — 100% врет. Так практически не бывает, за исключением единичных примеров. Но ссылаясь на эти примеры, некоторые строят целые онлайн-школы и бизнес (на твоих деньгах).
И я не говорю, что ты не получишь ничего полезного на этих занятиях. НО! Ты не сможешь, к примеру за 3 месяца, стать конкурентным специалистом в Java, если ты обычный среднестатистический человек.
Ну никак, сорян, кто бы что не говорил🤷♀️
🟥 Ощущение «я тупой» — обязательный этап каждого.
Перед окунанием в "программирование", знай, что к примеру Java, уже отпраздновала 30-летие в этом году. А это, возможно больше чем ты живешь на свете.
А это значит, что изучение её (по крайней мере, как ощущаю это я) - это погружение в бесконечную кроличью нору.🐇
На каждую понятую тобой концепцию или алгоритм, за его спиной вырастут еще с десяток и ты постоянно будешь ощущать себя неполноценным😂
Не переживай - это нормально. Все проходят через это🙂
🟥 Медленный прогресс — это не глупость.
Пойми и прими, то, что порой в Java встречаются темы, которые не взять "с наскока". Ну никак.
И если ты вдруг, ловишь себя на мысли, что на какую-то тему ты тратишь неприлично долгое время - это не значит, что ты "не тянешь".
Просто это тоже нормально. Мы все разные, с разным бекграундом.
Важно не «как быстро», а как долго ты не сливаешься. Ведь в итоге самые стойкие — выигрывают, даже если тупят на старте.🏝
🟥 Ты просто обязан пройти через говнокод.
Знай, никто не пишет "красиво" и "правильно" с первого раза. Даже "гении".
А ты и я тем более.
Поэтому, как я писал в предыдущей статье - если первые месяцы ты будешь писать грязно, неэффективно и тупо — это тоже нормально и правильно.
Запомни: в начале пути, идеальный код — не твоя цель. Цель — живой и работающий код, а все остальное приложится.🧑💻
🟥 Ну и главное - обучение не должно быть "в кайф".
Если тебе в процессе обучения неприятно, неудобно и сложно — значит, ты делаешь правильно. (Особенно это актуально для тех кто за "30"👋 )
Твой мозг вышел из зоны комфорта, он испытывает стресс и пытается повлиять на тебя, вернув в теплые объятия неведения.
Твоя задача - ежедневно, ежеминутно, бороться с ленью, преодолевать алгоритмические и идейные трудности, выстраивая новые нейронные связи.
Комфорт — не показатель правильности выбранной методики обучения. Часто наоборот.
И вот когда ты преодолеешь себя, увидишь как на твою почту придет первый оффер, тогда ты как и я, поймешь, что и не стоило ждать удобств в обучении. (Тем более, что оно всегда будет продолжаться)
Ведь те трудности которые ты преодолел - сформировали из тебя того кто смог пройти собеседование и получить заветную работу.🥳
Главное вера в себя и свои силы💪
😎
Понравилась статья - поделись с другом и, будет тебе моя благодарность 👏
#motivation
Так вышло, что мое знакомство с Java и программированием в целом, началось еще в 2021 году.
Тогда, окрыленный надеждами на новую, интересную работу, я потратил приличное количество времени на изучение Java Core. Но как часто бывает, реальность продиктовала свои условия, я не смог осилить обучение и бросил его.
Периодически возвращаясь я понял, что придется начинать сначала.
И когда я смог подогнать жизненные условия к тому, чтобы бросить все и посвятить себя только обучению, которое в итоге привело меня сюда, я понял важную вещь - обучение программированию (да наверно любой другой сложной концепции) — это долгая, часто тяжелая дорога, где не будет "легко", но "результат" стоит того.
Вот, что важно понимать если ты только принял решение вступить на этот путь:
Пойми простую вещь - кто обещает «легко и быстро» — 100% врет. Так практически не бывает, за исключением единичных примеров. Но ссылаясь на эти примеры, некоторые строят целые онлайн-школы и бизнес (на твоих деньгах).
И я не говорю, что ты не получишь ничего полезного на этих занятиях. НО! Ты не сможешь, к примеру за 3 месяца, стать конкурентным специалистом в Java, если ты обычный среднестатистический человек.
Ну никак, сорян, кто бы что не говорил
Перед окунанием в "программирование", знай, что к примеру Java, уже отпраздновала 30-летие в этом году. А это, возможно больше чем ты живешь на свете.
А это значит, что изучение её (по крайней мере, как ощущаю это я) - это погружение в бесконечную кроличью нору.
На каждую понятую тобой концепцию или алгоритм, за его спиной вырастут еще с десяток и ты постоянно будешь ощущать себя неполноценным
Не переживай - это нормально. Все проходят через это
Пойми и прими, то, что порой в Java встречаются темы, которые не взять "с наскока". Ну никак.
И если ты вдруг, ловишь себя на мысли, что на какую-то тему ты тратишь неприлично долгое время - это не значит, что ты "не тянешь".
Просто это тоже нормально. Мы все разные, с разным бекграундом.
Важно не «как быстро», а как долго ты не сливаешься. Ведь в итоге самые стойкие — выигрывают, даже если тупят на старте.
Знай, никто не пишет "красиво" и "правильно" с первого раза. Даже "гении".
А ты и я тем более.
Поэтому, как я писал в предыдущей статье - если первые месяцы ты будешь писать грязно, неэффективно и тупо — это тоже нормально и правильно.
Запомни: в начале пути, идеальный код — не твоя цель. Цель — живой и работающий код, а все остальное приложится.
Если тебе в процессе обучения неприятно, неудобно и сложно — значит, ты делаешь правильно. (Особенно это актуально для тех кто за "30"
Твой мозг вышел из зоны комфорта, он испытывает стресс и пытается повлиять на тебя, вернув в теплые объятия неведения.
Твоя задача - ежедневно, ежеминутно, бороться с ленью, преодолевать алгоритмические и идейные трудности, выстраивая новые нейронные связи.
Комфорт — не показатель правильности выбранной методики обучения. Часто наоборот.
И вот когда ты преодолеешь себя, увидишь как на твою почту придет первый оффер, тогда ты как и я, поймешь, что и не стоило ждать удобств в обучении. (Тем более, что оно всегда будет продолжаться)
Ведь те трудности которые ты преодолел - сформировали из тебя того кто смог пройти собеседование и получить заветную работу.
Главное вера в себя и свои силы
#motivation
Please open Telegram to view this post
VIEW IN TELEGRAM
Предлагаем темы для разбора и публикации! 📖
В комментариях к данному посту предлагайте вопросы, которые вы хотели бы увидеть максимально подробно разобранными в постах, а если будет интересно то и на видео.
Голосование будет проводиться всю неделю, а статья или видео - выходить по выходным.
Примерные правила:
🟢 темы, не выше уровня middle, чтоб был интерес общим.
🟢 один человек - одна тема.
🟢 Тема должна быть отдельным теоретически-практическим вопросом. Готовый проект - это не тема!
Жду Ваших предложений!👏
В комментариях к данному посту предлагайте вопросы, которые вы хотели бы увидеть максимально подробно разобранными в постах, а если будет интересно то и на видео.
Голосование будет проводиться всю неделю, а статья или видео - выходить по выходным.
Примерные правила:
Жду Ваших предложений!
Please open Telegram to view this post
VIEW IN TELEGRAM
Голосуем за предложенные темы!
Anonymous Poll
54%
Stream API
15%
@Slf4j, логирование, кастомизация логов
13%
IO, NIO: работа с файловой системой
17%
Maven: жизненный цикл, фазы
Объекты в Java
Объекты являются фундаментальным понятием в Java и лежат в основе всей объектно-ориентированной парадигмы языка. Каждый объект представляет собой экземпляр класса и объединяет в себе состояние (поля) и поведение (методы).
1. Введение
В Java всё, что не является примитивным типом, относится к ссылочным типам, а основные единицы этих типов — это объекты.
Объект-ориентированная модель основана на трёх ключевых принципах:
Инкапсуляция: объединение данных и методов для управления ими.
Наследование: возможность создавать новые классы на основе уже существующих, унаследовав их состояние и поведение.
Полиморфизм: возможность работать с объектами через их общий (абстрактный) тип, подставляя разные конкретные реализации.
Вся динамика и гибкость Java-приложений строится на том, что объекты создаются во время выполнения программы, передаются по ссылке, могут образовывать сложные графы связей и автоматически удаляться сборщиком мусора.
2. Создание объектов
2.1. Ключевое слово new
Самый распространённый способ создания объекта — использование оператора new, который выполняет два основных действия:
Выделяет память в куче (heap) под новый объект.
Вызывает конструктор соответствующего класса, чтобы инициализировать поля объекта.
Здесь:
new Person("John", 25) — порождает новый объект класса Person, вызывая конструктор Person(String name, int age).
Полученная ссылка на вновь созданный объект присваивается переменной person1 типа Person.
Переменная person1 не содержит непосредственно самого объекта, а лишь указывает на область памяти, где объект расположен.
2.2. Фабричные методы и другие способы
Кроме new, объекты могут создаваться через:
Фабричные методы (static factory methods), например, List.of(...) или Optional.of(...).
Клонирование (когда класс поддерживает интерфейс Cloneable и реализует метод clone()).
Десериализация (с помощью API сериализации или при работе с JSON/XML).
Рефлексия (пересоздание экземпляра через Class.newInstance() или Constructor.newInstance()).
Однако в подавляющем большинстве случаев для явного создания объекта используется именно new.
2.3. Размещение ссылок и объектов
Объекты всегда размещаются в куче (heap).
Ссылочные переменные (person1 в примере) могут храниться:
В стеке вызовов (если это локальная переменная метода).
В полях других объектов (если объект содержится в качестве поля другого объекта).
В элементах массива (если это массив ссылок).
В статических полях классов (в специальной области памяти, связанной с загрузчиком классов).
3. Существование и удаление объектов
3.1. Существование объектов
Объект продолжает «жить» в памяти до тех пор, пока на него существует хотя бы одна активная ссылка.
Пример:
В момент создания объекта через new в куче появляется новый экземпляр Person.
Переменные person1 и person2 указывают на одну и ту же область памяти.
Когда мы присвоили person1 = null;, объект всё ещё существует, поскольку на него ссылается person2.
Как только все ссылки будут убраны (например, person2 = null; или метод, в котором была локальная ссылка, завершится и стек «очистится»), объект становится недостижимым.
Java применяет алгоритм mark-and-sweep для сборки мусора, поэтому даже если два объекта ссылаются друг на друга, но на них никто извне не ссылается, они будут помечены как недостижимые и удалены.
#Java #для_новичков #beginner #reference_types #Object
Объекты являются фундаментальным понятием в Java и лежат в основе всей объектно-ориентированной парадигмы языка. Каждый объект представляет собой экземпляр класса и объединяет в себе состояние (поля) и поведение (методы).
1. Введение
В Java всё, что не является примитивным типом, относится к ссылочным типам, а основные единицы этих типов — это объекты.
Объект-ориентированная модель основана на трёх ключевых принципах:
Инкапсуляция: объединение данных и методов для управления ими.
Наследование: возможность создавать новые классы на основе уже существующих, унаследовав их состояние и поведение.
Полиморфизм: возможность работать с объектами через их общий (абстрактный) тип, подставляя разные конкретные реализации.
Вся динамика и гибкость Java-приложений строится на том, что объекты создаются во время выполнения программы, передаются по ссылке, могут образовывать сложные графы связей и автоматически удаляться сборщиком мусора.
2. Создание объектов
2.1. Ключевое слово new
Самый распространённый способ создания объекта — использование оператора new, который выполняет два основных действия:
Выделяет память в куче (heap) под новый объект.
Вызывает конструктор соответствующего класса, чтобы инициализировать поля объекта.
Person person1 = new Person("John", 25);
Здесь:
new Person("John", 25) — порождает новый объект класса Person, вызывая конструктор Person(String name, int age).
Полученная ссылка на вновь созданный объект присваивается переменной person1 типа Person.
Переменная person1 не содержит непосредственно самого объекта, а лишь указывает на область памяти, где объект расположен.
2.2. Фабричные методы и другие способы
Кроме new, объекты могут создаваться через:
Фабричные методы (static factory methods), например, List.of(...) или Optional.of(...).
Клонирование (когда класс поддерживает интерфейс Cloneable и реализует метод clone()).
Десериализация (с помощью API сериализации или при работе с JSON/XML).
Рефлексия (пересоздание экземпляра через Class.newInstance() или Constructor.newInstance()).
Однако в подавляющем большинстве случаев для явного создания объекта используется именно new.
2.3. Размещение ссылок и объектов
Объекты всегда размещаются в куче (heap).
Ссылочные переменные (person1 в примере) могут храниться:
В стеке вызовов (если это локальная переменная метода).
В полях других объектов (если объект содержится в качестве поля другого объекта).
В элементах массива (если это массив ссылок).
В статических полях классов (в специальной области памяти, связанной с загрузчиком классов).
3. Существование и удаление объектов
3.1. Существование объектов
Объект продолжает «жить» в памяти до тех пор, пока на него существует хотя бы одна активная ссылка.
Пример:
Person person1 = new Person("John", 25);
Person person2 = person1; // person2 ссылается на тот же самый объект
person1 = null; // теперь единственная ссылка на объект — person2
В момент создания объекта через new в куче появляется новый экземпляр Person.
Переменные person1 и person2 указывают на одну и ту же область памяти.
Когда мы присвоили person1 = null;, объект всё ещё существует, поскольку на него ссылается person2.
Как только все ссылки будут убраны (например, person2 = null; или метод, в котором была локальная ссылка, завершится и стек «очистится»), объект становится недостижимым.
Java применяет алгоритм mark-and-sweep для сборки мусора, поэтому даже если два объекта ссылаются друг на друга, но на них никто извне не ссылается, они будут помечены как недостижимые и удалены.
#Java #для_новичков #beginner #reference_types #Object
3.2. Состояние объектов при сборке мусора
Touchable (доступный): объекты, на которые есть хотя бы одна живая ссылка.
Resurrectible (возродимый): объекты, на которые больше нет обычных ссылок, но в методе finalize() ещё есть возможность «оживить» объект (устаревший механизм, не рекомендуется к использованию).
Untouchable (недоступный): объекты, окончательно помеченные для удаления сборщиком мусора.
Иерархия переходов такова:
Пока есть ссылки — объект «доступен» и используется.
Если ссылок нет, но метод finalize() ещё не вызывался — объект попадает в очередь финализации.
После выполнения finalize() (или если он не переопределён) объект окончательно переходит в состояние «недоступен» и убирается сборщиком мусора.
3.3. Удаление объектов
Перечислять и освобождать память вручную, как в C++, в Java не нужно.
Можно лишь рекомендовать запуск сборщика мусора через System.gc(), но вызов этого метода не гарантирует немедленного выполнения GC.
Метод finalize() устаревает (deprecated) и не рекомендуется к использованию, поскольку его выполнение непредсказуемо и может негативно влиять на производительность.
При работе с ресурсами (файлы, сокеты, потоки) рекомендуется применять конструкцию try-with-resources или явно закрывать ресурсы в блоке finally, а не полагаться на GC или finalize().
4. Использование объектов
4.1. Вызов методов и доступ к полям
После того как объект создан и на него есть ссылка, мы можем обращаться к его полям и методам:
Ключевое понимание:
Любой метод вызывается через ссылку на объект.
Внутри метода this указывает на тот же объект, на который указывает переменная, через которую мы вызвали метод.
4.2. Инкапсуляция и модульность
Объекты позволяют:
Инкапсулировать внутреннее состояние (часто делая поля private и предоставляя доступ через геттеры/сеттеры).
Скрыть детали реализации, предоставляя только публичный интерфейс (методы).
Повторно использовать код: один и тот же класс можно инстанцировать в разных местах программы.
4.3. Передача объектов в методы
Когда мы передаём объект в метод, копируется сама ссылка, а не весь объект.
Это значит, что метод получает «копию адреса», указывающую на тот же экземпляр:
Вызов list.add(10) изменил тот же объект, что и numbers.
А переприсваивание list = new ArrayList<>() коснулось только локальной копии ссылки внутри метода.
5. Трудности и подводные камни
5.1. NullPointerException
Самая распространённая ошибка при работе с объектами — попытка вызвать метод или обратиться к полю на null-ссылке:
Рекомендуемые практики:
При инициализации объектов делать явные проверки, либо использовать Objects.requireNonNull(obj).
При наличии неопределённости возвращать Optional<T> вместо потенциально null.
В местах, где возможно получение null, проверять ссылку прежде чем обращаться к её методам или полям.
#Java #для_новичков #beginner #reference_types #Object
Touchable (доступный): объекты, на которые есть хотя бы одна живая ссылка.
Resurrectible (возродимый): объекты, на которые больше нет обычных ссылок, но в методе finalize() ещё есть возможность «оживить» объект (устаревший механизм, не рекомендуется к использованию).
Untouchable (недоступный): объекты, окончательно помеченные для удаления сборщиком мусора.
Иерархия переходов такова:
Пока есть ссылки — объект «доступен» и используется.
Если ссылок нет, но метод finalize() ещё не вызывался — объект попадает в очередь финализации.
После выполнения finalize() (или если он не переопределён) объект окончательно переходит в состояние «недоступен» и убирается сборщиком мусора.
3.3. Удаление объектов
Перечислять и освобождать память вручную, как в C++, в Java не нужно.
Можно лишь рекомендовать запуск сборщика мусора через System.gc(), но вызов этого метода не гарантирует немедленного выполнения GC.
Метод finalize() устаревает (deprecated) и не рекомендуется к использованию, поскольку его выполнение непредсказуемо и может негативно влиять на производительность.
При работе с ресурсами (файлы, сокеты, потоки) рекомендуется применять конструкцию try-with-resources или явно закрывать ресурсы в блоке finally, а не полагаться на GC или finalize().
4. Использование объектов
4.1. Вызов методов и доступ к полям
После того как объект создан и на него есть ссылка, мы можем обращаться к его полям и методам:
person1.sayHello(); // вызов метода объекта
int age = person1.getAge(); // чтение свойства через геттер
Ключевое понимание:
Любой метод вызывается через ссылку на объект.
Внутри метода this указывает на тот же объект, на который указывает переменная, через которую мы вызвали метод.
4.2. Инкапсуляция и модульность
Объекты позволяют:
Инкапсулировать внутреннее состояние (часто делая поля private и предоставляя доступ через геттеры/сеттеры).
Скрыть детали реализации, предоставляя только публичный интерфейс (методы).
Повторно использовать код: один и тот же класс можно инстанцировать в разных местах программы.
4.3. Передача объектов в методы
Когда мы передаём объект в метод, копируется сама ссылка, а не весь объект.
Это значит, что метод получает «копию адреса», указывающую на тот же экземпляр:
void modifyList(List<Integer> list) {
list.add(10); // модифицирует оригинальный список
list = new ArrayList<>(); // переприсвоение локальной переменной — не влияет на внешний список
list.add(20); // меняет уже новый (локальный) список
}
List<Integer> numbers = new ArrayList<>();
modifyList(numbers);
System.out.println(numbers); // [10], но не [10, 20]
Вызов list.add(10) изменил тот же объект, что и numbers.
А переприсваивание list = new ArrayList<>() коснулось только локальной копии ссылки внутри метода.
5. Трудности и подводные камни
5.1. NullPointerException
Самая распространённая ошибка при работе с объектами — попытка вызвать метод или обратиться к полю на null-ссылке:
String s = null;
int length = s.length(); // NullPointerException
Рекомендуемые практики:
При инициализации объектов делать явные проверки, либо использовать Objects.requireNonNull(obj).
При наличии неопределённости возвращать Optional<T> вместо потенциально null.
В местах, где возможно получение null, проверять ссылку прежде чем обращаться к её методам или полям.
#Java #для_новичков #beginner #reference_types #Object
5.2. Сравнение ссылок и содержимого
Оператор == сравнивает адреса в памяти, то есть проверяет, совпадают ли ссылки.
Метод equals() (если переопределён) сравнивает логическое содержание объектов.
5.3. Изменяемые (mutable) и неизменяемые (immutable) объекты
Изменяемые объекты (например, ArrayList, StringBuilder) позволяют изменять своё внутреннее состояние после создания. Если несколько ссылок указывают на один и тот же экземпляр, то изменение через одну ссылку будет видно через все остальные.
Неизменяемые объекты (например, String, Integer, LocalDate) после создания не меняются; операции, которые «меняют» их, на самом деле возвращают новый экземпляр.
Непонимание этого может привести к неожиданным результатам:
5.4. Утечки памяти
В Java утечки памяти возникают не из-за отсутствия явного удаления объектов (как в C++), а из-за того, что на объекты остаются неожиданно живые ссылки, и GC не может их убрать:
Хранение объектов в static-полях и неочищаемых коллекциях.
Неправильная работа с кешами или пулом объектов, где ссылки не удаляются вовремя.
Анонимные внутренние классы или лямбда-выражения, сохраняющиеся после использования.
Пример простой утечки:
5.5. Производительность и частые аллокации
Частое создание небольших временных объектов может привести к частым запускам GC и общему снижению производительности.
Конкатенация строк в цикле через оператор + создаёт новые объекты String на каждом шаге.
Лучше использовать StringBuilder:
5.6. Пограничные случаи при копировании — глубокое vs поверхностное копирование
Поверхностное копирование (shallow copy) копирует только поля-примитивы и ссылки; вложенные объекты не дублируются, а «разделяются» между двумя экземплярами.
Глубокое копирование (deep copy) предполагает создание новых экземпляров для всех вложенных объектов, чтобы изменения в одном объекте не затрагивали другой.
5.7. Потокобезопасность (thread-safety)
Когда объекты доступны из нескольких потоков, нужно грамотно синхронизировать доступ к их полям и методам:
Использовать synchronized, ReentrantLock, атомарные типы (AtomicInteger, AtomicReference).
Предпочитать неизменяемые объекты, так как они автоматически безопасны для чтения из разных потоков.
Избегать состояния, зависимого от порядка выполнения, или пользоваться высокоуровневыми абстракциями из java.util.concurrent.
#Java #для_новичков #beginner #reference_types #Object
Оператор == сравнивает адреса в памяти, то есть проверяет, совпадают ли ссылки.
Метод equals() (если переопределён) сравнивает логическое содержание объектов.
String a = new String("hello");
String b = new String("hello");
System.out.println(a == b); // false (разные объекты)
System.out.println(a.equals(b)); // true (одинаковое содержимое)
Неверное использование == вместо equals() приводит к тому, что два «логически одинаковых» объекта будут считаться разными.
5.3. Изменяемые (mutable) и неизменяемые (immutable) объекты
Изменяемые объекты (например, ArrayList, StringBuilder) позволяют изменять своё внутреннее состояние после создания. Если несколько ссылок указывают на один и тот же экземпляр, то изменение через одну ссылку будет видно через все остальные.
Неизменяемые объекты (например, String, Integer, LocalDate) после создания не меняются; операции, которые «меняют» их, на самом деле возвращают новый экземпляр.
Непонимание этого может привести к неожиданным результатам:
List<String> list = new ArrayList<>();
list.add("A");
List<String> another = list;
another.clear(); // очищает список для обеих ссылок
System.out.println(list); // []
5.4. Утечки памяти
В Java утечки памяти возникают не из-за отсутствия явного удаления объектов (как в C++), а из-за того, что на объекты остаются неожиданно живые ссылки, и GC не может их убрать:
Хранение объектов в static-полях и неочищаемых коллекциях.
Неправильная работа с кешами или пулом объектов, где ссылки не удаляются вовремя.
Анонимные внутренние классы или лямбда-выражения, сохраняющиеся после использования.
Пример простой утечки:
public class Cache {
private static final Map<String, Object> CACHE = new HashMap<>();
public static void put(String key, Object value) {
CACHE.put(key, value);
}
// Если не реализовать метод удаления из CACHE, то объекты будут храниться в памяти постоянно
}
5.5. Производительность и частые аллокации
Частое создание небольших временных объектов может привести к частым запускам GC и общему снижению производительности.
Конкатенация строк в цикле через оператор + создаёт новые объекты String на каждом шаге.
Лучше использовать StringBuilder:
// Плохо:
String result = "";
for (int i = 0; i < 1000; i++) {
result += i; // каждый раз создаётся новый String
}
// Лучше:
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
sb.append(i);
}
String result = sb.toString();
5.6. Пограничные случаи при копировании — глубокое vs поверхностное копирование
Поверхностное копирование (shallow copy) копирует только поля-примитивы и ссылки; вложенные объекты не дублируются, а «разделяются» между двумя экземплярами.
Глубокое копирование (deep copy) предполагает создание новых экземпляров для всех вложенных объектов, чтобы изменения в одном объекте не затрагивали другой.
class Address {
String street;
}
class Person implements Cloneable {
String name;
Address address;
@Override
protected Person clone() throws CloneNotSupportedException {
Person cloned = (Person) super.clone(); // поверхностное копирование
cloned.address = new Address(); // нужно вручную создать новый адрес
cloned.address.street = this.address.street;
return cloned;
}
}
Если не учитывать глубокое копирование, можно случайно разделить внутреннее состояние между двумя объектами, что приведёт к трудноотлавливаемым ошибкам.
5.7. Потокобезопасность (thread-safety)
Когда объекты доступны из нескольких потоков, нужно грамотно синхронизировать доступ к их полям и методам:
Использовать synchronized, ReentrantLock, атомарные типы (AtomicInteger, AtomicReference).
Предпочитать неизменяемые объекты, так как они автоматически безопасны для чтения из разных потоков.
Избегать состояния, зависимого от порядка выполнения, или пользоваться высокоуровневыми абстракциями из java.util.concurrent.
#Java #для_новичков #beginner #reference_types #Object
6. Дополнительные нюансы
6.1. Массивы как объекты
Хотя у массивов особый синтаксис, они всё же являются полноценными объектами:
Имеют поле length.
Могут быть null (если не инициализированы), поэтому доступ к элементам массива без проверки может привести к NullPointerException.
Создаются через new Type[size] или инициализируются через литералы { … }.
6.2. Generics и ограничение на примитивы
В обобщённых (generic) классах и методах можно использовать только ссылочные типы. Примитивы (например, int, char) нельзя указать напрямую как параметр типа.
В качестве параметры обобщений применяются соответствующие классы-обёртки: Integer, Character, Double и т. д.
6.3. Наследование от Object
Все классы в Java неявно наследуются от java.lang.Object.
В классе Object определены методы: toString(), equals(), hashCode(), getClass(), clone(), finalize() и др.
При работе с любыми объектами полезно переопределять toString(), equals() и hashCode() в соответствии с логикой класса:
6.4. Расположение в памяти
Объекты — в куче. При создании нового экземпляра сборщик мусора определяет, в какой части кучи разместить объект (young generation, old generation и т. д.).
Ссылочные переменные (локальные) — в стеке вызовов. Когда метод завершается, все локальные ссылки удаляются из стека.
Ссылки в полях — часть объекта в куче. Когда объект удаляется, удаляются и все его поля-ссылки.
Это знание помогает понимать, какие объекты могут быстро «умирать» (локальные объекты, ссылки на которые не передаются дальше) и какие могут «жить» дольше (объекты, ссылки на которые остаются в статических полях или в глобальном контексте).
#Java #для_новичков #beginner #reference_types #Object
6.1. Массивы как объекты
Хотя у массивов особый синтаксис, они всё же являются полноценными объектами:
Имеют поле length.
Могут быть null (если не инициализированы), поэтому доступ к элементам массива без проверки может привести к NullPointerException.
Создаются через new Type[size] или инициализируются через литералы { … }.
int[] nums = new int[5];
System.out.println(nums.length); // 5
String[] names = null;
System.out.println(names.length); // NullPointerException
6.2. Generics и ограничение на примитивы
В обобщённых (generic) классах и методах можно использовать только ссылочные типы. Примитивы (например, int, char) нельзя указать напрямую как параметр типа.
В качестве параметры обобщений применяются соответствующие классы-обёртки: Integer, Character, Double и т. д.
List<Integer> integers = new ArrayList<>();
integers.add(10); // автоупаковка: int → Integer
6.3. Наследование от Object
Все классы в Java неявно наследуются от java.lang.Object.
В классе Object определены методы: toString(), equals(), hashCode(), getClass(), clone(), finalize() и др.
При работе с любыми объектами полезно переопределять toString(), equals() и hashCode() в соответствии с логикой класса:
class Point {
int x, y;
@Override
public String toString() {
return "Point(" + x + ", " + y + ")";
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof Point)) return false;
Point other = (Point) obj;
return x == other.x && y == other.y;
}
@Override
public int hashCode() {
return 31 * x + y;
}
}
6.4. Расположение в памяти
Объекты — в куче. При создании нового экземпляра сборщик мусора определяет, в какой части кучи разместить объект (young generation, old generation и т. д.).
Ссылочные переменные (локальные) — в стеке вызовов. Когда метод завершается, все локальные ссылки удаляются из стека.
Ссылки в полях — часть объекта в куче. Когда объект удаляется, удаляются и все его поля-ссылки.
Это знание помогает понимать, какие объекты могут быстро «умирать» (локальные объекты, ссылки на которые не передаются дальше) и какие могут «жить» дольше (объекты, ссылки на которые остаются в статических полях или в глобальном контексте).
#Java #для_новичков #beginner #reference_types #Object
Что выведет код?
#Tasks
public class Task090625 {
public static void main(String[] args) {
Object obj1 = new Object();
Object obj2 = new Object();
System.out.println(obj1 == obj2);
System.out.println(obj1.equals(obj2));
}
}
#Tasks