Java for Beginner
871 subscribers
1.01K photos
275 videos
14 files
1.68K links
Канал от новичков для новичков!
Изучайте Java вместе с нами!
Здесь мы обмениваемся опытом и постоянно изучаем что-то новое!

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

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
Что такое switch с паттернами (Pattern Matching for Switch)? 🤓

Ответ:

Начиная с Java 17 (preview с Java 17, финал в Java 21), switch может сопоставлять не только константы, но и типы объектов с автоматическим приведением.

Пример: 
String result = switch (obj)
{
case Integer i -> "Integer: " + i;
case String s -> "String: " + s;
case null -> "null"; default -> "Unknown";
};.


Также поддерживаются охранные условия (guards): case Point p when p.x() > 0 -> ....

Это делает switch полноценным инструментом для работы с иерархиями типов, уменьшая количество instanceof и приведений.



#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
История технологии сегодня — 25 июля

ℹ️ Кто родился в этот день

Джон Баннистер Гуденаф (англ. John Bannister Goodenough; 25 июля 1922, Йена, Тюрингия[вд] — 25 июня 2023, Остин) — американский учёный, специалист в области физики и химии твёрдого тела и материаловедения. Известен своим вкладом в разработку первых литий-ионных аккумуляторов.


🌐 Знаковые события

1907 — русский физик Борис Розинг подал заявку на патент на «Способ электрической передачи изображений на расстояние», то есть телевидение.


#Biography #Birth_Date #Events #25июля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
История технологии сегодня — 26 июля

ℹ️ Кто родился в этот день

Джеймс Эфрэйм Лавлок (англ. James Ephraim Lovelock; 26 июля 1919, Летчуэрт, Хартфордшир — 26 июля 2022[3], Эбботсбери[вд], Юго-Западная Англия) — британский учёный, независимый исследователь, биофизик, химик, футуролог. Приобрёл известность как создатель Гипотезы Геи (согласно которой планета Земля функционирует как суперорганизм), а также как активный сторонник использования атомной энергии.

Исаак Бэббитт (англ. Isaac Babbitt; 26 июля 1799, Тонтон, Массачусетс, США — 26 мая 1862, Сомервилл, Массачусетс, США) — американский изобретатель. В 1839 году он изобрел подшипник из металлического сплава на основе олова с низким коэффициентом трения. Этот металл был назван по его имени баббитом, и до сих пор широко используется в подшипниках.


🌐 Знаковые события

1925 — впервые поднялся в воздух самолёт «К-1» конструкции К. А. Калинина — первый отечественный пассажирский самолёт, рекомендованный к серийному выпуску.

1989 — 24-летнему американскому студенту Роберту Моррису предъявляется обвинение в создании и запуске компьютерного вируса. Моррис становится первым создателем вируса, подвергнутым уголовному преследованию.


#Biography #Birth_Date #Events #26июля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Как отдыхать от кода, чтобы не потерять к нему интерес.

Было время, когда я изучая программирование и готовясь к собеседованиям, просиживал за изучением Java по 12-15 часов в день. Это был цейтнот и время поджимало, поэтому я не жалел себя.
И прекрасно помню, как вставая от компа, я понимал, что вообще не соображаю. Мозг, как онемевший орган, переставал реагировать на внешние раздражители.


Учиться в таком режиме было тяжело, но быстро. А ощущение отупения накапливалось и с каждым днем было все сложнее заставить себя учиться. Все сложнее было воспринимать. и что важнее - осознавать что-то новое.

Тогда я и понял, что отдых для мозга не менее важен, чем для мышц при напряженной физической работе.

Вот мои советы:

1. Программирование — это умственный стресс и нагрузка. Значит, отдых должен быть противоположным.


Многие думают: «Отдохну, полежу, сериальчик посмотрю». Это может сработать разок, но по сути — это просто пассивная стимуляция. Усталый мозг не отключается, он продолжает переваривать входящие, только уже из Netflix.

В психологии есть понятие когнитивной разрядки (cognitive offloading) — это когда мозг сознательно уходит от абстрактных нагрузок к чему-то телесному и простому.

Поэтому, будут крайне полезны:
🔵 Регулярные пешие прогулки, без телефона в руках.
🔵 Физнагрузки (бег, плавание, даже уборка) — вообще мастхев для программистов.

Я в свою очередь стараюсь заниматься хотя-бы через день. Ничего лучше так не прочищает мозг, чем 5-километровая пробежка по парку
😉.


2. Отдых не должен быть побегом. Он должен быть паузой.

Плохо, когда однажды перенагрузив мозг, ты вновь пытаешься это повторить, а он сопротивляется. Ты прямо-таки можешь ощущать его сопротивление, нежелание осознавать прочитанное.
И ты пытаешься сбежать от программирования в какие-то рандомные развлечения. Это может вызвать ненужные тебе переживания, самоосуждение, тут и до "темного попутчика"
(о котором мы говорили в статье) недалеко.

Поэтому правильный, а что немаловажно, своевременный отдых — это контекстный отдых, когда ты всё ещё как бы рядом с ИТ, но без задачи что-то выдать.

