Java for Beginner
714 subscribers
659 photos
174 videos
12 files
1.03K links
Канал от новичков для новичков!
Изучайте Java вместе с нами!
Здесь мы обмениваемся опытом и постоянно изучаем что-то новое!

Наш YouTube канал - https://www.youtube.com/@Java_Beginner-Dev

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
📌 Факт дня:

А вы знали, что первый "цифровой билет" был продан в 1995 году?

В 1995 году Southwest Airlines стала первой компанией, предложившей электронные билеты на авиарейсы через свой сайт. Это устранило необходимость в бумажных билетах и изменило индустрию путешествий.


#facts
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
📌 Цитата дня: Майкл Делл

"Идеи бесполезны без реализации."


Майкл Делл, основатель Dell, сказал это в 1999 году в интервью журналу Forbes, подчеркивая важность действия.

Почитать короткую биографию
И хабр, интересно

#Citation #Biography
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Ссылочные типы данных в Java

Ссылочные типы данных (reference types) являются неотъемлемой частью объектно-ориентированной модели Java. В отличие от примитивов, они представляют объекты и хранят ссылки (адреса) на область памяти, где находится фактическое содержимое.

1. Концепция и философия


Java — строго объектно-ориентированный язык, и ссылки — основа его динамической природы.

Зачем нужны ссылочные типы:

Инкапсуляция данных и поведения. Объекты объединяют данные и методы, действующие над ними.
Гибкость. Ссылочные типы позволяют моделировать сложные структуры (например, графы, деревья, коллекции).
Полиморфизм и наследование. Через ссылки возможна работа с объектами по интерфейсам и абстрактным типам.


List<String> names = new ArrayList<>(); // ссылка на объект ArrayList


2. Представление и поведение ссылок

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

String a = "Hello";
String b = a;
Обе переменные a и b ссылаются на один и тот же объект "Hello" в куче (heap). Изменение объекта (если он мутабелен) через одну ссылку отразится на другой.


Пример с мутабельным объектом:
List<Integer> list1 = new ArrayList<>();
List<Integer> list2 = list1;
list1.add(10);
System.out.println(list2); // [10]


3. Классы, интерфейсы и массивы

К ссылочным типам относятся:

Классы (например, String, Object, Scanner, ArrayList)
Интерфейсы (например, List, Runnable, Serializable)
Массивы (int[], String[], Object[][]) — в Java массивы — это объекты!
Специальный тип null — означает отсутствие объекта


4. Работа JVM с ссылками

При работе со ссылочными типами:
Объекты размещаются в куче (heap).
Ссылки могут храниться в стеке вызовов, в полях объектов, в массиве и т.д.
JVM использует сборку мусора (GC) для очистки неиспользуемых объектов.


class User {
String name;
}

User user1 = new User();
User user2 = user1;
user1 = null; // объект всё ещё доступен через user2


5. Особенности ссылочных типов

a) Сравнение ссылок
String a = new String("Java");
String b = new String("Java");
System.out.println(a == b); // false — разные объекты
System.out.println(a.equals(b)); // true — сравнение содержимого
== сравнивает ссылки, а equals() — содержимое (если метод переопределён корректно).


b) NullPointerException
String s = null;
System.out.println(s.length()); // исключение
Поэтому рекомендуется использовать Objects.requireNonNull, Optional, или делать явные проверки на null.


6. Автоматическая работа с памятью


Одно из главных преимуществ Java — автоматическое управление памятью. Не нужно вручную освобождать объекты, как в C/C++.

Но важно помнить:
Объекты "висят" в памяти, пока есть активные ссылки.
Циклические ссылки не мешают сборке мусора (в отличие от простых reference counting-систем).


7. Массивы как ссылочные типы

Массивы в Java — полноценные объекты.

int[] nums = {1, 2, 3};
System.out.println(nums.length); // 3
Массивы имеют поля и методы (length — поле, а не метод), и их тип — int[], String[] и т.д.


