Java for Beginner
870 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
История технологии сегодня — 8 июля

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

И́горь Евге́ньевич Тамм (26 июня (8 июля) 1895 года, Владивосток — 12 апреля 1971, Москва) — советский физик-теоретик, лауреат Нобелевской премии по физике (1958). Основные направления научного творчества Тамма относятся к квантовой механикефизике твёрдого тела, теории излучения, ядерной физикефизике элементарных частиц, а также к решению ряда прикладных задач. В 1932 году опубликовал работу, в которой теоретически предсказал существование поверхностных состояний на поверхности твёрдого тела (этот вид поверхностных состояний сейчас известен как состояния Тамма).

Пётр Леони́дович Капи́ца (26 июня [8 июля] 1894, Кронштадт — 8 апреля 1984, Москва) — советский физик, инженер и инноватор, нобелевский лауреат (1978). Лауреат Нобелевской премии по физике за открытие явления сверхтекучести жидкого гелия, ввёл в научный обиход термин «сверхтекучесть». Известен также работами в области физики низких температур, изучении сверхсильных магнитных полей и удержания высокотемпературной плазмы. Разработал высокопроизводительную промышленную установку для сжижения воздуха на базе турбодетандера.
(Почитайте биографию, как решение властей СССР изменило жизнь человека во благо страны)

Никола́й Никола́евич Бенардо́с (8 (26) июня 1842, Бенардосовка, Херсонская губерния — 21 (8) сентября 1905, Фастов, Киевская губерния)русский инженер и изобретатель греческого происхождения, создатель электрической дуговой сварки (метод «Электрогефест», 1881). Автор около 200 изобретений в различных областях техники, ему также принадлежит разработка точечной и шовной контактной сварки.

Граф Фердина́нд Адо́льф Ге́нрих А́вгуст фон Це́ппелин (нем. Ferdinand Adolf Heinrich August Graf von Zeppelin; 8 июля 1838, Констанц, Великое герцогство Баден, Германский союз — 8 марта 1917, Берлин, Германская империя) — немецкий изобретатель и военный деятель, конструктор многочисленных дирижаблей.


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

2011 — начался последний полёт шаттла «Атлантис», завершивший эксплуатацию кораблей системы «Space Shuttle».


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

Тема: ReentrantLock не освобождается автоматически (в отличие от synchronized).

Проблема: ReentrantLock требует явного вызова метода unlock() для освобождения блокировки.

Если разработчик забывает это сделать или между lock() и unlock() возникает исключение, блокировка остается захваченной навсегда. Это приводит к взаимоблокировкам (deadlock) и остановке потоков, которые пытаются захватить эту блокировку.

В отличие от synchronized, который автоматически освобождает монитор при выходе из блока (включая исключения), ReentrantLock не предоставляет такой гарантии. Ошибки ручного управления особенно опасны в сложных цепочках вызовов, где легко пропустить unlock. Это делает ReentrantLock более гибким, но и более рискованным инструментом.

Решение: Всегда обрамляйте вызов lock() конструкцией try-finally, где unlock() вызывается в блоке finally.

Это гарантирует, что блокировка будет освобождена даже при возникновении исключения. Для операций с таймаутами используйте tryLock(long, TimeUnit), который возвращает boolean, и проверяйте результат. В высоконагруженных системах применяйте tryLock() с таймаутом и повторными попытками для предотвращения бесконечного ожидания.

При работе с Condition также требуется try-finally. Для упрощения кода можно использовать вспомогательные методы, но они не отменяют необходимости явного освобождения.

import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.TimeUnit;

public class ReentrantLockFinally {

private final ReentrantLock lock = new ReentrantLock();

//Антипаттерн: без finally — риск deadlock
public void badMethod() {
lock.lock();
// Если здесь произойдет исключение, lock не освободится
doWork();
lock.unlock(); // Может не выполниться
}

//Правильно: try-finally
public void goodMethod() {
lock.lock();
try {
doWork();
} finally {
lock.unlock(); // Гарантированно вызовется
}
}

//tryLock с таймаутом
public boolean tryLockWithTimeout() throws InterruptedException {
if (lock.tryLock(1, TimeUnit.SECONDS)) {
try {
doWork();
return true;
} finally {
lock.unlock();
}
} else {
System.out.println("Не удалось захватить блокировку");
return false;
}
}

//Использование Condition (тоже с finally)
public void conditionExample() throws InterruptedException {
var condition = lock.newCondition();
lock.lock();
try {
condition.await(1, TimeUnit.SECONDS);
} finally {
lock.unlock();
}
}

private void doWork() {
// критическая секция
}
}

Объяснение: ReentrantLock — это явная блокировка, предоставляющая расширенные возможности: прерывание ожидания, таймауты, опрос, несколько условий. Однако эти возможности требуют ответственного управления.

Блок finally гарантирует, что unlock() будет вызван независимо от того, завершится ли защищаемый код успешно или с ошибкой. Если блокировка не освобождена, другие потоки, вызывающие lock(), будут заблокированы навсегда. В отличие от synchronized, где компилятор и JVM обеспечивают освобождение, в ReentrantLock это полностью на совести разработчика.