Примеры:
🔵Чтение биографий учёных, разработчиков — это вдохновляет и не грузит.
🔵Хобби: пайка электроники, музыка, геймдев или гейминг — лёгкое смежное времяпрепровождение.
🔵Визуальные виды деятельности: рисование, моделирование, pixel art.

В психологии это описывается как ресторативная активность (restorative experiences) — действия, которые возвращают ощущение контроля и удовольствия от процесса.

И твое «Хочу программировать» останется внутри даже в перерыве от него, ведь ты не перенапрягаешься.



3. Мини-проекты без цели.

Порой, когда ты перегружен "сложным" программированием и чувствуешь, что уже не вывозишь, полезно переключиться на "развлекательное" программирование - написать что-то простое и веселое.

Попробуй написать:
🔵Телеграм - бота, который будет постить твои рандомные мысли.
🔵Код, сортирующий папки по настроению (буквально по цветам или дням недели).
🔵Программу, делающую любую глупость, но красиво ☺️.

Это и есть "игра с собой" (self-determined play) — процесс, в котором мотивация рождается не из цели, а из самого процесса. В котором ты отдыхаешь, но при этом не теряешь связи с программированием и получаешь удовольствие от процесса.


4. Общение в среде программирования.

Иногда, после высокой умственной нагрузки, достаточно оставаться рядом с темой. Расслабиться и послушать подкасты, посмотреть чужие лайвкодинги.
А можно найти сообщество (похожее на наше
☺️) и программистов, с которыми пообсуждать околопрограммерские вопросы.

Это вызывает ощущение сопричастности.

В когнитивной психологии это называется пассивное обучение (incidental learning) — когда ты усваиваешь что-то из обсуждения, даже не замечая.
А это в свою очередь, поддерживает интерес и мотивацию (
Deci & Ryan, 2000).


Эффективный отдых — это не пассивность, а активная смена когнитивной нагрузки. Хороший отдых питает тот же источник интереса, что и программирование, но делает это без давления.


А как вы боретесь с усталостью? Пишите в комментариях! 💪


#motivation
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥1
История технологии сегодня — 27 июля

ℹ️ Кто родился в этот день

Сэр Демис Хассабис (родился 27 июля 1976 г.) — британский исследователь в области искусственного интеллекта (ИИ) и предприниматель. Он является генеральным директором и соучредителем Google DeepMind и Isomorphic Labs, а также советником правительства Великобритании по вопросам ИИ. В 2024 году Хассабис и Джон М. Джампер были совместно удостоены Нобелевской премии по химии за свой вклад в исследования ИИ в области предсказания структуры белков.


🌐 Знаковые события

1985 — первый полёт спортивно-пилотажного акробатического самолёта СУ-26М, в конструкции которого широко применены композитные материалы.


#Biography #Birth_Date #Events #27июля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥2
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2👍1
Раздел 11. Работа с файлами, I/O и сетью (NIO.2)

Глава 2. Современный NIO.2 (java.nio.file)

SeekableByteChannel — произвольный доступ к файлу. Символические и жёсткие ссылки

До этого момента мы работали с файлами через высокоуровневые абстракции: читали целиком, писали целиком, копировали, перемещали. Но файловая система — это в первую очередь последовательность байтов на диске, и иногда нужно читать или писать не с начала, а с произвольной позиции.

Для этого в NIO.2 существует интерфейс SeekableByteChannel. Он объединяет возможности чтения, записи и позиционирования в единый канал, заменяя устаревший RandomAccessFile.

Вторая часть посвящена ссылкам в файловой системе — механизму, который позволяет одним данным соответствовать несколько имён. Символические и жёсткие ссылки — фундаментальная концепция Unix-файловых систем, и их непонимание часто приводит к багам при обходе деревьев, подсчёте размеров и резервном копировании.


Часть 1. SeekableByteChannel

SeekableByteChannel — это интерфейс в пакете java.nio.channels, расширяющий ByteChannel. ByteChannel в свою очередь объединяет ReadableByteChannel и WritableByteChannel, то есть поддерживает и чтение, и запись. Добавление приставки "Seekable" означает, что канал позволяет изменять текущую позицию чтения/записи — "перематывать" указатель в произвольное место файла.

Канал (channel) в Java NIO — это абстракция для соединения с сущностью, способной выполнять операции ввода-вывода: файл, сокет, пайп. Каналы работают с буферами (ByteBuffer), а не с потоками байтов. Это позволяет использовать прямой (direct) ввод-вывод, минуя промежуточное копирование в кучу JVM.

Интерфейс SeekableByteChannel декларирует три ключевых метода, отсутствующих в обычном ByteChannel:
position() — возвращает текущую позицию в файле.
position(long newPosition) — устанавливает новую позицию.
size() — возвращает текущий размер файла в байтах.


Открытие канала: Files.newByteChannel()

Метод Files.newByteChannel(Path path, OpenOption... options) возвращает SeekableByteChannel для указанного пути. Это фабричный метод, который делегирует создание канала текущему FileSystemProvider.
import java.nio.file.*;
import java.nio.channels.SeekableByteChannel;
import java.nio.ByteBuffer;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