8. Использование в обобщениях

Ссылочные типы активно применяются в дженериках (обобщениях).

List<Integer> list = new ArrayList<>();


Нельзя использовать примитивы в параметрах типа:
List<int> wrongList; // ошибка
Поэтому применяются классы-обёртки: Integer, Double, Boolean и т.д.


9. Влияние на производительность

Работа со ссылками может быть дороже, чем с примитивами:
Дополнительные обращения к памяти
Участие в GC
Наличие виртуального вызова методов (vtable)
Частые создания объектов (например, при упаковке/распаковке)


Оптимизации:
Избегать ненужных аллокаций
Использовать StringBuilder вместо + в циклах
Применять ObjectPool, если объекты часто переиспользуются


#Java #для_новичков #beginner #reference_types
👍2
Что выведет код?

public class Task050625 {
public static void main(String[] args) {
Object[] objects = new Object[3];
objects[0] = 10;
objects[1] = "Hello";
objects[2] = new int[]{1, 2, 3};

System.out.println(objects[0] instanceof Number);
System.out.println(objects[1] instanceof CharSequence);
System.out.println(objects[2] instanceof Object);
}
}


#Tasks
👍1
Продолжаем выбирать темы для разбора и голосовать за рассмотрение предложенных! 🤓

Голосуем за тему к рассмотрению в эти выходные!

Выбираем новую тему!
(можете предложить что-то из того, что предлагали на прошлой и позапрошлых неделях и что проиграло в голосовании!)

Не стесняемся! ✌️
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Что такое StringBuilder и чем он отличается от String? 🤓

Ответ:

String — неизменяемый (immutable) класс. При конкатенации создается новый объект.

StringBuilder — изменяемый, эффективен для многократных изменений строки, так как не создает новые объекты.


#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
📌 Факт дня:

А вы знали, что термин "цифровой след" появился в 1990-х?

Понятие "digital footprint" (цифровой след) начало использоваться в 1990-х годах для описания следов активности пользователей в интернете, таких как посещения сайтов и посты. Сегодня это ключевой аспект конфиденциальности.


info


#facts
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
📌 Цитата дня: Анита Борг

"Разнообразие в технологиях — это не роскошь, а необходимость."


Анита Борг, основательница Grace Hopper Celebration, сказала это в 1997 году на конференции по женщинам в IT.

Почитать короткую биографию

#Citation #Biography
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Интеграция Liquibase с другими инструментами

Maven / Gradle

Maven

Добавьте зависимость в pom.xml:
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
<version>4.25.0</version>
</dependency>


Конфигурация через pom.xml:
<plugin>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-maven-plugin</artifactId>
<version>4.25.0</version>
<configuration>
<changeLogFile>src/main/resources/db/changelog/db.changelog-master.yaml</changeLogFile>
<url>jdbc:postgresql://localhost:5432/mydb</url>
<username>user</username>
<password>pass</password>
</configuration>
</plugin>


Запуск миграций:
mvn liquibase:update


Gradle

Добавьте в build.gradle:
plugins {
id 'org.liquibase.gradle' version '2.2.0'
}

dependencies {
liquibaseRuntime 'org.liquibase:liquibase-core:4.25.0'
liquibaseRuntime 'org.postgresql:postgresql:42.6.0'
}

liquibase {
changeLogFile 'src/main/resources/db/changelog/db.changelog-master.yaml'
url 'jdbc:postgresql://localhost:5432/mydb'
username 'user'
password 'pass'
}


Запуск:
gradle liquibaseUpdate


Spring Boot (автоконфигурация)

Spring Boot автоматически настраивает Liquibase, если он обнаружен в classpath.

Настройки в application.yml:
spring:
datasource:
url: jdbc:postgresql://localhost:5432/mydb
username: user
password: pass
liquibase:
change-log: classpath:db/changelog/db.changelog-master.yaml
enabled: true
contexts: dev # Фильтрация по контексту