#Java #советы
👍5
Что выведет код?

import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.TimeUnit;

public class Task080726 {
private static final ReentrantLock lock = new ReentrantLock();

public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
lock.lock();
System.out.println("Thread1 acquired lock");
});

Thread t2 = new Thread(() -> {
try {
if (lock.tryLock(1, TimeUnit.SECONDS)) {
System.out.println("Thread2 acquired lock");
lock.unlock();
} else {
System.out.println("Thread2 failed to acquire lock");
}
} catch (InterruptedException e) {
System.out.println("Interrupted");
}
});

t1.start();
Thread.sleep(100);
t2.start();
t2.join();
}
}


#Tasks
👍2
Что такое Collectors.groupingBy() и partitioningBy()? 🤓

Ответ:

Collectors.groupingBy(Function classifier)
 — собирает элементы в Map, где ключ — результат классификатора, значение — список элементов. Есть перегрузки с downstream коллектором (например, counting(), summingInt()). 

Collectors.partitioningBy(Predicate) — разбивает на две части (true/false), возвращая Map<Boolean, List>.

Оба мощные инструменты для статистики и отчетов. Пример: группировка сотрудников по департаментам, подсчет количества, суммы зарплат и т.д. Основа для data-driven операций.


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

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

Бенджамин (Бен) Рой Мо́ттельсон (англ. Benjamin Roy Mottelson; 9 июля 1926, Чикаго, Иллинойс — 13 мая 2022, Копенгаген) — американо-датский физик-теоретик и физик-ядерщик. Лауреат Нобелевской премии по физике «за открытие взаимосвязи между коллективным движением и движением отдельной частицы в атомном ядре и развитие теории строения атомного ядра, базирующейся на этой взаимосвязи».

Томас Дэвенпорт (англ. Thomas Davenport; 9 июля 1802 — 6 июля 1851) — американский кузнец, изобретатель. В 1833 году сконструировал первый роторный электродвигатель постоянного тока, создал приводимую им в движение модель поезда. В 1837 году получил патент на электромагнитную машину.


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

1957 — открыт 102-й элемент таблицы Менделеева — нобелий.


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

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

Класс Files — утилитный класс для работы с файлами

Класс Files из пакета java.nio.file — это центральная утилита в NIO.2, появившаяся в Java 7. Его роль в файловом API аналогична роли Collections для коллекций или Arrays для массивов: он предоставляет исключительно статические методы, которые выполняют операции над объектами Path. Если Path — это адрес, то Files — это набор инструментов, которые позволяют по этому адресу что-либо сделать.

Утилитный класс (utility class) — это класс, содержащий только статические методы и константы, не предназначенный для создания экземпляров. Обычно он имеет приватный конструктор, чтобы предотвратить инстанцирование. Files именно такой: вы не пишете new Files(), а вызываете Files.exists(path).


Архитектура: почему Files лучше java.io.File

Старый класс java.io.File существует с первой версии Java (1996 год) и несёт в себе архитектурные компромиссы того времени. Класс Files вместе с Path решает эти проблемы системно.

Разделение ответственности
java.io.File смешивал в себе три роли: представление пути, проверку метаданных и выполнение операций. Path отвечает только за путь, а Files — только за операции. Это соответствует принципу SRP (Single Responsibility Principle, принцип единственной ответственности): каждый класс должен иметь только одну причину для изменения.

Исключения вместо молчаливых ошибок
Методы File возвращали boolean при неудаче, не объясняя причину:
java.io.File oldFile = new java.io.File("/etc/shadow");
boolean deleted = oldFile.delete(); // false — но почему? Нет прав? Файл занят? Файла нет?

Методы Files выбрасывают checked-исключения (проверяемые исключения) — подклассы IOException, которые содержат точную причину отказа: NoSuchFileException, AccessDeniedException, DirectoryNotEmptyException и другие. Это позволяет писать надёжный код с ветвлением по конкретным ошибкам.

Checked-исключение — это исключение в Java, которое компилятор требует либо обработать в блоке try-catch, либо объявить в сигнатуре метода через throws. Модель checked/unchecked исключений в Java разделяет ошибки, от которых вызывающий код теоретически может восстановиться (checked), и программные ошибки (unchecked, наследники RuntimeException).

Поддержка символических ссылок
File не различал символическую ссылку (symlink) и целевой файл. Files предоставляет методы, явно работающие с ссылками: isSymbolicLink(), readSymbolicLink(), а также варианты методов с параметром LinkOption.NOFOLLOW_LINKS, который указывает, что операция должна применяться к самой ссылке, а не к тому, на что она указывает.

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

Атомарность и конкурентность
Многие методы Files гарантируют атомарность на уровне файловой системы. Например, Files.move() с опцией ATOMIC_MOVE выполняет перемещение как неделимую операцию, что невозможно было реализовать через старый File.renameTo().

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


Проверка существования и типа файла

Files.exists(Path path, LinkOption... options)