public class ChannelOpener {

public void openForRead(Path file) throws IOException {
// Открываем только для чтения
try (SeekableByteChannel channel = Files.newByteChannel(file, StandardOpenOption.READ)) {
System.out.println("Размер файла: " + channel.size());
System.out.println("Текущая позиция: " + channel.position());
}
}

public void openForWrite(Path file) throws IOException {
// Открываем для чтения и записи, создаём если нет, обрезаем если есть
try (SeekableByteChannel channel = Files.newByteChannel(file,
StandardOpenOption.READ,
StandardOpenOption.WRITE,
StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING)) {

// Записываем данные
ByteBuffer buffer = ByteBuffer.wrap("Hello, World".getBytes(StandardCharsets.UTF_8));
channel.write(buffer);
}
}
}


StandardOpenOption — режимы открытия

StandardOpenOption — это enum, определяющий, как именно открывать или создавать файл. Каждая опция соответствует флагу системного вызова open() (POSIX):
READ — открыть для чтения. Файл должен существовать. Соответствует флагу O_RDONLY.
WRITE — открыть для записи. Файл должен существовать. Соответствует флагу O_WRONLY (в комбинации с READ даёт O_RDWR).
APPEND — все операции записи производятся в конец файла, независимо от текущей позиции. Соответствует флагу O_APPEND. Позиция после записи не изменяется (остаётся там, где была до записи).
CREATE — создать файл, если он не существует. Соответствует O_CREAT.
CREATE_NEW — создать файл, но выбросить исключение, если он уже существует. Соответствует O_CREAT | O_EXCL. Атомарная операция.
TRUNCATE_EXISTING — если файл существует и открыт для записи, обрезать его размер до 0. Соответствует O_TRUNC.
DELETE_ON_CLOSE — удалить файл при закрытии канала. Полезно для временных файлов.
SYNC — каждая операция записи синхронизирует данные и метаданные с диском. Соответствует O_SYNC. Сильно снижает производительность, но гарантирует durability.
DSYNC — синхронизирует только данные, не метаданные. Соответствует O_DSYNC.
SPARSE — создать разреженный файл (sparse file), если файловая система поддерживает.

Разреженный файл (sparse file) — это файл, в котором последовательности нулевых байтов не занимают место на диске. Файловая система хранит только информацию о "дырах" (holes), а не сами нули. При чтении таких областей возвращаются нулевые байты. Разреженные файлы экономят дисковое пространство при работе с большими файлами, большая часть которых пуста.

Durability (стойкость) — свойство системы хранения, гарантирующее, что записанные данные сохранятся даже при сбое питания. SYNC и DSYNC принудительно сбрасывают данные из кэша страниц ОС на физическое устройство хранения.


Чтение и запись с произвольной позиции
public class RandomAccessExample {

public void readFromPosition(Path file, long position, int length) throws IOException {
try (SeekableByteChannel channel = Files.newByteChannel(file, StandardOpenOption.READ)) {
// Устанавливаем позицию
channel.position(position);

ByteBuffer buffer = ByteBuffer.allocate(length);
int bytesRead = channel.read(buffer);

buffer.flip(); // переключаем буфер из режима записи в режим чтения
byte[] data = new byte[bytesRead];
buffer.get(data);

System.out.println("Прочитано с позиции " + position + ": " + new String(data));
}
}

public void writeAtPosition(Path file, long position, String data) throws IOException {
try (SeekableByteChannel channel = Files.newByteChannel(file,
StandardOpenOption.READ, StandardOpenOption.WRITE)) {

channel.position(position);

ByteBuffer buffer = ByteBuffer.wrap(data.getBytes(StandardCharsets.UTF_8));
channel.write(buffer);

// После записи позиция сдвинулась на количество записанных байт
System.out.println("Новая позиция: " + channel.position());
}
}

public void appendToFile(Path file, String data) throws IOException {
// Способ 1: через APPEND опцию
try (SeekableByteChannel channel = Files.newByteChannel(file,
StandardOpenOption.WRITE, StandardOpenOption.APPEND)) {
ByteBuffer buffer = ByteBuffer.wrap(data.getBytes(StandardCharsets.UTF_8));
channel.write(buffer);
}

// Способ 2: через position(size()) — ручное позиционирование в конец
try (SeekableByteChannel channel = Files.newByteChannel(file,
StandardOpenOption.READ, StandardOpenOption.WRITE)) {
channel.position(channel.size()); // переходим в конец
ByteBuffer buffer = ByteBuffer.wrap(data.getBytes(StandardCharsets.UTF_8));
channel.write(buffer);
}
}
}


ByteBuffer
— это класс в Java NIO, представляющий блок памяти, через который производится ввод-вывод. Буфер имеет три ключевых свойства: capacity (ёмкость), limit (предел) и position (текущая позиция). Метод flip() переключает буфер из режима записи (write) в режим чтения (read): устанавливает limit = position, position = 0.


#Java #для_новичков #beginner #IO #NIO #SeekableByteChannel
👍4
Сравнение с RandomAccessFile

Класс java.io.RandomAccessFile существует с Java 1.0 и предоставляет аналогичный функционал.

