Please open Telegram to view this post
VIEW IN TELEGRAM
История технологии сегодня — 5 июля
ℹ️ Кто родился в этот день
Ю́рис Ха́ртманис (латыш. Juris Hartmanis; 5 июля 1928, Рига — 29 июля 2022) — учёный в области теории вычислительных систем, награждён в 1993 году премией Тьюринга за достижения в исследовании теории сложности вычислений.
Уильям Джон Макуорн Ранкин (Ренкин) (англ. William John Macquorn Rankine; 5 июля 1820, Эдинбург — 24 декабря 1872, Глазго) — шотландский инженер, физик и механик, один из создателей технической термодинамики. В 1849 году независимо от Клаузиуса получил общие уравнения термодинамики, выражающие соотношение между количеством теплоты и механической энергией. Исследовал термодинамические свойства газов и пара в 1850 году и составил таблицы водяных паров получивших широкое применение. В 1859 году построил полную теорию паровой машины; в частности, разработал идеальный термодинамический цикл парового двигателя, названного в его честь.
Ге́рард Хо́фт (Герард эт Хоофт, нид. Gerardus (Gerard) ’t Hooft; род. 5 июля 1946, Ден-Хелдер, Северная Голландия) — голландский физик-теоретик, профессор Утрехтского университета (Нидерланды), лауреат Нобелевской премии по физике за 1999 год (совместно с Мартинусом Велтманом). Разработанные Хофтом и Велтманом математические методы ренормализации янг-миллсовских полей, как безмассовых, так и получающих массу вследствие спонтанного нарушения симметрии, позволили рассчитать некоторые эффекты электрослабого взаимодействия, в частности, оценить массы промежуточных векторных бозонов W± и Z0, предсказанных теорией и вскоре после этого открытых экспериментально, причём полученные значения хорошо согласовывались с экспериментальными данными. Методом Велтмана и Хофта также была рассчитана масса топ-кварка, экспериментально обнаруженного в 1995 году в Национальной лаборатории им. Э. Ферми (США).
🌐 Знаковые события
1996 — в Великобритании родилось первое клонированное млекопитающее — овца Долли
2016 — автоматическая межпланетная станция НАСА «Юнона», запущенная в 2011 году, вышла на полярную орбиту Юпитера.
#Biography #Birth_Date #Events #05июля
Ю́рис Ха́ртманис (латыш. Juris Hartmanis; 5 июля 1928, Рига — 29 июля 2022) — учёный в области теории вычислительных систем, награждён в 1993 году премией Тьюринга за достижения в исследовании теории сложности вычислений.
Уильям Джон Макуорн Ранкин (Ренкин) (англ. William John Macquorn Rankine; 5 июля 1820, Эдинбург — 24 декабря 1872, Глазго) — шотландский инженер, физик и механик, один из создателей технической термодинамики. В 1849 году независимо от Клаузиуса получил общие уравнения термодинамики, выражающие соотношение между количеством теплоты и механической энергией. Исследовал термодинамические свойства газов и пара в 1850 году и составил таблицы водяных паров получивших широкое применение. В 1859 году построил полную теорию паровой машины; в частности, разработал идеальный термодинамический цикл парового двигателя, названного в его честь.
Ге́рард Хо́фт (Герард эт Хоофт, нид. Gerardus (Gerard) ’t Hooft; род. 5 июля 1946, Ден-Хелдер, Северная Голландия) — голландский физик-теоретик, профессор Утрехтского университета (Нидерланды), лауреат Нобелевской премии по физике за 1999 год (совместно с Мартинусом Велтманом). Разработанные Хофтом и Велтманом математические методы ренормализации янг-миллсовских полей, как безмассовых, так и получающих массу вследствие спонтанного нарушения симметрии, позволили рассчитать некоторые эффекты электрослабого взаимодействия, в частности, оценить массы промежуточных векторных бозонов W± и Z0, предсказанных теорией и вскоре после этого открытых экспериментально, причём полученные значения хорошо согласовывались с экспериментальными данными. Методом Велтмана и Хофта также была рассчитана масса топ-кварка, экспериментально обнаруженного в 1995 году в Национальной лаборатории им. Э. Ферми (США).
1996 — в Великобритании родилось первое клонированное млекопитающее — овца Долли
2016 — автоматическая межпланетная станция НАСА «Юнона», запущенная в 2011 году, вышла на полярную орбиту Юпитера.
#Biography #Birth_Date #Events #05июля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
История технологии сегодня — 6 июля
ℹ️ Кто родился в этот день
Бори́с Па́влович Константи́нов (23 июня (6 июля) 1910, Санкт-Петербург — 9 июля 1969, Ленинград) — советский учёный, физик-ядерщик, академик (с 1960; член-корреспондент с 1953), вице-президент Академии наук СССР (c 8 февраля 1966 по 9 июля 1969). Работы посвящены акустике, физической химии, физике изотопов, физике плазмы и проблеме управляемого термоядерного синтеза, астрофизике, голографии. В ФТИ им. А. Ф. Иоффе основал астрофизическую лабораторию и филиал ядерной физики (впоследствии ПИЯФ).
🌐 Знаковые события
1926 — в СССР открыта первая электрифицированная линия железной дороги (Баку-Сабунчи).
2003 — с помощью радиотелескопа РТ-70 под Евпаторией был передан Космический зов — кодированное послание к нескольким звёздам солнечного типа.
#Biography #Birth_Date #Events #06июля
Бори́с Па́влович Константи́нов (23 июня (6 июля) 1910, Санкт-Петербург — 9 июля 1969, Ленинград) — советский учёный, физик-ядерщик, академик (с 1960; член-корреспондент с 1953), вице-президент Академии наук СССР (c 8 февраля 1966 по 9 июля 1969). Работы посвящены акустике, физической химии, физике изотопов, физике плазмы и проблеме управляемого термоядерного синтеза, астрофизике, голографии. В ФТИ им. А. Ф. Иоффе основал астрофизическую лабораторию и филиал ядерной физики (впоследствии ПИЯФ).
1926 — в СССР открыта первая электрифицированная линия железной дороги (Баку-Сабунчи).
2003 — с помощью радиотелескопа РТ-70 под Евпаторией был передан Космический зов — кодированное послание к нескольким звёздам солнечного типа.
#Biography #Birth_Date #Events #06июля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
[Совет по Java #057]
Тема:
Проблема:
Решение: В пулах потоков избегайте использования
Объяснение:
В пулах потоков потоки создаются один раз и затем переиспользуются, поэтому наследование происходит только при инициализации пула. Если пул создан в главном потоке, то все задачи унаследуют контекст главного потока, а не контекст того потока, который отправил задачу. Если пул создается внутри задачи, то все потоки пула унаследуют контекст этой задачи, что также нежелательно. Таким образом,
#Java #советы
Тема:
ThreadLocal с InheritableThreadLocal опасен для пулов потоков.Проблема:
InheritableThreadLocal расширяет ThreadLocal и позволяет передавать значения из родительского потока в дочерний при создании нового потока. В средах с пулами потоков (например, ExecutorService, веб-контейнеры) потоки не создаются заново для каждой задачи, а переиспользуются. При использовании InheritableThreadLocal значения наследуются от потока, который создал пул (обычно главный поток приложения), а не от того, который поставил задачу. Это приводит к тому, что все задачи в пуле получают один и тот же контекст, либо, если пул был создан внутри другой задачи, дочерние задачи могут унаследовать контекст от случайной родительской задачи. В результате происходит утечка контекста безопасности, идентификатора пользователя, транзакционных данных и т.п., что приводит к непредсказуемому поведению и серьезным уязвимостям.Решение: В пулах потоков избегайте использования
InheritableThreadLocal. Если нужно передать контекст, используйте явные параметры в методах или передавайте контекст через ThreadLocal с ручной установкой и обязательной очисткой в блоке try-finally. Для безопасной передачи контекста между задачами в пулах применяйте ThreadLocal и устанавливайте его значение перед выполнением задачи, очищая после. В высоконагруженных системах рассмотрите использование ScopedValue (Java 21+), который предназначен для передачи значений без утечек. Никогда не полагайтесь на автоматическое наследование в пулах потоков.public class InheritableThreadLocalPitfall {
//Опасно: InheritableThreadLocal в пуле
private static final InheritableThreadLocal<String> USER_CONTEXT =
new InheritableThreadLocal<>();
public static void main(String[] args) throws InterruptedException {
ExecutorService executor = Executors.newFixedThreadPool(2);
// Главный поток устанавливает контекст
USER_CONTEXT.set("Admin");
// Задача, которая пытается получить унаследованное значение
executor.submit(() -> {
// Выведет "Admin", даже если ожидается другой контекст
System.out.println("Task 1 - inherited: " + USER_CONTEXT.get());
});
// Меняем контекст перед новой задачей в главном потоке
USER_CONTEXT.set("Guest");
executor.submit(() -> {
// Выведет "Guest" (текущее значение главного потока)
System.out.println("Task 2 - inherited: " + USER_CONTEXT.get());
});
// В реальности пул создан один раз, и значения берутся из главного
// потока в момент создания пула или подачи задачи? На самом деле
// наследование происходит при создании потока, а не при submit.
// В данном примере потоки уже созданы, поэтому унаследованных значений нет.
// Это показывает, что наследование происходит только при создании потока.
// Если создать новый пул внутри другой задачи, то контекст унаследуется
// от родительской задачи, что тоже опасно.
executor.shutdown();
}
}//Безопасный подход: явная передача контекста
public class SafeThreadLocal {
private static final ThreadLocal<String> CONTEXT = new ThreadLocal<>();
public static void executeWithContext(ExecutorService executor,
String user, Runnable task) {
executor.submit(() -> {
try {
CONTEXT.set(user);
task.run();
} finally {
CONTEXT.remove(); // обязательная очистка
}
});
}
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(2);
executeWithContext(executor, "Admin", () -> {
System.out.println("Working as: " + CONTEXT.get());
});
executor.shutdown();
}
}
Объяснение:
InheritableThreadLocal работает только в момент создания нового потока — он копирует значения из родительского потока в новый поток. В пулах потоков потоки создаются один раз и затем переиспользуются, поэтому наследование происходит только при инициализации пула. Если пул создан в главном потоке, то все задачи унаследуют контекст главного потока, а не контекст того потока, который отправил задачу. Если пул создается внутри задачи, то все потоки пула унаследуют контекст этой задачи, что также нежелательно. Таким образом,
InheritableThreadLocal нарушает принцип изоляции задач в пуле. Правильный подход — явно устанавливать контекст для каждой задачи и обязательно очищать его после выполнения, чтобы избежать утечек между задачами в одном потоке. Начиная с Java 21, ScopedValue предоставляет безопасную альтернативу для передачи значений, которая автоматически очищается.#Java #советы
👍4
Что выведет код?
#Tasks
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Task060726 {
private static final InheritableThreadLocal<String> threadLocal = new InheritableThreadLocal<>();
public static void main(String[] args) {
threadLocal.set("main");
ExecutorService executor = Executors.newFixedThreadPool(1);
for (int i = 0; i < 3; i++) {
final int taskId = i;
executor.submit(() -> {
if (threadLocal.get() == null) {
threadLocal.set("task" + taskId);
}
System.out.print(threadLocal.get() + " ");
});
}
executor.shutdown();
}
}
#Tasks
👍3
Варианты ответа:
Anonymous Quiz
43%
main main main
21%
task0 task1 task2
29%
task0 task0 task0
7%
null null null
👍3
Что такое 🤓
Ответ:
В Java 9 добавлены новые методы Optional:
ifPresentOrElse(Consumer action, Runnable emptyAction) — выполняет одно действие, если значение есть, и другое, если отсутствует.
or(Supplier<Optional>) — позволяет "подменить" пустой Optional другим Optional. Также в Java 10 появился orElseThrow() (который стал синонимом get()).
Эти методы делают работу с Optional более функциональной и избавляют от использования isPresent()/get(), что считается анти-паттерном.
#собеседование
Optional.ifPresentOrElse() и Optional.or()? Ответ:
ifPresentOrElse(Consumer action, Runnable emptyAction) — выполняет одно действие, если значение есть, и другое, если отсутствует.
or(Supplier<Optional>) — позволяет "подменить" пустой Optional другим Optional. Также в Java 10 появился orElseThrow() (который стал синонимом get()).
Эти методы делают работу с Optional более функциональной и избавляют от использования isPresent()/get(), что считается анти-паттерном.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
История технологии сегодня — 7 июля
ℹ️ Кто родился в этот день
Ю́рий Серге́евич О́сипов (род. 7 июля 1936, Тобольск) — советский и российский математик и механик, профессор. Специалист в области прикладной математики и механики. Основные научные исследования посвящены теории управления, дифференциальным уравнениям и их приложениям.
Создал законченную теорию стабилизации стационарных и периодических динамических систем, описываемых дифференциальными уравнениями с запаздывающим аргументом.
Разработал теорию дифференциальных игр для динамических систем с запаздывающим аргументом.
Открыл конструктивный локальный принцип управления системами с запаздыванием.
Построил теорию антагонистических позиционных дифференциальных игр для другого класса конфликтно управляемых систем с бесконечномерными пространствами фазовых состояний — систем, описываемых дифференциальными уравнениями с частными производными, в первую очередь параболическими.
Цикл работ посвящён созданию теории устойчивого динамического обращения управляемых систем.
Получил серию результатов в смежных направлениях: им выполнен ряд работ по оптимизации форм, в одной из которых был, в частности, дан ответ на вопрос о существовании оптимума, поставленный Ж.-Л. Лионсом.
🌐 Знаковые события
1891 — компания «Американ Экспресс» запатентовала дорожные чеки, послужившие прообразом современных кредитных карт.
#Biography #Birth_Date #Events #07июля
Ю́рий Серге́евич О́сипов (род. 7 июля 1936, Тобольск) — советский и российский математик и механик, профессор. Специалист в области прикладной математики и механики. Основные научные исследования посвящены теории управления, дифференциальным уравнениям и их приложениям.
Создал законченную теорию стабилизации стационарных и периодических динамических систем, описываемых дифференциальными уравнениями с запаздывающим аргументом.
Разработал теорию дифференциальных игр для динамических систем с запаздывающим аргументом.
Открыл конструктивный локальный принцип управления системами с запаздыванием.
Построил теорию антагонистических позиционных дифференциальных игр для другого класса конфликтно управляемых систем с бесконечномерными пространствами фазовых состояний — систем, описываемых дифференциальными уравнениями с частными производными, в первую очередь параболическими.
Цикл работ посвящён созданию теории устойчивого динамического обращения управляемых систем.
Получил серию результатов в смежных направлениях: им выполнен ряд работ по оптимизации форм, в одной из которых был, в частности, дан ответ на вопрос о существовании оптимума, поставленный Ж.-Л. Лионсом.
1891 — компания «Американ Экспресс» запатентовала дорожные чеки, послужившие прообразом современных кредитных карт.
#Biography #Birth_Date #Events #07июля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Раздел 11. Работа с файлами, I/O и сетью (NIO.2)
Глава 2. Современный NIO.2 (java.nio.file)
Интерфейс
Интерфейс
Что такое Path
Path (от англ. "путь") — это интерфейс, представляющий иерархическое расположение файла или директории в файловой системе. Главное отличие от старого
Абстракция — в программировании это способ представления сложной реальности в упрощённом виде, скрывая детали реализации.
Создание объекта Path
Основной способ создания — статический метод фабрики
Способ 1: единая строка пути
При передаче строки с обратными слешами в Windows
Способ 2: сегменты пути (varargs)
Этот способ удобен при динамической сборке пути из частей. Метод
Способ 3: относительный путь
Относительный путь строится относительно текущей рабочей директории JVM — это директория, из которой был запущен процесс Java.
Способ 4: через FileSystem
Ключевые методы интерфейса Path
toString() — строковое представление
Метод возвращает строку пути в нативном формате ОС. Это не просто геттер — он выполняет конкатенацию сегментов с правильным разделителем.
getFileName() — имя файла или последняя директория
Возвращает последний сегмент пути как новый объект
getParent() — родительская директория
Возвращает путь без последнего сегмента. Если у пути нет родителя (корень или относительный путь из одного сегмента), возвращает
getRoot() — корневая часть пути
Для абсолютного пути возвращает корневой элемент (
getNameCount() — количество сегментов
Возвращает число имен (сегментов) в пути, исключая корень. Корень не считается именем — это отправная точка иерархии.
getName(int index) — сегмент по индексу
Индексация начинается с 0. Индекс
subpath(int beginIndex, int endIndex) — подпуть
Возвращает подпуть от
isAbsolute() — проверка на абсолютность
Абсолютный путь содержит корневой элемент и однозначно указывает местоположение в файловой системе. Относительный — зависит от текущей директории.
toAbsolutePath() — преобразование в абсолютный
Если путь уже абсолютный — возвращает себя. Иначе резолвит относительно текущей рабочей директории.
normalize() — нормализация пути
Удаляет избыточные сегменты:
resolve(Path other) — резолюция пути
Если
relativize(Path other) — относительный путь между двумя путями
Вычисляет, как добраться от
startsWith(Path other) / endsWith(Path other)
Сравнивают сегменты пути, а не строки.
#Java #для_новичков #beginner #IO #NIO #Path
Глава 2. Современный NIO.2 (java.nio.file)
Интерфейс
Path – путь к файлу/директорииИнтерфейс
Path — это ключевая абстракция в Java NIO.2 (New I/O 2), представленная в Java 7 (2011 год, пакет java.nio.file). Он заменил устаревший класс java.io.File и предоставляет платформонезависимый способ работы с путями к файлам и директориям. В отличие от File, который напрямую обращался к файловой системе ОС, Path — это чистая абстракция: объект Path может существовать в памяти JVM, даже если соответствующего файла на диске нет.Что такое Path
Path (от англ. "путь") — это интерфейс, представляющий иерархическое расположение файла или директории в файловой системе. Главное отличие от старого
File в том, что Path — это не файл, а именно путь. Он не знает, существует ли файл, доступен ли он для чтения, и т.д. — эти вопросы решаются через другие классы NIO.2, например Files.Абстракция — в программировании это способ представления сложной реальности в упрощённом виде, скрывая детали реализации.
Path абстрагирует различия между файловыми системами: в Windows путь разделяется обратным слешем C:\Users\file.txt, в Linux и macOS — прямым /home/user/file.txt. Path нормализует эти различия на уровне API.Создание объекта Path
Основной способ создания — статический метод фабрики
Paths.get(). Класс Paths (во множественном числе) — это утилитарный класс-фабрика, который делегирует создание Path текущей файловой системе по умолчанию.Способ 1: единая строка пути
import java.nio.file.Path;
import java.nio.file.Paths;
// Linux / macOS
Path linuxPath = Paths.get("/home/user/documents/report.txt");
// Windows
Path windowsPath = Paths.get("C:\\Users\\Admin\\file.txt");
При передаче строки с обратными слешами в Windows
Paths.get() корректно парсит путь. Важно: в Java-строке обратный слеш — это escape-символ, поэтому в литерале пишется \\, но при чтении из внешнего источника (конфиг, ввод пользователя) это не требуется.Способ 2: сегменты пути (varargs)
Path path = Paths.get("/home", "user", "documents", "report.txt");
// Результат: /home/user/documents/report.txtЭтот способ удобен при динамической сборке пути из частей. Метод
get(String first, String... more) принимает первый сегмент и переменное число дополнительных сегментов (varargs — механизм Java для передачи произвольного количества аргументов одного типа). Сегменты автоматически соединяются разделителем, специфичным для ОС.Способ 3: относительный путь
Path relative = Paths.get("src", "main", "java", "App.java");
// Результат: src/main/java/App.java (на Unix) или src\main\java\App.java (на Windows)Относительный путь строится относительно текущей рабочей директории JVM — это директория, из которой был запущен процесс Java.
Способ 4: через FileSystem
import java.nio.file.FileSystems;
Path path = FileSystems.getDefault().getPath("/tmp", "data.txt");
FileSystems.getDefault() возвращает объект FileSystem — абстракцию над конкретной файловой системой. Этот подход используется при работе с нестандартными файловыми системами (например, ZIP-архив как файловая система через FileSystems.newFileSystem()).Ключевые методы интерфейса Path
toString() — строковое представление
Path p = Paths.get("/home/user/file.txt");
System.out.println(p.toString());
// Вывод: /home/user/file.txtМетод возвращает строку пути в нативном формате ОС. Это не просто геттер — он выполняет конкатенацию сегментов с правильным разделителем.
getFileName() — имя файла или последняя директория
Path p = Paths.get("/home/user/documents/report.txt");
Path fileName = p.getFileName(); // report.txt
Path dir = Paths.get("/home/user/documents");
Path dirName = dir.getFileName(); // documentsВозвращает последний сегмент пути как новый объект
Path. Если путь — корень (/), возвращает null.getParent() — родительская директория
Path p = Paths.get("/home/user/documents/report.txt");
Path parent = p.getParent(); // /home/user/documents
Path root = Paths.get("/");
Path rootParent = root.getParent(); // nullВозвращает путь без последнего сегмента. Если у пути нет родителя (корень или относительный путь из одного сегмента), возвращает
null.getRoot() — корневая часть пути
Path absolute = Paths.get("/home/user/file.txt");
Path root = absolute.getRoot(); // /
Path relative = Paths.get("src/main/java");
Path relRoot = relative.getRoot(); // nullДля абсолютного пути возвращает корневой элемент (
/ на Unix, C:\ на Windows). Для относительного — null, так как корень не определён.getNameCount() — количество сегментов
Path p = Paths.get("/home/user/documents/report.txt");
int count = p.getNameCount(); // 4 (home, user, documents, report.txt)Возвращает число имен (сегментов) в пути, исключая корень. Корень не считается именем — это отправная точка иерархии.
getName(int index) — сегмент по индексу
Path p = Paths.get("/home/user/documents/report.txt");
Path segment = p.getName(1); // userИндексация начинается с 0. Индекс
0 — первый сегмент после корня. Выход за границы выбрасывает IllegalArgumentException.subpath(int beginIndex, int endIndex) — подпуть
Path p = Paths.get("/home/user/documents/report.txt");
Path sub = p.subpath(1, 3); // user/documentsВозвращает подпуть от
beginIndex (включительно) до endIndex (исключительно). Индексы отсчитываются от корня, но сам корень в результат не включается.isAbsolute() — проверка на абсолютность
Path abs = Paths.get("/etc/passwd");
boolean isAbs = abs.isAbsolute(); // true
Path rel = Paths.get("config/app.properties");
boolean isRel = rel.isAbsolute(); // falseАбсолютный путь содержит корневой элемент и однозначно указывает местоположение в файловой системе. Относительный — зависит от текущей директории.
toAbsolutePath() — преобразование в абсолютный
Path rel = Paths.get("config/app.properties");
Path abs = rel.toAbsolutePath();
// Результат: /current/working/dir/config/app.propertiesЕсли путь уже абсолютный — возвращает себя. Иначе резолвит относительно текущей рабочей директории.
normalize() — нормализация пути
Path p = Paths.get("/home/user/../documents/./report.txt");
Path norm = p.normalize(); // /home/documents/report.txtУдаляет избыточные сегменты:
. (текущая директория) и .. (родительская директория). Не проверяет реальное существование файловой системы — работает чисто на уровне строк.resolve(Path other) — резолюция пути
Path base = Paths.get("/home/user");
Path resolved = base.resolve("documents/report.txt");
// Результат: /home/user/documents/report.txtЕсли
other абсолютный — возвращает other. Если относительный — присоединяет к base. Эквивалент операции "base/other".relativize(Path other) — относительный путь между двумя путями
Path base = Paths.get("/home/user");
Path target = Paths.get("/home/user/documents/report.txt");
Path rel = base.relativize(target); // documents/report.txtВычисляет, как добраться от
base до target относительным путём. Оба пути должны быть либо абсолютными, либо относительными.startsWith(Path other) / endsWith(Path other)
Path p = Paths.get("/home/user/documents");
boolean starts = p.startsWith(Paths.get("/home")); // true
boolean ends = p.endsWith(Paths.get("documents")); // trueСравнивают сегменты пути, а не строки.
startsWith проверяет, начинается ли путь с указанных сегментов с учётом иерархии.#Java #для_новичков #beginner #IO #NIO #Path
👍4
toFile() — обратная совместимость
Преобразует Path в старый java.io.File. Полезно при интеграции с legacy-кодом или библиотеками, которые ещё не перешли на NIO.2.
iterator() — итерация по сегментам
Path реализует Iterable<Path>, что позволяет использовать for-each для обхода сегментов. Корень в итерацию не включается.
compareTo(Path other) — лексикографическое сравнение
Сравнивает пути посегментно, учитывая регистр (на системах с case-sensitive файловыми системами). Реализует
Путь байтов в памяти JVM при работе с Path
Когда вы пишете Paths.get("/home/user/file.txt"), в памяти JVM происходит следующее:
1. Создание строки в пуле строк (String Pool)
Литерал
При компиляции он попадает в пул строк (String Pool) — специальная область в Metaspace (начиная с Java 8; ранее — PermGen).
Пул строк — это кэш строковых литералов, где одинаковые строки представлены единственным экземпляром. Это экономит память, так как строки в Java иммутабельны (неизменяемы).
Metaspace — область памяти JVM, выделенная под метаданные классов, константы, пул строк и другие внутренние структуры.
В отличие от старого PermGen, Metaspace использует нативную память (native memory) вне кучи и расширяется динамически.
2. Вызов Paths.get() и создание объекта Path
Метод
Файловая система по умолчанию (обычно
Эти объекты создаются в куче (Heap) — основной области памяти для объектов Java.
Объект
Ссылку на файловую систему (
Массив байтов или строк, представляющих сегменты пути
Хэш-код для кэширования
3. Работа GC с объектами Path
Объекты
GC (Garbage Collector, сборщик мусора) — это механизм JVM, автоматически освобождающий память от объектов, на которые больше нет ссылок.
Когда переменная
Однако сама строка-путь в пуле строк остаётся — пул строк не подлежит обычной сборке мусора, так как JVM предполагает, что строковые литералы могут понадобиться снова.
Если
Young Generation — часть кучи, где размещаются новые объекты. Она делится на Eden (пространство, куда попадают все новые объекты) и два Survivor-пространства (S0, S1). Когда Eden заполняется, запускается Minor GC — быстрая сборка мусора, перемещающая живые объекты в Survivor. Объекты
Если объект
Важно:
4. Байты на уровне ОС
Когда
#Java #для_новичков #beginner #IO #NIO #Path
Path path = Paths.get("/tmp/data.txt");
java.io.File legacyFile = path.toFile();Преобразует Path в старый java.io.File. Полезно при интеграции с legacy-кодом или библиотеками, которые ещё не перешли на NIO.2.
iterator() — итерация по сегментам
Path p = Paths.get("/home/user/file.txt");
for (Path segment : p) {
System.out.println(segment);
}
// Вывод: home, user, file.txtPath реализует Iterable<Path>, что позволяет использовать for-each для обхода сегментов. Корень в итерацию не включается.
compareTo(Path other) — лексикографическое сравнение
Path p1 = Paths.get("/a/b/c");
Path p2 = Paths.get("/a/b/d");
int result = p1.compareTo(p2); // отрицательное число (c < d)Сравнивает пути посегментно, учитывая регистр (на системах с case-sensitive файловыми системами). Реализует
Comparable<Path>, что позволяет сортировать пути.Путь байтов в памяти JVM при работе с Path
Когда вы пишете Paths.get("/home/user/file.txt"), в памяти JVM происходит следующее:
1. Создание строки в пуле строк (String Pool)
Литерал
"/home/user/file.txt" — это объект String. При компиляции он попадает в пул строк (String Pool) — специальная область в Metaspace (начиная с Java 8; ранее — PermGen).
Пул строк — это кэш строковых литералов, где одинаковые строки представлены единственным экземпляром. Это экономит память, так как строки в Java иммутабельны (неизменяемы).
Metaspace — область памяти JVM, выделенная под метаданные классов, константы, пул строк и другие внутренние структуры.
В отличие от старого PermGen, Metaspace использует нативную память (native memory) вне кучи и расширяется динамически.
2. Вызов Paths.get() и создание объекта Path
Метод
Paths.get() вызывает FileSystems.getDefault().getPath(first, more). Файловая система по умолчанию (обычно
UnixFileSystem на Linux/macOS или WindowsFileSystem на Windows) создаёт конкретную реализацию Path — например, UnixPath или WindowsPath.Эти объекты создаются в куче (Heap) — основной области памяти для объектов Java.
Объект
Path хранит:Ссылку на файловую систему (
FileSystem)Массив байтов или строк, представляющих сегменты пути
Хэш-код для кэширования
3. Работа GC с объектами Path
Объекты
Path — это обычные Java-объекты в куче. GC (Garbage Collector, сборщик мусора) — это механизм JVM, автоматически освобождающий память от объектов, на которые больше нет ссылок.
Когда переменная
Path выходит из области видимости (например, метод завершился, и локальная переменная недоступна), объект становится кандидатом на сборку мусора. Однако сама строка-путь в пуле строк остаётся — пул строк не подлежит обычной сборке мусора, так как JVM предполагает, что строковые литералы могут понадобиться снова.
Если
Path создаётся динамически (например, Paths.get(base, userInput)), и входные данные уникальны при каждом вызове, строки не попадают в пул автоматически (если только не вызван intern()). Такие строки создаются в куче и полностью управляются GC. При частом создании временных путей (например, в цикле обработки 10 000 файлов) объекты Path и связанные строки накапливаются в Young Generation (молодое поколение) кучи.Young Generation — часть кучи, где размещаются новые объекты. Она делится на Eden (пространство, куда попадают все новые объекты) и два Survivor-пространства (S0, S1). Когда Eden заполняется, запускается Minor GC — быстрая сборка мусора, перемещающая живые объекты в Survivor. Объекты
Path, созданные внутри короткоживущего метода, обычно уничтожаются на этом этапе.Если объект
Path кэшируется (например, сохраняется в статическое поле или долгоживущую коллекцию), он переходит в Old Generation (старое поколение, Tenured). Там он живёт до Major GC (или Full GC) — более тяжёлой сборки, которая затрагивает всю кучу. Major GC запускается, когда Old Generation заполняется.Важно:
Path — лёгкий объект. Он не держит открытых файловых дескрипторов (в отличие от FileInputStream). Поэтому его сборка мусора безопасна в любой момент. Однако если Path используется для открытия ресурса (через Files.newInputStream(path)), то сам поток уже требует явного закрытия через try-with-resources, иначе дескриптор останется открытым на уровне ОС, даже если объект Path собран GC.4. Байты на уровне ОС
Когда
Path передаётся в метод Files.readAllBytes(path), JVM через JNI (Java Native Interface — механизм вызова нативного кода) обращается к системному вызову ОС. Путь преобразуется в массив байтов в кодировке, понятной файловой системе (обычно UTF-8). Эти байты передаются в системный вызов open() (POSIX) или CreateFile() (Windows). Прочитанные данные возвращаются в JVM как массив байтов в куче (heap-allocated byte array).#Java #для_новичков #beginner #IO #NIO #Path
👍5
Интеграции и практические примеры
Пример 1: Обход директории с фильтрацией
Пример 2: Резолюция путей в конфигурации приложения
Этот паттерн защищает от Path Traversal (атака обхода пути), когда злоумышленник передаёт
Пример 3: Копирование с проверкой
Пример 4: Работа с временными файлами
Path vs File: ключевые различия
Класс java.io.File (существует с Java 1.0) имеет ряд архитектурных недостатков:
Смешение ответственности:
Ограниченная поддержка символических ссылок:
Отсутствие нормализации:
Нет поддержки файловых систем, отличных от дефолтной:
Методы
#Java #для_новичков #beginner #IO #NIO #Path
Пример 1: Обход директории с фильтрацией
import java.nio.file.*;
import java.io.IOException;
public class DirectoryScanner {
public static void scanDirectory(Path root) throws IOException {
// Files.walk — рекурсивный обход дерева директорий
try (Stream<Path> paths = Files.walk(root, 3)) { // глубина 3 уровня
paths.filter(Files::isRegularFile) // только файлы
.filter(p -> p.toString().endsWith(".java"))
.forEach(p -> System.out.println(p.toAbsolutePath()));
}
}
}
Files.walk() возвращает Stream<Path> — ленивый поток (lazy stream), который читает директории по мере необходимости. Это предотвращает загрузку всех путей в память сразу, что критично для больших файловых деревьев.Пример 2: Резолюция путей в конфигурации приложения
public class ConfigResolver {
private final Path baseDir;
public ConfigResolver(String basePath) {
this.baseDir = Paths.get(basePath).toAbsolutePath().normalize();
}
public Path resolveConfig(String configName) {
// resolve объединяет baseDir с относительным путём
Path resolved = baseDir.resolve("config").resolve(configName);
// безопасность: проверяем, что результирующий путь всё ещё внутри baseDir
if (!resolved.startsWith(baseDir)) {
throw new SecurityException("Path traversal attempt detected");
}
return resolved;
}
}Этот паттерн защищает от Path Traversal (атака обхода пути), когда злоумышленник передаёт
../../../etc/passwd в качестве configName. Метод startsWith() гарантирует, что результирующий путь остаётся внутри разрешённой директории.Пример 3: Копирование с проверкой
public void safeCopy(Path source, Path target) throws IOException {
// normalize убирает . и .. перед проверкой
Path normalizedSource = source.toAbsolutePath().normalize();
Path normalizedTarget = target.toAbsolutePath().normalize();
// getParent возвращает директорию назначения
Path targetDir = normalizedTarget.getParent();
if (targetDir != null && !Files.exists(targetDir)) {
Files.createDirectories(targetDir); // создаём всю цепочку директорий
}
// StandardCopyOption — перечисление, определяющее поведение копирования
Files.copy(normalizedSource, normalizedTarget,
StandardCopyOption.REPLACE_EXISTING,
StandardCopyOption.COPY_ATTRIBUTES);
}StandardCopyOption — это enum (перечисление), тип данных в Java, представляющий фиксированный набор констант. REPLACE_EXISTING разрешает перезапись существующего файла, COPY_ATTRIBUTES копирует метаданные (права доступа, временные метки).Пример 4: Работа с временными файлами
public Path createTempFileWithPath() throws IOException {
// getDefault() возвращает файловую систему по умолчанию
Path tempDir = FileSystems.getDefault().getPath(System.getProperty("java.io.tmpdir"));
// createTempFile создаёт файл с префиксом и суффиксом
Path tempFile = Files.createTempFile(tempDir, "app_", ".tmp");
System.out.println("Created: " + tempFile.toAbsolutePath());
return tempFile;
}System.getProperty("java.io.tmpdir") возвращает путь к временной директории ОС. Files.createTempFile гарантирует уникальность имени через атомарную операцию на уровне файловой системы.Path vs File: ключевые различия
Класс java.io.File (существует с Java 1.0) имеет ряд архитектурных недостатков:
Смешение ответственности:
File одновременно представляет и путь, и файл, и директорию. Path разделяет эти концепции.Ограниченная поддержка символических ссылок:
File не различает символическую ссылку и целевой файл. Path в сочетании с Files предоставляет полный контроль.Отсутствие нормализации:
File не предоставляет методов для работы с . и ... Path.normalize() решает это.Нет поддержки файловых систем, отличных от дефолтной:
Path работает с любой FileSystem — ZIP, память, сетевые ФС.Методы
File возвращают boolean вместо исключений: file.delete() возвращает false при ошибке, не объясняя причину. Files.delete(path) выбрасывает IOException с деталями.#Java #для_новичков #beginner #IO #NIO #Path
👍5
Что выведет код?
#Tasks
import java.nio.file.Path;
import java.nio.file.Paths;
public class Task070726 {
public static void main(String[] args) {
Path p1 = Paths.get("/foo");
Path p2 = Paths.get("/bar");
Path p3 = p1.resolve(p2);
Path p4 = p1.resolve("bar");
System.out.print(p3 + " " + p4);
}
}
#Tasks
👍3
Варианты ответа:
Anonymous Quiz
22%
/foo/bar /bar
11%
/bar /foo/bar
44%
/foo/bar /foo/bar
22%
/bar /bar
👍3
Что такое 🤓
Ответ:
В Java 16 добавлен метод Stream.toList() (без параметров), который возвращает неизменяемый список (immutable).
В отличие от collect(Collectors.toList()), который возвращает мутабельный список (обычно ArrayList). toList() гарантирует, что список нельзя изменить (выбросит UnsupportedOperationException).
Это экономит память и улучшает безопасность. Для мутабельного списка всё ещё используйте collect(Collectors.toCollection(ArrayList::new)) или collect(Collectors.toList()).
#собеседование
Stream.toList() и чем отличается от collect(Collectors.toList())? Ответ:
В отличие от collect(Collectors.toList()), который возвращает мутабельный список (обычно ArrayList). toList() гарантирует, что список нельзя изменить (выбросит UnsupportedOperationException).
Это экономит память и улучшает безопасность. Для мутабельного списка всё ещё используйте collect(Collectors.toCollection(ArrayList::new)) или collect(Collectors.toList()).
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
История технологии сегодня — 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июля
И́горь Евге́ньевич Тамм (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]
Тема:
Проблема:
Если разработчик забывает это сделать или между
В отличие от
Решение: Всегда обрамляйте вызов
Это гарантирует, что блокировка будет освобождена даже при возникновении исключения. Для операций с таймаутами используйте
При работе с
Объяснение:
Блок
#Java #советы
Тема:
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
Что выведет код?
#Tasks
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(Function classifier) — собирает элементы в Map, где ключ — результат классификатора, значение — список элементов. Есть перегрузки с downstream коллектором (например, counting(), summingInt()).
Collectors.partitioningBy(Predicate) — разбивает на две части (true/false), возвращая Map<Boolean, List>.
Оба мощные инструменты для статистики и отчетов. Пример: группировка сотрудников по департаментам, подсчет количества, суммы зарплат и т.д. Основа для data-driven операций.
#собеседование
Collectors.groupingBy() и partitioningBy()? Ответ:
Collectors.groupingBy(Function classifier)
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июля
Бенджамин (Бен) Рой Мо́ттельсон (англ. 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 — утилитный класс для работы с файлами
Класс
Утилитный класс (utility class) — это класс, содержащий только статические методы и константы, не предназначенный для создания экземпляров. Обычно он имеет приватный конструктор, чтобы предотвратить инстанцирование.
Архитектура: почему Files лучше java.io.File
Старый класс
Разделение ответственности
Исключения вместо молчаливых ошибок
Методы
Методы
Checked-исключение — это исключение в Java, которое компилятор требует либо обработать в блоке
Поддержка символических ссылок
Символическая ссылка (symbolic link, symlink) — это специальный файл в файловой системе, содержащий путь к другому файлу или директории. В отличие от жёсткой ссылки, символическая ссылка может указывать на несуществующий объект и может пересекать границы файловых систем.
Атомарность и конкурентность
Многие методы
Атомарная операция — это операция, которая либо выполняется целиком, либо не выполняется вообще; промежуточных состояний не существует. В контексте файловых систем это означает, что другие процессы не увидят частичного результата.
Проверка существования и типа файла
Files.exists(Path path, LinkOption... options)
Метод проверяет, существует ли файл, директория или символическая ссылка по указанному пути. Возвращает
Важный нюанс:
Параметр
Files.notExists(Path path, LinkOption... options)
Этот метод возвращает
Файл не существует — возвращает
Файл существует, но нет прав на проверку — возвращает
Произошла другая ошибка ввода-вывода — выбрасывает
Эта пара методов реализует трёхзначную логику существования: DEFINITELY_EXISTS, DEFINITELY_NOT_EXISTS, UNKNOWN. Такой подход необходим в системах, где безопасность критична: например, при проверке перед созданием файла, чтобы избежать перезаписи существующего файла, к которому у вас нет прав на чтение, но есть права на запись.
#Java #для_новичков #beginner #IO #NIO #Files
Глава 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