Метод проверяет, существует ли файл, директория или символическая ссылка по указанному пути. Возвращает true, если файл существует, false — если нет или если при проверке произошла ошибка (например, отказ в доступе).
Path configPath = Paths.get("/app/config.properties");
boolean exists = Files.exists(configPath);

Важный нюанс: Files.exists() возвращает false не только когда файла нет, но и когда нет прав на проверку. Это делает метод неидеальным для однозначных выводов. Если вам нужно различать "файла нет" и "нет прав", используйте Files.notExists() в паре с Files.exists().

Параметр LinkOption... options — это varargs массив опций. Передача LinkOption.NOFOLLOW_LINKS означает, что если путь — символическая ссылка, метод проверит существование самой ссылки, а не целевого файла.

Files.notExists(Path path, LinkOption... options)
Этот метод возвращает true, если файл точно не существует. Он отличается от простой инверсии !Files.exists() тем, что различает два состояния:
Файл не существует — возвращает true.
Файл существует, но нет прав на проверку — возвращает false.
Произошла другая ошибка ввода-вывода — выбрасывает IOException.
Path secret = Paths.get("/root/.ssh/id_rsa");

if (Files.notExists(secret)) {
// Мы уверены, что файла нет (или нет прав, но тогда exists тоже вернул бы false)
System.out.println("Файл не существует");
} else if (Files.exists(secret)) {
// Мы уверены, что файл есть
System.out.println("Файл существует");
} else {
// Files.exists() == false И Files.notExists() == false
// Это возможно только при ошибке доступа — состояние неопределённости
System.out.println("Невозможно определить существование файла");
}

Эта пара методов реализует трёхзначную логику существования: DEFINITELY_EXISTS, DEFINITELY_NOT_EXISTS, UNKNOWN. Такой подход необходим в системах, где безопасность критична: например, при проверке перед созданием файла, чтобы избежать перезаписи существующего файла, к которому у вас нет прав на чтение, но есть права на запись.

#Java #для_новичков #beginner #IO #NIO #Files
👍3
Files.isDirectory(Path path, LinkOption... options)
Проверяет, является ли путь директорией. Возвращает false, если путь — файл, символическая ссылка на файл, или если проверка невозможна. Для корректной работы требуется, чтобы файл существовал: метод не выбрасывает исключение при отсутствии файла, но возвращает false.
Path dir = Paths.get("/var/log");
if (Files.isDirectory(dir)) {
// Это директория
}


Files.isRegularFile(Path path, LinkOption... options)
Проверяет, является ли путь обычным файлом. Обычный файл (regular file) — это файл, который не является директорией, символической ссылкой, именованным каналом, сокетом домена Unix или устройством. Это файл с данными, который можно читать и писать.
Path file = Paths.get("/etc/passwd");
if (Files.isRegularFile(file)) {
// Это обычный файл, можно безопасно читать
}


Files.isSymbolicLink(Path path)
Проверяет, является ли путь символической ссылкой. Этот метод не следует по ссылке — он проверяет сам объект файловой системы. Если путь — symlink, метод вернёт true даже если целевой файл удалён (висячая ссылка).
Path link = Paths.get("/usr/bin/java");
if (Files.isSymbolicLink(link)) {
Path target = Files.readSymbolicLink(link); // куда указывает ссылка
System.out.println("Ссылка ведёт на: " + target);
}



Практический пример: инициализация конфигурации

Рассмотрим сценарий, в котором приложение при старте проверяет файл конфигурации. Если файл отсутствует — создаёт его с дефолтными настройками. Если файл существует, но является директорией или символической ссылкой — обрабатывает это как ошибку.
import java.nio.file.*;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

public class ConfigInitializer {

private static final Path CONFIG_PATH = Paths.get("app.conf");
private static final String DEFAULT_CONFIG =
"# Default configuration\n" +
"server.port=8080\n" +
"db.url=jdbc:h2:mem:test\n";

public void initialize() throws IOException {
// Шаг 1: проверяем, существует ли путь
if (Files.notExists(CONFIG_PATH)) {
// Файла точно нет — создаём с дефолтами
createDefaultConfig();
System.out.println("Конфигурация создана по умолчанию");
return;
}

// Шаг 2: файл существует — проверяем, что это обычный файл
if (!Files.isRegularFile(CONFIG_PATH)) {
if (Files.isDirectory(CONFIG_PATH)) {
throw new IOException(
"Конфигурационный путь \"" + CONFIG_PATH + "\" является директорией"
);
}
if (Files.isSymbolicLink(CONFIG_PATH)) {
// Разрешаем символическую ссылку, но проверяем целевой объект
Path target = Files.readSymbolicLink(CONFIG_PATH);
if (!Files.isRegularFile(target, LinkOption.NOFOLLOW_LINKS)) {
throw new IOException(
"Символическая ссылка конфигурации указывает на не-файл: " + target
);
}
// Ссылка валидна — продолжаем
return;
}
throw new IOException("Неизвестный тип файла конфигурации");
}

// Шаг 3: обычный файл существует — проверяем читаемость
if (!Files.isReadable(CONFIG_PATH)) {
throw new AccessDeniedException("Нет прав на чтение конфигурации");
}

System.out.println("Конфигурация загружена из существующего файла");
}

private void createDefaultConfig() throws IOException {
// getParent() может вернуть null, если путь в текущей директории
Path parent = CONFIG_PATH.getParent();
if (parent != null && Files.notExists(parent)) {
// createDirectories создаёт всю иерархию, включая промежуточные директории
Files.createDirectories(parent);
}
// write записывает массив байтов в файл, создавая его атомарно
Files.write(CONFIG_PATH, DEFAULT_CONFIG.getBytes(StandardCharsets.UTF_8));
}
}