Однако у него есть архитектурные недостатки:
Не работает с Path: RandomAccessFile принимает только String или File, не Path. Для использования с NIO.2 требуется конвертация.
Не поддерживает символические ссылки корректно: RandomAccessFile всегда следует по ссылкам, нет опции NOFOLLOW_LINKS.
Не интегрирован с NIO: RandomAccessFile работает со своими методами read(), write(), не с ByteBuffer. Хотя с Java 1.4 у него появился метод getChannel(), возвращающий FileChannel.
Менее гибкая модель опций: RandomAccessFile имеет только два режима — "r" (read) и "rw" (read-write). Нет поддержки APPEND, CREATE_NEW, SYNC и других флагов.
Не поддерживает кастомные FileSystem: RandomAccessFile работает только с дефолтной файловой системой. SeekableByteChannel через FileSystemProvider может работать с ZIP, сетевыми ФС и т.д.
// Старый способ (RandomAccessFile)
try (RandomAccessFile raf = new RandomAccessFile("data.bin", "rw")) {
raf.seek(100); // позиционирование
raf.write("data".getBytes());
}

// Новый способ (SeekableByteChannel)
try (SeekableByteChannel channel = Files.newByteChannel(Paths.get("data.bin"),
StandardOpenOption.READ, StandardOpenOption.WRITE)) {
channel.position(100);
channel.write(ByteBuffer.wrap("data".getBytes()));
}

FileChannel — это конкретная реализация SeekableByteChannel в Java, работающая с файлами локальной файловой системы. Он предоставляет дополнительные методы: map() (memory-mapped files), transferTo()/transferFrom() (zero-copy), lock() (файловые блокировки), force() (синхронизация с диском).


Часть 2. Символические и жёсткие ссылки

В файловых системах Unix имя файла — это не сам файл, а ссылка на структуру данных, хранящую метаданные и указатели на блоки. Эта структура называется inode. Директория — это просто список пар "имя — номер inode". Ссылка — это запись в этом списке.

inode (index node) — структура данных в файловой системе Unix, содержащая всё, кроме имени файла и его содержимого: тип файла, права доступа, владелец, группа, размер, временные метки, счётчик ссылок и указатели на блоки данных. Номер inode уникален в пределах файловой системы (раздела диска).


Жёсткая ссылка (hard link)

Жёсткая ссылка — это дополнительное имя для существующего файла, указывающее на тот же inode.

Все жёсткие ссылки на файл равноправны: нет "оригинала" и "копий". Каждая жёсткая ссылка увеличивает счётчик ссылок (link count) в inode на 1.

Когда файл удаляется через unlink() (системный вызов, лежащий в основе Files.delete()), ядро уменьшает счётчик ссылок. Если счётчик достигает 0 и нет открытых файловых дескрипторов на этот inode, блоки данных помечаются как свободные. Если счётчик 0, но дескрипторы открыты, файл становится "невидимым" в файловой системе, но продолжает существовать до закрытия всех дескрипторов.

Ограничения жёстких ссылок:
Нельзя создать на директорию (за исключением системных . и ..). Это предотвращает циклы в файловой системе.
Нельзя создать между разными файловыми системами (разделами диска), так как inode уникален только в пределах одной ФС.
Нельзя создать на несуществующий файл.
import java.nio.file.*;
import java.io.IOException;

public class HardLinkManager {

public void createHardLink(Path existingFile, Path newLink) throws IOException {
// Проверяем, что исходный файл существует и на той же файловой системе
if (!Files.isRegularFile(existingFile)) {
throw new IllegalArgumentException("Исходный файл не существует или не является обычным файлом");
}

// createLink создаёт жёсткую ссылку
Files.createLink(newLink, existingFile);

// Проверяем: оба пути указывают на один inode
Object key1 = Files.readAttributes(existingFile, BasicFileAttributes.class).fileKey();
Object key2 = Files.readAttributes(newLink, BasicFileAttributes.class).fileKey();

if (key1 != null && key1.equals(key2)) {
System.out.println("Жёсткая ссылка создана. Оба пути указывают на inode " + key1);
}
}
}


Files.createLink(Path link, Path existing) выполняет системный вызов link() (POSIX), который создаёт новую запись в директории, указывающую на тот же inode, что и existing. Это атомарная операция на уровне файловой системы.


Символическая ссылка (symbolic link, symlink)

Символическая ссылка — это специальный файл, содержащий путь (строку) к другому файлу или директории. В отличие от жёсткой ссылки, символическая ссылка имеет свой собственный inode и не влияет на счётчик ссылок целевого файла. Она может указывать на несуществующий объект (висячая ссылка, dangling symlink), на директорию, на файл в другой файловой системе или даже на саму себя.

Висячая ссылка (dangling symlink) — символическая ссылка, целевой объект которой был удалён или перемещён. При попытке доступа к такой ссылке системный вызов вернёт ENOENT (No such file or directory).

Символические ссылки могут быть абсолютными (начинаются с /, указывают на фиксированный путь в файловой системе) или относительными (указывают относительно директории, в которой находится ссылка).