Поведение:
Миграции запускаются при старте приложения.
Можно отключить через spring.liquibase.enabled=false.


Расширенные функции Liquibase

Динамические свойства (property)

Позволяют выносить повторяющиеся значения в переменные.

Пример (YAML):
databaseChangeLog:
- property:
name: default.schema
value: public
- changeSet:
id: 1
author: dev
changes:
- createTable:
tableName: ${default.schema}.users
columns:
- column:
name: id
type: INT


В
liquibase.properties:
default.schema=public


Через командную строку:
liquibase update -Ddefault.schema=public


Контексты (contexts) и фильтрация changeSet’ов

Контексты позволяют выбирать, какие changeSet’ы применять в определённых окружениях.

Пример (YAML):
- changeSet:
id: 2
author: dev
context: "dev,test" # Будет выполнен только в dev и test
changes:
- insert:
tableName: users
columns:
- column:
name: username
value: "test_user"

- changeSet:
id: 3
author: dev
context: "prod" # Только в production
changes:
- createIndex:
tableName: users
indexName: idx_user_email
columns:
- column:
name: email


Как передать контекст?

Через командную строку:
liquibase update --contexts="dev"


В Spring Boot:
spring:
liquibase:
contexts: dev


#Java #middle #Liquibase
👍3
Best Practices

Организация changelog-файлов

Рекомендуемая структура:
src/main/resources/db/changelog/
├── db.changelog-master.yaml # Главный файл
├── changes/
│ ├── 001-create-tables.yaml
│ ├── 002-add-indexes.yaml
│ └── 003-insert-data.yaml
└── rollback/
├── 001-rollback.yaml # Ручные откаты


Главный файл (db.changelog-master.yaml):
databaseChangeLog:
- includeAll:
path: db/changelog/changes/
relativeToChangelogFile: true


Почему так?

Удобно управлять версиями.
Легко находить изменения.


Тестирование миграций

Стратегии:
Локальная проверка:
liquibase validate  # Проверка синтаксиса
liquibase update # Применение в test-DB


Интеграционные тесты (JUnit + Testcontainers):
@Testcontainers
@SpringBootTest
class LiquibaseMigrationTest {
@Container
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15");

@Test
void testMigrations() {
// Spring Boot автоматически применит миграции
assertTrue(true); # Если не упало — значит, успешно
}
}


Работа в команде (избежание конфликтов)


Правила:

Именование changeSet’ов:
Используйте id: <дата>-<номер> (например, id: 20240315-1).
Указывайте автора (author: github_username).


Порядок изменений:
Не зависеть от порядка выполнения (например, не предполагать, что таблица A уже существует при создании B).

Использование preConditions:
- changeSet:
id: 20240315-1
author: dev
preConditions:
- tableExists:
tableName: users
changes:
- addColumn:
tableName: users
column:
name: phone
type: VARCHAR(20)


Регулярные обновления:
Перед началом работы выполняйте liquibase update, чтобы получить актуальную схему.

#Java #middle #Liquibase
👍2
Что выведет код?

import java.util.Optional;

public class Task060625 {
public static void main(String[] args) {
Optional<String> opt = Optional.ofNullable(null)
.or(() -> Optional.of("Java"))
.map(v -> ((String) v).toUpperCase());

System.out.println(opt.orElse("Default"));
}
}


#Tasks
🔥2
👍1
Продолжаем выбирать темы для разбора и голосовать за рассмотрение предложенных! 🤓

Голосуем за тему к рассмотрению в эти выходные!

Выбираем новую тему!
(можете предложить что-то из того, что предлагали на прошлой и позапрошлых неделях и что проиграло в голосовании!)

Не стесняемся! ✌️
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Что такое лямбда-выражения в Java? 🤓

Ответ:

Лямбда-выражения в Java — это краткий способ записи анонимных функций, которые можно передавать как аргументы в методы или сохранять в переменные. Они появились в Java 8 и позволяют писать более компактный и читаемый код, особенно при работе с функциональными интерфейсами (интерфейсами с одним абстрактным методом, например, Runnable, Comparator, Predicate).

Синтаксис лямбда-выражения:
(параметры) -> { тело_лямбды }

Если параметр один, скобки () можно опустить.
Если тело состоит из одной строки, фигурные скобки {} и return можно не писать.


#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
С 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
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
После проведенного голосования, определилась тема для рассмотрения в выходные - JavaMailSender.

Спасибо предложившему 👏, интересная тема, даже не знал о существовании такого модуля Spring. Есть мысли потом сделать видео гайд. Как смотрите?

Ну и читаем'с статейку

(примечание - код взят с открытых источников и мной не тестировался, уж извините)


JavaMailSender в Spring Boot


JavaMailSender — это интерфейс из Spring Framework, который упрощает работу с JavaMail API (перешедшим на Jakarta EE) и позволяет отправлять электронные письма из приложений на Spring Boot. Он используется вместе с зависимостью spring-boot-starter-mail и предоставляет удобный API для работы с SMTP-серверами. Поддерживаются простые текстовые письма, HTML-сообщения, вложения, inline-ресурсы и шаблоны.

Установка зависимости

Для использования JavaMailSender добавьте зависимость в ваш проект. В Spring Boot 3.x используется jakarta.mail вместо javax.mail.

Maven:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.angus</groupId>
<artifactId>jakarta.mail</artifactId>
<version>2.0.1</version>
</dependency>


Gradle:
implementation 'org.springframework.boot:spring-boot-starter-mail'
implementation 'org.eclipse.angus:jakarta.mail:2.0.1'


Базовая настройка почтового клиента

Настройте параметры SMTP-сервера в файле application.properties или application.yml.

Пример для Gmail:
spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username=your.email@gmail.com
spring.mail.password=${MAIL_PASSWORD}
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true


Если используется application.yml:
spring:
mail:
host: smtp.gmail.com
port: 587
username: your.email@gmail.com
password: ${MAIL_PASSWORD}
properties:
mail:
smtp:
auth: true
starttls:
enable: true

Примечание: Пароль лучше хранить в переменных окружения или внешних конфигурациях (например, Kubernetes Secrets) вместо прямого указания в файле.

Настройка для популярных SMTP-серверов

Настройки SMTP зависят от провайдера. Вот примеры для популярных сервисов.

Gmail
SMTP-сервер: smtp.gmail.com
Порт: 587 (STARTTLS) или 465 (SSL)
Рекомендуется использовать OAuth2 вместо пароля приложения.


Yandex
spring.mail.host=smtp.yandex.ru
spring.mail.port=465
spring.mail.username=your.email@yandex.ru
spring.mail.password=${MAIL_PASSWORD}
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.ssl.enable=true


Mail.ru
spring.mail.host=smtp.mail.ru
spring.mail.port=465
spring.mail.username=your.email@mail.ru
spring.mail.password=${MAIL_PASSWORD}
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.ssl.enable=true


Outlook / Office365
spring.mail.host=smtp.office365.com
spring.mail.port=587
spring.mail.username=your.email@outlook.com
spring.mail.password=${MAIL_PASSWORD}
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true


Amazon SES
spring.mail.host=email-smtp.us-east-1.amazonaws.com
spring.mail.port=587
spring.mail.username=your-ses-access-key
spring.mail.password=your-ses-secret-key
spring.mail.properties.mail.smtp.starttls.enable=true


Примечание: Для корпоративных SMTP-серверов уточняйте настройки у администратора. Для Amazon SES требуется настройка в AWS Console.


#Java #middle #on_request #JavaMailSender
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Настройка OAuth2 для Gmail

Для 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
👍1