В этом примере последовательность проверок критична: сначала notExists гарантирует, что мы не перезапишем существующий файл. Затем isRegularFile защищает от директорий и ссылок. Files.isReadable() — дополнительная проверка, которая не выбрасывает исключение, а возвращает boolean, что удобно для ветвления логики.


Путь байтов в памяти JVM при работе с Files


Каждый вызов метода Files порождает цепочку преобразований данных от Java-объекта до системного вызова ОС и обратно. Разберём этот путь на примере Files.readAllBytes(path).

1. Объект Path в куче
Объект Path, переданный в метод, уже находится в куче. Как описано в предыдущем уроке, Path — это лёгкая структура, хранящая сегменты пути и ссылку на FileSystem. При вызове Files.readAllBytes(path) JVM помещает ссылку на Path в стек вызовов текущего потока — это область памяти, где хранятся локальные переменные и параметры методов. Стек потока выделяется в нативной памяти и не управляется GC напрямую.

2. Переход в нативный код через JNI
Реализация Files.readAllBytes() в OpenJDK делегирует работу классу FileChannel или прямому нативному вызову через JNI (Java Native Interface — механизм взаимодействия Java-кода с библиотеками, написанными на C/C++ или ассемблере). На этом этапе строковое представление пути извлекается из объекта Path и кодируется в массив байтов в кодировке UTF-8.
Этот массив байтов создаётся в куче как временный объект byte[] или char[]. Затем он копируется в нативную память (native memory, память вне кучи JVM) через JNI-функции, так как системные вызовы ОС работают с C-строками (char* или wchar_t*), а не с Java-объектами.

3. Системный вызов и кэш страниц ОС
ОС получает путь в виде байтов и выполняет системный вызов open() (POSIX) или NtCreateFile() (Windows). Ядро ОС преобразует путь в структуру inode (на Unix) или MFT-запись (на NTFS), проверяет права доступа и открывает файловый дескриптор.
Данные файла читаются не напрямую с диска, а через кэш страниц (page cache) — область оперативной памяти ядра, где хранятся недавно использованные блоки файлов. Если данные есть в кэше, чтение происходит без обращения к диску. Если нет — происходит промах кэша, и данные загружаются с диска в кэш страниц.

4. Возврат данных в кучу JVM
Прочитанные байты копируются из кэша страниц ОС через нативную память обратно в кучу JVM. Метод readAllBytes() выделяет byte[] точного размера файла. Этот массив создаётся в Young Generation (молодом поколении) кучи, в области Eden. Если файл большой (например, 100 МБ), массив может оказаться слишком крупным для Young Generation и будет сразу размещён в Old Generation (старом поколении) — такие объекты называются humongous objects (гигантские объекты) в G1 GC.
G1 GC (Garbage-First Garbage Collector) — это сборщик мусора, используемый по умолчанию с Java 9. Он делит кучу на регионы фиксированного размера (обычно 1–32 МБ). Объект, занимающий более половины региона, считается humongous и размещается непрерывным блоком в Old Generation.

5. Работа GC с файловыми данными
После возврата из readAllBytes() массив байтов остаётся в куче. Если он присвоен локальной переменной внутри метода и метод завершился, ссылка на массив исчезает из стека, и массив становится мусором. Minor GC (молодая сборка) соберёт его при следующем проходе, если он находится в Eden. Если массив большой и попал в Old Generation, он дождётся Major GC (полной сборки).

Важно: сам файловый дескриптор, открытый ОС, закрывается нативным кодом до возврата в Java. Но если вы используете потоковое чтение (Files.newInputStream()), дескриптор остаётся открытым до вызова close(). Если забыть закрыть поток, дескриптор утечёт на уровне ОС, даже если Java-объект InputStream будет собран GC. GC не знает о ресурсах ОС — он управляет только памятью кучи. Поэтому try-with-resources обязателен:
// try-with-resources гарантирует вызов close() даже при исключении
// AutoCloseable — интерфейс, требующий реализации метода close()
try (InputStream in = Files.newInputStream(path)) {
// работа с потоком
} // close() вызывается автоматически здесь