Относительные ссылки предпочтительны, так как сохраняют работоспособность при перемещении дерева.
public class SymlinkManager {

public void createSymlink(Path link, Path target) throws IOException {
// Создаём символическую ссылку
// target может быть абсолютным или относительным
Files.createSymbolicLink(link, target);
}

public void createRelativeSymlink(Path linkDir, Path targetFile) throws IOException {
// Строим относительный путь от linkDir до targetFile
Path relativeTarget = linkDir.relativize(targetFile);
Path link = linkDir.resolve("shortcut");

Files.createSymbolicLink(link, relativeTarget);
}

public void inspectSymlink(Path link) throws IOException {
if (!Files.isSymbolicLink(link)) {
System.out.println("Это не символическая ссылка");
return;
}

// Читаем целевой путь, хранящийся в ссылке
Path target = Files.readSymbolicLink(link);
System.out.println("Ссылка указывает на: " + target);

// Проверяем, существует ли целевой объект
if (Files.exists(link)) {
System.out.println("Целевой объект существует");

// Читаем атрибуты целевого объекта (следуем по ссылке)
BasicFileAttributes attrs = Files.readAttributes(link, BasicFileAttributes.class);
System.out.println("Тип цели: " + (attrs.isDirectory() ? "директория" : "файл"));
} else {
System.out.println("Висячая ссылка — цель не существует");
}

// Читаем атрибуты самой ссылки (не следуем по ней)
BasicFileAttributes linkAttrs = Files.readAttributes(
link, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS
);
System.out.println("Размер самой ссылки: " + linkAttrs.size() + " байт (длина пути)");
}
}

Files.readSymbolicLink(Path link) возвращает Path, содержащий строку, записанную в символической ссылке. Это не резолвит путь — просто читает содержимое ссылки. Размер символической ссылки (возвращаемый Files.size()) равен длине строки пути в байтах, а не размеру целевого файла.


#Java #для_новичков #beginner #IO #NIO #SeekableByteChannel
👍4
Опасности символических ссылок при обходе дерева

Символические ссылки на директории создают риск бесконечного цикла при рекурсивном обходе. Если директория A содержит символическую ссылку на свою родительскую директорию, обход зайдёт в родителя, снова найдёт A, снова зайдёт в ссылку — и так до переполнения стека или исчерпания ресурсов.
public class SafeTreeWalker {

// ОПАСНО: может зациклиться, если есть symlink на предка
public void dangerousWalk(Path root) throws IOException {
try (Stream<Path> stream = Files.walk(root, FileVisitOption.FOLLOW_LINKS)) {
stream.forEach(System.out::println); // риск бесконечного цикла
}
}

// БЕЗОПАСНО: не следуем по символическим ссылкам
public void safeWalk(Path root) throws IOException {
try (Stream<Path> stream = Files.walk(root)) { // без FOLLOW_LINKS
stream.forEach(System.out::println);
}
}

// БЕЗОПАСНО: следуем по ссылкам, но отслеживаем посещённые inode
public void safeWalkWithCycleDetection(Path root) throws IOException {
Set<Object> visitedInodes = new HashSet<>();

Files.walkFileTree(root, EnumSet.of(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE,
new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
Object key = attrs.fileKey();
if (key != null) {
if (visitedInodes.contains(key)) {
System.out.println("Обнаружен цикл через ссылку: " + file);
return FileVisitResult.SKIP_SIBLINGS;
}
visitedInodes.add(key);
}
System.out.println(file);
return FileVisitResult.CONTINUE;
}
}
);
}
}


В безопасном варианте с отслеживанием fileKey() (пара device_id + inode) мы можем обнаружить, что уже посещали этот inode, и пропустить его. Это защищает от циклов через жёсткие ссылки и символические ссылки на директории.


Сравнение жёстких и символических ссылок

Жёсткая ссылка:
Указывает напрямую на inode.
Не может указывать на директорию (кроме системных).
Не может пересекать границы файловых систем.
Не может указывать на несуществующий файл.
Увеличивает счётчик ссылок в inode.
Не имеет собственного размера (размер равен размеру файла).
Удаление одной ссылки не влияет на другие.

Символическая ссылка:
Указывает на путь (строку), имеет свой inode.
Может указывать на директорию.
Может пересекать границы файловых систем.
Может указывать на несуществующий файл (висячая ссылка).
Не влияет на счётчик ссылок целевого файла.
Имеет размер, равный длине строки пути.
При удалении целевого файла становится висячей.


Путь байтов в памяти JVM при работе с SeekableByteChannel и ссылками

SeekableByteChannel: путь данных

При Files.newByteChannel(path, StandardOpenOption.READ, StandardOpenOption.WRITE):
Объект Path в куче преобразуется в байты пути в нативной памяти. Выполняется системный вызов open() с флагами O_RDWR. Ядро ОС проверяет права доступа, находит или создаёт inode, открывает файловый дескриптор и возвращает его в пространство процесса.
JVM создаёт объект FileChannel (реализация SeekableByteChannel в OpenJDK) в куче (Heap), в Young Generation.

Этот объект содержит:
Целочисленный файловый дескриптор (хранится как int в поле объекта).
Ссылку на FileSystem.
Флаги режима открытия.
Кэшированное значение позиции (для уменьшения системных вызовов lseek).
При вызове channel.position(100):
Если кэшированная позиция уже 100, системный вызов не выполняется.
Иначе выполняется lseek(fd, 100, SEEK_SET) (POSIX), который перемещает указатель чтения-записи файлового дескриптора. Это операция только над метаданными дескриптора, данные на диске не читаются.