#Java #для_новичков #beginner #IO #NIO #Files
👍5
6. Метаданные и временные объекты
При вызовах Files.exists(), isDirectory() и подобных методов данные файла не читаются. Вместо этого выполняется системный вызов stat() (POSIX) или GetFileAttributes() (Windows), который возвращает метаданные: тип файла, права доступа, размер, временные метки. Эти метаданные возвращаются в виде структуры в нативной памяти, из которой JVM извлекает нужные поля и создаёт примитивы (boolean, long) на стеке. Никаких объектов в куче при этом не создаётся, поэтому такие проверки — "бесплатные" с точки зрения GC.


Чтение и запись данных

Files.readAllBytes(Path) и Files.readAllLines(Path, Charset)
// Чтение всего файла как массива байтов
byte[] rawData = Files.readAllBytes(Paths.get("data.bin"));

// Чтение текстового файла в список строк
List<String> lines = Files.readAllLines(
Paths.get("log.txt"),
StandardCharsets.UTF_8
);

readAllBytes() удобен для небольших файлов, но опасен для больших: он загружает весь файл в память. Для больших файлов используйте Files.newBufferedReader() или Files.lines().

Files.lines() возвращает Stream<String>ленивый поток (lazy stream), который читает файл построчно по мере обхода. Это экономит память, но требует закрытия потока:
// Stream<String> должен быть закрыт, так как держит файловый дескриптор
try (Stream<String> stream = Files.lines(Paths.get("huge.log"))) {
long errorCount = stream.filter(line -> line.contains("ERROR")).count();
}

Ленивый поток — это поток данных, элементы которого вычисляются или читаются по требованию, а не все сразу. В Java Stream API операции промежуточные (filter, map) ленивы, а терминальные (count, collect) — энергичные (запускают вычисление).

Files.write(Path, byte[]/Iterable, OpenOption...)
Path target = Paths.get("output.txt");
byte[] data = "Hello, World".getBytes(StandardCharsets.UTF_8);

// CREATE — создать файл, если не существует
// TRUNCATE_EXISTING — очистить существующий файл перед записью
Files.write(target, data, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);

OpenOption — это интерфейс-маркер, который реализуют перечисления StandardOpenOption и LinkOption. Он определяет, как именно открывать или создавать файл.
Копирование, перемещение и удаление

Files.copy(Path source, Path target, CopyOption... options)
Path src = Paths.get("/tmp/source.dat");
Path dst = Paths.get("/backup/source.dat");

Files.copy(src, dst,
StandardCopyOption.REPLACE_EXISTING, // перезаписать, если есть
StandardCopyOption.COPY_ATTRIBUTES // скопировать права и временные метки
);

Метод поддерживает копирование между разными файловыми системами (например, из ZIP-архива на диск), так как работает через абстракцию FileSystemProvider.

FileSystemProvider — это сервис-провайдер (SPI, Service Provider Interface), который реализует конкретную файловую систему. Для каждой ФС существует свой провайдер: UnixFileSystemProvider, WindowsFileSystemProvider, ZipFileSystemProvider и т.д. Files.copy() делегирует операцию провайдеру источника и провайдеру назначения.

Files.move(Path source, Path target, CopyOption... options)
Files.move(src, dst, StandardCopyOption.ATOMIC_MOVE);

ATOMIC_MOVE гарантирует, что операция будет атомарной в пределах одной файловой системы. Если источник и назначение на разных ФС, метод выбросит AtomicMoveNotSupportedException.

Files.delete(Path path) и Files.deleteIfExists(Path path)
// delete бросает NoSuchFileException, если файла нет
Files.delete(Paths.get("temp.tmp"));

// deleteIfExists возвращает boolean, не бросая исключение при отсутствии
boolean deleted = Files.deleteIfExists(Paths.get("temp.tmp"));


Files.delete()
требует, чтобы директория была пустой. Для рекурсивного удаления используйте обход дерева:
// walk возвращает Stream<Path> всех файлов и директорий, начиная с root
// sorted(Comparator.reverseOrder()) — сначала файлы, потом родительские директории
Files.walk(root)
.sorted(Comparator.reverseOrder())
.forEach(p -> {
try {
Files.delete(p);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
});



Работа с метаданными

Files.getAttribute и Files.setAttribute
// Чтение произвольного атрибута файловой системы
Object creationTime = Files.getAttribute(path, "creationTime");

// Установка POSIX-прав доступа (только на Unix)
Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rw-r--r--");
Files.setPosixFilePermissions(path, perms);

POSIX (Portable Operating System Interface) — это семейство стандартов, определяющих интерфейс между ОС и приложениями. В контексте файлов POSIX определяет модель прав доступа (владелец, группа, остальные) и набор операций над файлами.

Files.getFileStore(Path)
FileStore store = Files.getFileStore(path);
long usableSpace = store.getUsableSpace();
long totalSpace = store.getTotalSpace();

FileStore — это абстракция над хранилищем файловой системы (раздел диска, том, сетевой диск). Она позволяет узнать общий и доступный объём, тип ФС и другие характеристики.


Продвинутые паттерны использования

Паттерн "Write to temp, then move"

Для атомарной записи файла пишите во временный файл в той же директории, а затем атомарно перемещайте:
public void atomicWrite(Path target, byte[] data) throws IOException {
// Создаём временный файл в той же директории, что и target
// это важно, чтобы move был атомарным в пределах одного FileStore
Path temp = Files.createTempFile(target.getParent(), "tmp_", ".dat");
try {
Files.write(temp, data);
// Атомарное переименование: либо старый файл заменён, либо нет
Files.move(temp, target, StandardCopyOption.ATOMIC_REPLACE);
} catch (IOException e) {
// При ошибке удаляем временный файл
Files.deleteIfExists(temp);
throw e;
}
}

Этот паттерн гарантирует, что читатели никогда не увидят частично записанный файл. Временный файл создаётся через Files.createTempFile(), который генерирует уникальное имя атомарно.

Паттерн "Directory watch"
WatchService watchService = FileSystems.getDefault().newWatchService();
Path dir = Paths.get("/app/inbox");

// Регистрируем директорию на отслеживание создания и модификации файлов
dir.register(watchService,
StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_MODIFY
);

// WatchService — механизм мониторинга изменений в файловой системе
// Он использует нативные API ОС (inotify на Linux, FSEvents на macOS, ReadDirectoryChangesW на Windows)

WatchService — сервис наблюдения за изменениями в файловой системе. Вместо периодического опроса (polling) он использует событийную модель ОС, что экономит CPU.

#Java #для_новичков #beginner #IO #NIO #Files
👍5
Что выведет код?

import java.nio.file.*;
import java.io.IOException;

public class Task090726 {
public static void main(String[] args) throws IOException {
Path p1 = Paths.get("");
Path p2 = Paths.get(".");
System.out.println(Files.isSameFile(p1, p2));
System.out.println(p1.equals(p2));
System.out.println(p1.normalize().equals(p2.normalize()));
}
}


#Tasks
👍2
👍2
Ребят, продолжаю набор желающих обучиться Java. 🤓

Гарантий трудоустройства нет, но на уровень мидла точно выведу) Недорого)))

Пишите в лс! @Oleborn 📞
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Что такое Collectors.toUnmodifiableList() и toUnmodifiableSet()? 🤓

Ответ:

Java 10 ввел коллекторы для создания неизменяемых коллекций: Collectors.toUnmodifiableList(), toUnmodifiableSet(), toUnmodifiableMap().

Они возвращают коллекции, которые не поддерживают изменения (в отличие от toList() из Java 16, который также неизменяем, но реализован проще).

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



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

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

Ни́кола Те́сла (в некоторых источниках Нико́ла Те́сла, серб. Ни́кола Те́сла, англ. Nikola Tesla; 10 июля 1856, Смилян, Военная граница, Австрийская империя — 7 января 1943, Манхэттен, Нью-Йорк, США) — американский инженер и физик-электроник сербского происхождения, изобретатель в области электротехники и радиотехники, внёсший существенный вклад в развитие электроинженерии. Наиболее известен разработкой современной системы электроснабжения переменного тока. После победы в «Войне токов» и демонстрации радио стал одной из самых известных личностей в истории науки XX века.

Никола́й Алекса́ндрович Ши́лов (28 июня (10 июля) 1872, Москва — 17 августа 1930, Гагра) — русский и советский физико-химик, специалист в области теории адсорбции и реакций окисления.

Харви Болл (англ. Harvey Ross Ball; 10 июля 1921, Вустер, Массачусетс, США — 12 апреля 2001, там же)американский графический дизайнер, создатель «смайлика», учредитель Всемирного дня улыбки (отмечается в первую пятницу октября).

О́уэн Че́мберлен (англ. Owen Chamberlain; 10 июля 1920, Сан-Франциско, США — 28 февраля 2006, Беркли, США) американский физик, член Национальной академии наук США (1960), лауреат Нобелевской премии по физике 1959 года «за открытие антипротона» совместно с Эмилио Сегре.


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

1962 — запущен первый коммерческий спутник связи — «Телстар».


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

Тема: Condition.await() может проснуться без сигнала (spurious wakeup).

Проблема: Метод await() класса Condition (из java.util.concurrent.locks) может вернуть управление даже без вызова signal() или signalAll() на этой же Condition.

Это явление называется ложным пробуждением (spurious wakeup) и разрешено спецификацией для оптимизации реализации на некоторых платформах. Если после возврата из await() не проверить условие, ради которого поток ожидал, а сразу продолжить выполнение, то программа может выполнить критическую секцию, когда условие еще не выполнено.

Это приводит к нарушению инвариантов, повреждению данных и трудноуловимым ошибкам, которые проявляются крайне редко (из-за редкости ложных пробуждений) и поэтому особенно опасны.

Решение: Всегда помещайте вызов await() в цикл while (condition), который проверяет условие до и после пробуждения. Это гарантирует, что поток продолжит работу только когда условие действительно истинно. Эта идиома универсальна для всех реализаций Condition и рекомендуется в документации Java. Также нужно помнить, что await() может быть прерван (InterruptedException), и это следует корректно обрабатывать.