При channel.read(buffer):
Выполняется системный вызов readv() или pread() (если позиция задана явно). Данные читаются из кэша страниц ОС (page cache) в нативную память, а затем копируются в ByteBuffer.
Если ByteBuffer — direct (создан через ByteBuffer.allocateDirect()), данные копируются напрямую в нативную память буфера, минуя кучу JVM. Это zero-copy на уровне JVM: нет промежуточного массива byte[] в куче.
Если ByteBuffer — heap (создан через ByteBuffer.allocate()), JVM выделяет временный direct буфер в нативной памяти, копирует туда данные из ОС, а затем копирует из нативного буфера в массив byte[] в куче. Это лишнее копирование, но необходимо, так как системные вызовы работают только с нативной памятью.

Direct ByteBuffer — это буфер, размещённый в нативной памяти (вне кучи JVM). Он создаётся через ByteBuffer.allocateDirect(size) и управляется JVM, но не подлежит обычной сборке мусора. Память освобождается, когда буфер становится недостижимым и Cleaner (специальный механизм JVM) вызывает free() для нативной памяти.

При channel.write(buffer):
Данные из ByteBuffer копируются в кэш страниц ОС (для direct буфера — напрямую, для heap — через временный direct буфер).
Запись в кэш страниц — это операция в памяти, быстрая. Физическая запись на диск происходит позже, когда ядро решает сбросить "грязные" страницы (dirty pages) на устройство хранения.
Если открыт с SYNC или DSYNC, после записи выполняется fsync() или fdatasync(), который принудительно сбрасывает кэш на диск. Это блокирующая операция, зависящая от скорости диска.
Объект FileChannel остаётся в куче до закрытия. Если он локальная переменная в try-with-resources, он становится мусором после выхода из блока и собирается Minor GC. Файловый дескриптор закрывается через close(), а не через GC.


Создание ссылок: путь данных

При Files.createSymbolicLink(link, target):
Объекты link и target (оба Path) находятся в куче. Их строковые представления извлекаются.
Выполняется системный вызов symlink(targetPath, linkPath) (POSIX). Ядро ОС:
Создаёт новый inode типа "символическая ссылка".
Записывает строку targetPath в блоки данных этого inode.
Добавляет запись в родительскую директорию link, связывающую имя с новым inode.
Никаких новых объектов в куче JVM не создаётся. Метод возвращает Path link (тот же объект, что был передан).

При Files.createLink(newLink, existing):
Выполняется системный вызов link(existingPath, newLinkPath) (POSIX).
Ядро находит inode существующего файла, увеличивает его счётчик ссылок на 1, и добавляет новую запись в директорию newLink, указывающую на тот же inode.
Никаких объектов в куче не создаётся. Операция полностью атомарна на уровне файловой системы.


Работа GC с каналами и ссылками

Объекты SeekableByteChannel и Path при создании ссылок — это обычные объекты в куче.

Они управляются стандартным механизмом GC:
Создаются в Eden (Young Generation).
При короткоживущем использовании (внутри метода с try-with-resources) собираются при следующей Minor GC.
Если канал открыт и сохранён в долгоживущем поле (например, пул соединений к файлам), объект переходит в Old Generation и живёт до Major GC.
Важно: ByteBuffer.allocateDirect() создаёт буфер в нативной памяти. Эта память не входит в кучу и не управляется GC напрямую. Однако сам объект DirectByteBuffer (обёртка в куче) управляется GC. Когда обёртка собирается GC, внутренний механизм Cleaner вызывает нативный метод для освобождения нативной памяти.

Cleaner — это механизм в JVM (класс java.lang.ref.Cleaner с Java 9, ранее sun.misc.Cleaner), который позволяет регистрировать callback-метод, вызываемый при сборке мусора определённого объекта. Используется для освобождения нативных ресурсов, ассоциированных с Java-объектами, например, нативной памяти DirectByteBuffer.

Однако Cleaner не гарантирует немедленное освобождение — нативная память может оставаться занятой до следующей сборки мусора. Поэтому для критичных ресурсов (файловые дескрипторы, каналы) всегда используется явное закрытие через close(), а не полагание на GC и Cleaner.


#Java #для_новичков #beginner #IO #NIO #SeekableByteChannel
👍4
Раскатил обновление https://devforge.ru/

Обновлений много:
📍Добавлена логика мультичатовости. Теперь можно общаться как в Общем чате так и создавать личные, приглашая туда кого пожелаете.
📍Добавлена возможность писать, редактировать и отправлять на проверку свои статьи. Статьи поддерживают язык схем - Mermaid. Пишете и отправляете на проверку. Если все хорошо статья будет опубликована.
📍Авторизация организована через Authentik. Более малое количество времени на токены, но зато надежнее.

Кроме того куча мелких исправлений и новых багов ждут вас! 😁

пысы: все предыдущие аккаунты удалены. не стесняйтесь регаться заново
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3👍1
Что выведет код?

import java.nio.channels.SeekableByteChannel;
import java.nio.file.*;
import java.nio.*;

public class Task270726 {
public static void main(String[] args) throws Exception {
Path path = Paths.get("test.txt");
try (SeekableByteChannel ch = Files.newByteChannel(path,
StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.READ)) {
ch.write(ByteBuffer.wrap("Hello".getBytes()));
ch.position(10);
ch.write(ByteBuffer.wrap("World".getBytes()));
System.out.println(ch.size());
}
}
}