Для обеспечения безопасности используйте lock.lock() и try-finally для освобождения блокировки.
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class SpuriousWakeup {

private final ReentrantLock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
private boolean ready = false;

//Антипаттерн: if вместо цикла
public void badAwait() throws InterruptedException {
lock.lock();
try {
if (!ready) {
condition.await(); // Может проснуться ложно
}
// Здесь ready может быть false!
doWork();
} finally {
lock.unlock();
}
}

//Правильно: while цикл
public void goodAwait() throws InterruptedException {
lock.lock();
try {
while (!ready) {
condition.await(); // Проверка в цикле
}
// Теперь ready гарантированно true
doWork();
} finally {
lock.unlock();
}
}

// Сигнал для изменения состояния
public void signal() {
lock.lock();
try {
ready = true;
condition.signal();
} finally {
lock.unlock();
}
}

// Демонстрация с несколькими потоками
public static void main(String[] args) throws InterruptedException {
SpuriousWakeup demo = new SpuriousWakeup();

Thread waiter = new Thread(() -> {
try {
demo.goodAwait();
System.out.println("Проснулся корректно");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});

waiter.start();
Thread.sleep(100);
demo.signal(); // Разбудим
waiter.join();
}
}

Объяснение: Спецификация Java позволяет ложные пробуждения, чтобы упростить реализацию на некоторых ОС (например, в системах с условными переменными pthreads). Даже если вероятность ложного пробуждения крайне мала, полагаться на то, что оно не произойдет, ненадежно.

Использование цикла while делает код устойчивым: поток проверяет условие до ожидания и после каждого пробуждения. Это стандартный паттерн, называемый "условная переменная" (condition variable). В цикле также проверяется наличие прерывания — если поток прерван, await() выбрасывает InterruptedException, которое должно быть обработано. Аналогично следует поступать с методами await(long time, TimeUnit unit) и awaitUntil(Date deadline).

#Java #советы
👍4
Что выведет код?

import java.util.concurrent.locks.*;
import java.util.concurrent.TimeUnit;

public class Task100726 {
private static final Lock lock = new ReentrantLock();
private static final Condition condition = lock.newCondition();
private static volatile boolean flag = false;

public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
lock.lock();
try {
if (!flag) {
condition.await(3, TimeUnit.SECONDS);
}
System.out.print("Done");
} catch (InterruptedException e) {
System.out.print("Interrupted");
} finally {
lock.unlock();
}
});
t.start();
t.join();
}
}


#Tasks
👍3
Что такое CompletableFuture (цепочки и комбинаторы)? 🤓

Ответ:

CompletableFuture (Java 8) реализует Future и CompletionStage.

Позволяет строить цепочки асинхронных операций: thenApply (преобразование), thenAccept (потребление), thenRun (действие без результата).

Для комбинирования: thenCombine (объединение двух результатов), thenCompose (плоское сцепление), anyOf (первый завершившийся), allOf (все завершились).

Можно обрабатывать исключения через exceptionally и handle. Позволяет создавать неблокирующие, реактивные системы без внешних библиотек.



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

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

Алекса́ндр Миха́йлович Про́хоров (11 июля 1916, Атертон, штат Квинсленд, Австралия — 8 января 2002, Москва) — советский и российский физик, один из основоположников важнейшего направления современной физики — квантовой электроники, лауреат Нобелевской премии по физике за 1964 год, один из изобретателей лазерных технологий.

Серге́й Никола́евич Верно́в (28 июня [11 июля] 1910, Сестрорецк, Санкт-Петербургская губерния — 26 сентября 1982, Москва) — российский и советский физик, академик АН СССР (1968), специалист в области физики космических лучей. Один из участников открытия внешнего радиационного пояса Земли.


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

2006 — компания Microsoft прекратила техническую поддержку операционных систем Windows 98 и Windows Me.

2022 — опубликовано первое изображение, полученное космическим телескопом «Джеймс Уэбб». Это изображение ранней Вселенной с самым высоким разрешением из когда-либо сделанных ранее.


#Biography #Birth_Date #Events #11июля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Немного о ИИ.

Всем привет.

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

Она явно перекликается с тем, что последнее время, мне много с кем пришлось обсуждать вопрос - а что нас ждет в мире с ИИ?

Давайте я коротко определю стороны вопроса:

1. Оптимисты

Те кто уверен что использование ИИ - благо. В программировании, в управлении предприятием и государством, в приготовлении на кухне и даже в постели с женой. Используют условный Claude каждый день и крайне довольны результатами.
Доводы: явный быстрый доступ к любым знаниям, значительное увеличение скорости процессов, снижение затрат на данные процессы.


2. Воздержавшиеся (похуисты)

Тем кому ИИ побоку. Шахтеры, строители, землекопы и ногтеточицы. Уверены что их работу ИИ не заменит, а те кто якобы "пострадал" от ИИ - унылые лентяи.
Доводы: нас не заменят, до нас пока дойдет, не выёбывайся - бери сварочный и пошли на завод.


3. Реалисты