#Tasks
👍2
Варианты ответа:
Anonymous Quiz
25%
0
0%
5
25%
10
50%
15
👍2
Что такое String.formatted() и чем отличается от String.format()? 🤓

Ответ:

"Hello %s".formatted("World") (Java 15)
— это метод экземпляра String, который делает то же, что и статический String.format(), но в более удобном синтаксисе для цепочек вызовов.

Внутри он вызывает String.format(this, args).

Отличие только в синтаксисе: formatted() — метод объекта, format() — статический метод. Оба поддерживают спецификаторы (%s, %d, %n).

Это особенно удобно с текстовыми блоками: """ Name: %s """.formatted(name).



#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Ребят, с сегодняшнего дня, основные статьи будут публиковаться и на https://devforge.ru/, но на день раньше!

Оцените удобство чтения и формата первой статьи на портале. 🙂

Для написания рецензий и комментов придется зарегистрироваться 🧑‍💻

Ссылка - тык ✈️
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
История технологии сегодня — 28 июля

ℹ️ Кто родился в этот день

Па́вел Алексе́евич Черенко́в (15 [28] июля 1904, Новая Чигла, Бобровский уезд, Воронежская губерния, Российская империя — 6 января 1990, Москва, СССР) — советский физик-ядерщикнобелевский лауреат (1958), академик АН СССР (1970). Основные работы Черенкова посвящены физической оптикеядерной физикефизике частиц высоких энергий. В 1934 году обнаружил специфическое голубое свечение прозрачных жидкостей при облучении быстрыми заряженными частицами. Показал отличие данного вида излучения от флуоресценции. В 1936 году установил основное его свойство — направленность излучения, образование светового конуса, ось которого совпадает с траекторией движения частицы. В 1958 году вместе с Таммом и Франком был награждён Нобелевской премией по физике «за открытие и истолкование эффекта Черенкова». 

Никола́й Никола́евич Андре́ев (16 [28] июля 1880, село Курманы, Полтавская губерния, Российская империя — 31 декабря 1970, Москва, СССР) российский и советский физик; специалист в области акустики. Дал строгую теорию распределения звука в движущихся средах. Осуществил исследования по теории распространения звука вдоль поглощаемых поверхностей, теории акустических фильтров и звуковых волн конечной амплитуды. Ряд работ связан с изучением спектра затухающих колебаний, с исследованием колебаний кристаллических и анизотропных сред, вопросов реверберации звука и звукоизоляции. Под его руководством в нашей стране были начаты исследования по нелинейной акустике, по распространению звука в слоистых средах, электромеханическим активным материалам. Создал школу в области физической и технической акустики.

Ро́берт Гук (англ. Robert Hooke; Роберт Хук, 18 (28) июля 1635 — 3 (14) марта 1703) — английский естествоиспытатель и изобретатель. Член Лондонского королевского общества (1663).
К числу открытий Гука принадлежат:
- открытие пропорциональности между упругими растяжениями, сжатиями и изгибами, и производящими их напряжениями (закон Гука),
- правильная формулировка закона всемирного тяготения (приоритет Гука оспаривался Ньютоном, но, по-видимому, не в части формулировки — сила тяготения обратно пропорциональна квадрату расстояния; кроме того, Ньютон утверждал о независимом и более раннем открытии этой формулы, которую, однако, до открытия Гуком никому не сообщал),
- открытие цветов тонких плёнок (то есть, в конечном итоге, явления интерференции света),
- идея о волнообразном распространении света (более или менее одновременно с Гюйгенсом), экспериментальное обоснование её открытой Гуком интерференцией света, волновая теория света,
- гипотеза о поперечном характере световых волн,
- открытия в акустике, например, демонстрация того, что высота звука определяется частотой колебаний,
- теоретическое положение о сущности теплоты как движения частиц тела,
- открытие постоянства температуры таяния льда и кипения воды,
- первое наблюдение живой клетки с помощью усовершенствованного им микроскопа; также женской яйцеклетки и мужских сперматозоидов. Гуку же принадлежит сам термин «клетка» (англ. cell).

Чарлз Хард Та́унс (англ. Charles Hard Townes; 28 июля 1915, Гринвилл, Южная Каролина — 27 января 2015, Окленд, Калифорния) — американский учёный, физик-ядерщик, лауреат Нобелевской премии по физике (1964). Основные труды Таунса посвящены радиоспектроскопииквантовой электронике и её приложениям, нелинейной оптикерадиоастрономии. Независимо от А. М. Прохорова и Н. Г. Басова выдвинул идею нового принципа генерации и усиления электромагнитных волн и на его основе совместно с сотрудниками создал первый квантовый генератор — мазер на аммиаке (1954). В 1958 году совместно с А. Шавловым обосновали и запатентовали возможность создания оптического квантового генератора (лазера). В 1964 «за фундаментальные работы в области квантовой электроники, которые привели к созданию излучателей и усилителей на лазерно-мазерном принципе», Таунс совместно с Н. Г. Басовым и А. М. Прохоровым был удостоен Нобелевской премии по физике.


🌐 Знаковые события

1959 — В Англии впервые введены почтовые коды и установлены автоматические сортировочные машины.


#Biography #Birth_Date #Events #28июля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
[Совет по Java #065]

Тема: System.arraycopy — native метод, самый быстрый для копирования массивов, но проверяет типы во время выполнения.

Проблема: Копирование массивов — часто выполняемая операция, особенно при работе с коллекциями, буферами и низкоуровневыми структурами.

Существует несколько способов скопировать массив: цикл forArrays.copyOfArrays.copyOfRangeclone() и System.arraycopy. Многие разработчики используют циклы или высокоуровневые методы, забывая о самом производительном варианте. 

System.arraycopy
 — это native метод, реализованный на уровне JVM и операционной системы, который использует прямое копирование памяти (обычно через memcpy в C). Он работает значительно быстрее, чем ручные циклы, особенно для больших массивов, так как оптимизирован под аппаратные возможности. Однако System.arraycopy проверяет совместимость типов во время выполнения и выбрасывает ArrayStoreException, если типы несовместимы.

Эта проверка может быть неочевидна при работе с массивами объектов и ковариантными типами, что приводит к трудноуловимым ошибкам.

Решение: Для копирования массивов всегда используйте System.arraycopy, если вам нужна максимальная производительность и вы контролируете типы.

Для простого копирования всего массива используйте Arrays.copyOf или clone(), которые внутри вызывают System.arraycopy. Для частичного копирования предпочтителен прямой вызов System.arraycopy.

При копировании массивов объектов убедитесь, что исходный массив является подтипом целевого (например, String[] можно скопировать в Object[]). Если типы несовместимы, будет выброшено исключение, поэтому используйте явные проверки или обобщения, чтобы гарантировать корректность. Избегайте ручных циклов для копирования больших объемов данных.
import java.util.Arrays;

public class ArrayCopyPerformance {

public static void main(String[] args) {
int[] src = new int[1000000];
for (int i = 0; i < src.length; i++) src[i] = i;

//Медленно: ручной цикл
int[] dest1 = new int[src.length];
for (int i = 0; i < src.length; i++) {
dest1[i] = src[i];
}

//Быстро: System.arraycopy
int[] dest2 = new int[src.length];
System.arraycopy(src, 0, dest2, 0, src.length);

//Удобно: Arrays.copyOf (использует arraycopy внутри)
int[] dest3 = Arrays.copyOf(src, src.length);

// Частичное копирование
int[] destPartial = new int[100];
System.arraycopy(src, 500, destPartial, 0, 100); // копируем 100 элементов с позиции 500

// Опасность с объектами
String[] strings = {"a", "b", "c"};
Object[] objects = new Object[3];
System.arraycopy(strings, 0, objects, 0, 3); // OK: String[] -> Object[]

try {
// Ошибка: несовместимые типы
Integer[] ints = {1, 2, 3};
System.arraycopy(ints, 0, strings, 0, 3); // ArrayStoreException
} catch (ArrayStoreException e) {
System.err.println("Типы несовместимы: " + e);
}

// Для примитивов проверка осуществляется во время выполнения
// но совместимость гарантируется компилятором, если типы одинаковы
}
}


Объяснение:
 System.arraycopy является intrinsic методом во многих JVM, то есть компилятор может заменить его вызов на высокооптимизированный машинный код без перехода в native-метод. Он копирует непрерывные участки памяти, используя инструкции процессора для быстрого перемещения блоков данных. Это делает его в несколько раз быстрее, чем поэлементное копирование в Java, особенно для массивов примитивов, где нет накладных расходов на упаковку.

При копировании массивов объектов System.arraycopy выполняет проверку типов: если исходный тип не является подтипом целевого, выбрасывается ArrayStoreException с указанием несовместимого элемента. Эта проверка происходит во время выполнения, что может быть неожиданным для разработчиков, привыкших к проверкам на этапе компиляции.

Поэтому при работе с обобщенными массивами или преобразованиями типов рекомендуется использовать Arrays.copyOf или явные проверки через instanceof.


#Java #советы
👍4
Ребят! Продолжаю набор желающих обучиться Java до уровня мидла на Spring Framework.

Кроме того могу провести мок-собес или ревью любого вашего проекта с подробным фидбеком, для оценки уровня.

Пишите в лс
@Oleborn
👍2
Что выведет код?

public class Task280726 {
public static void main(String[] args) {
Object[] src = {"A", "B", 1};
String[] dest = new String[3];
System.arraycopy(src, 0, dest, 0, 3);
System.out.println(dest[0]);
}
}


#Tasks
👍3
Варианты ответа:
Anonymous Quiz
23%
A
0%
null
54%
ArrayStoreException
23%
ClassCastException
👍4
Что такое Map.ofEntries() и Map.entry()? 🤓

Ответ:

Для создания неизменяемых карт с более чем 10 элементами в Java 9+ используется Map.ofEntries() с Map.entry(). 

Map.of() имеет перегрузки только до 10 пар. Map.ofEntries() принимает массив Map.Entry и подходит для больших карт.

Пример: Map.ofEntries( entry("a", 1), entry("b", 2), ... ).

Также можно использовать Map.copyOf() для создания неизменяемой копии существующей карты.


Все эти методы создают неизменяемые, сериализуемые структуры.



#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4