Те кто погружен в тему работы ИИ понимая ограничения и последствия. Используют ИИ так же каждый день в сложных темах.
Доводы: ИИ не панацея и не может заменить реальное обучение и человеческий мозг. Не имеет интуиции и понимая последствий своих решений. Употреблять строго по инструкции и с здоровой долей скептицизма.


Кроме вышеозначенных сторон конечно же есть те кто вынужден топить за популяризацию ИИ, так как с этого лутает денюжку. Они же продадут вам кусок говна лишь бы была прибыль. Думаю их распознать довольно не сложно.

В остальном среднестатистический человек просто в ожидании - чем вся эта вакханалия закончится.


Мое мнение

Я уверенно могу сказать что с скептицизмом отношусь к будущему с ИИ. Статья которую я предложил вначале - плюс-минус соответствует моему мнению и прогнозам.

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

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

Я вижу насколько удобна ИИ каждый день. Это и советчик и мотиватор. Это доступ к любым знаниям в удобоваримом для меня формате. ЛЛМ может и код написать и песню спеть. Короче просто незаменимая весчь, блин.


Но моё чутье чует ловушки:

1. Незаменимый компаньон

Очень надеюсь вам не приходилось складывать яйца в один пакет, а потом его ронять. Неприятно. Или давать доступ к серверу лучшему другу, а потом обнаружить, что он продан. Крайне неприятно.

ЛЛМ сейчас становится тем инструментом без которого становится крайне сложно обойтись. Кому-то вообще невозможно.

А что если его завтра не станет? Ломка? Нарушение ежедневных отлаженных процессов? И пойдет условный дядя снимать шапки в подворотнях чтобы оплатить токены, ведь цены будут расти (грубая аналогия родом из 90-х, но думаю от этого не менее понятная).

Уже сейчас решают как ограничить доступ к популярным бесплатным ЛЛМ.

Дальше будет хуже. Нас подсадили, а потом будут снимать сливки.


2. Отупение и деградация

Очень противоречивый но явный тезис. Человек стремиться идти по простому пути - закон сохранения энергии в действии.

Чтобы получить знание надо придумать и провести эксперимент. Или послушать выводы того кто его осознал и провел. Или прочитать книгу того кто слушал выводы проводившего эксперимент и обогатил его своими умозаключениями. Или пойти в институт где умные люди прочитавшие много подобных книг и обогатившие эти знания индивидуальным опытом, расскажут выводы эксперимента. И так далее.
Но во всем этом пути так или иначе задействован человеческий мозг и сознание. С необходимой долей скептицизма и осторожности к каждому выводу.

ЛЛМ устраняет все эти нюансы. Выводы (в том числе и не правильные) попавшие в выборку ее обучения не анализируется, а лишь токенизируется по словам. Запрос по данному вопросу порождает не глубокий анализ и скептицизм а лишь правильный в зависимости от промпта набор слов.

И люди верят. В глубокий анализ и понимание. И начинают внемлить и прославлять.

ЛЛМ имеет у нас колоссальный кредит доверия, вы заметили?

Зачем мне решать сложный пример в голове когда ллм (калькулятор) сделает это быстрее? Тут вы можете сказать что калькуляторы существуют уже поколение а вроде тупее никто не стал?
А я отвечу - стал.

Я один из тех кто умеет считать на логарифмической линейке. Многие из тех кто это прочитает даже не знают что это такое. А раньше с ней дома строили.

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

Школьник решает сложный пример, но не запоминает выводов приведших к решению. А зачем ведь ллм всегда рядом.

Будущее будет сложным.


3. Политика

Уже сейчас даже не искушенный понимает что ИИ становится проводником политических ценностей той страны где он запущен. Еще неявно, но неотвратимо. ЛЛМ превращается в стратегическое оружие, обладание которым будет не менее важным чем обладание ЯО.

Мы с вами фактически отрезаны от западных моделей, их и наше государство делает все чтобы доступов было все меньше. Восток хоть и дружественен но тоже думаю скоро будет обрезать или ограничивать каналы.
Свои ЛЛМ есть но они пока на уровне 2-4 летней давности западных. Что будет в ближайшие годы - покажет как страна будет жить в будущем.


Выводы.

А их не будет.

Делайте их сами для себя в зависимости от вашей степени привыкания и окружения.

То что псевдоИИ уже тут - это факт. Возможно в ближайшие 5 лет и полноценный ИИ появится.

Что будет с человеком остается только догадываться.

Как по мне - оставайтесь людьми с своей головой на плечах.

=====================================

А что думаете Вы? Готов подискутировать.

Сможете ли вы сегодня обойтись без ллм?
👍7🔥1
История технологии сегодня — 12 июля

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

Уиллис Юджин Лэмб (англ. Willis Eugene Lamb; 12 июля 1913, Лос-Анджелес, США — 15 мая 2008, Тусон, США) — американский физик, лауреат Нобелевской премии по физике в 1955 г. (половина премии «за открытия, связанные с тонкой структурой спектра водорода»).


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

2011 — Нептун завершил свой первый с момента открытия планеты в 1846 году полный оборот вокруг Солнца.


#Biography #Birth_Date #Events #12июля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3