FilesЧтение всего файла в список строк (
readAllLines)
import java.nio.file.*;
import java.io.IOException;
import java.util.List;
public class Main {
public static void main(String[] args) throws IOException {
Path path = Paths.get("example.txt");
List<String> lines = Files.readAllLines(path);
lines.forEach(System.out::println);
}
}
📌 Читает весь файл в List<String>, удобно для небольших файлов.
Запись в файл (
write)
List<String> lines = List.of("Первая строка", "Вторая строка");
Files.write(Paths.get("output.txt"), lines);
📌 Если файла нет — создаст, если есть — перезапишет.
Добавление в файл (без перезаписи):
Files.write(Paths.get("output.txt"), lines, StandardOpenOption.APPEND);
#java #Files #readAllLines #write
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤4
byte — (byte)0;
short — (short)0;
int — 0;
long — 0L;
float — 0f;
double — 0d;
char — \u0000;
boolean — false;
Объекты (в том числе String) — null.
#java #initialization
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍10🥴2❤1
В Java 9 появилось два новых метода, полезных для выбора элементов потока с хорошей производительностью: takeWhile и dropWhile.
Допустим, у нас есть следующий список блюд:
List<Dish> specialMenu = Arrays.asList(
new Dish("seasonal fruit", 120),
new Dish("prawns", 300),
new Dish("rice", 350),
new Dish("chicken", 400),
new Dish("french fries", 530));
Для получения блюд с калорийностью меньше 320, можно воспользоваться операцией
filter. Недостаток операции filter в том, что она требует прохода в цикле по всему потоку данных с применением предиката ко всем элементам.В нашем примере список уже отсортирован по числу калорий. Вместо того, чтобы пройтись по каждому элементу, можно прекратить работу сразу же после обнаружения блюда, содержащего 320 калорий или более. В случае небольшого списка это может показаться не таким уж громадным преимуществом, но при работе с потенциально большим потоком элементов окажется весьма полезным.
Поможет нам в этом операция
takeWhile! Она позволяет выполнить срез любого потока данных (даже бесконечного) с помощью предиката. И, к счастью, она прекращает работу сразу же по обнаружении неподходящего элемента. Вот как ее следует использовать:
List<Dish> sliceMenu1
= specialMenu.stream()
.takeWhile(dish -> dish.getCalories() < 320)
.collect(toList());
#java #stream #takeWhile
Please open Telegram to view this post
VIEW IN TELEGRAM
❤8🔥3👍2
Блоки инициализации позволяют гибко управлять созданием объектов. Вот как их правильно использовать:
Выполняются перед конструктором:
public class Logger {
private String prefix;
{ // Блок инициализации экземпляра (выполняется перед конструктором)
prefix = "[LOG] " + LocalDateTime.now(); // Инициализация префикса с текущей датой/временем
System.out.println("Логгер готов!"); // Сообщение о готовности логгера
}
public Logger() {
System.out.println(prefix + " | Новый объект"); // Вывод информации о создании объекта
}
}▸ Для чего: предварительная настройка полей, валидация, логирование.
Срабатывают один раз при загрузке класса:
public class ConfigLoader {
static {
System.out.println("Загружаем конфиги...");
// Здесь можно читать файлы, подключать БД и т.д.
}
}▸ Для чего: инициализация кэшей, регистрация драйверов, загрузка ресурсов.
- Нестатические блоки → простая инициализация полей
- Статические блоки → настройка системных ресурсов
Для улучшения читаемости кода используйте блоки инициализации для простых операций. Избегайте сложной логики — это может затруднить отладку и понимание приложения.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤1
== и .equals()?При сравнении объектов в Java важно понимать различие между
== и .equals().✔️
== сравнивает ссылки на объекты, проверяя, указывают ли они на одну и ту же область памяти.✔️
.equals() используется для сравнения содержимого объектов, если метод переопределен.Пример:
String a = new String("Java");
String b = new String("Java");
System.out.println(a == b); // false (разные ссылки)
System.out.println(a.equals(b)); // true (сравнение содержимого)equals() в вашем классе.#java #equals #comparison
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤1
Основные компоненты
✔️ Config Server — сервер, который хранит конфигурации (обычно в Git) и раздает их микросервисам.
✔️ Config Client — клиент в микросервисах, который получает конфигурации от Config Server.
Возможности
✔️ Централизация конфигураций всех сервисов.
✔️ Поддержка версионирования конфигураций (например, через Git).
✔️ Динамическое обновление конфигураций без перезапуска приложений с помощью Spring Cloud Bus.
✔️ Поддержка различных сред и профилей (dev, prod и т.д.).
Пример настройки Config Server:
spring:
cloud:
config:
server:
git:
uri: https://github.com/your-repo/config-repo
Пример настройки Config Client:
spring:
cloud:
config:
uri: http://localhost:8888
profile: dev
Преимущества: упрощает управление конфигурациями, поддерживает разные среды, позволяет динамически обновлять настройки.
Недостатки: важен контроль за доступом и стабильностью Config Server.
#java #Spring #Cloud #Config
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤1
В Java есть недооценённая фишка - ленивые вычисления через
Supplier. Это может сильно упростить код и улучшить производительность.📦 Что такое `Supplier`?
Это функциональный интерфейс из
java.util.function, который просто возвращает значение:
Supplier<String> supplier = () -> "Hello";
System.out.println(supplier.get());
Но магия начинается, когда используешь его правильно 👇
🔥 Кейс: дорогое вычисление
public String getData() {
System.out.println("Loading...");
return "data";
}
Теперь сравни:
❌ Обычный вызов:
String result = getData(); // всегда выполняется
✅ Ленивый вызов:
Supplier<String> supplier = this::getData;
// вызов произойдёт только здесь
String result = supplier.get();
👉 Код выполняется только когда реально нужен результат.
⚡ Практическое применение: логирование
logger.debug("Result: " + expensiveOperation());
❗ Даже если debug выключен —
expensiveOperation() всё равно выполнится.✅ Правильно:
logger.debug(() -> "Result: " + expensiveOperation());
👉 Вычисление произойдёт только если лог реально пишется.
🧠 Комбинация с `Optional`
String name = Optional.ofNullable(getName())
.orElseGet(() -> generateDefaultName());
👉
generateDefaultName() вызовется только если значение отсутствует(в отличие от
orElse, который выполняется всегда)🚀 Паттерн: кэширование (lazy cache)
Supplier<String> cached = new Supplier<>() {
private String value;
@Override
public String get() {
if (value == null) {
value = loadExpensiveData();
}
return value;
}
};
👉 Получаешь простую ленивую инициализацию без лишних библиотек
📌 Вывод
Supplier — это не просто "лямбда ради лямбды", а инструмент для:* ленивых вычислений
* оптимизации
* более чистого API
Please open Telegram to view this post
VIEW IN TELEGRAM
❤10👍1
Одна из самых коварных тем в Java — это контракт между
equals() и hashCode(). Ошибся и HashMap или HashSet начинают вести себя "магически" (читай: ломаются).📦 Проблема на практике
Set<User> users = new HashSet<>();
users.add(new User("Alex"));
System.out.println(users.contains(new User("Alex"))); // ❌ false
🤨 Почему
false, если значения одинаковые?⚠️ Причина
По умолчанию
equals() сравнивает ссылки (==), а не содержимое.✅ Правильная реализация
public class User {
private String name;
// equals
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User)) return false;
User user = (User) o;
return Objects.equals(name, user.name);
}
// hashCode
@Override
public int hashCode() {
return Objects.hash(name);
}
}
🔥 Почему важны ОБА метода?
Если переопределить только
equals():
users.add(new User("Alex"));
users.contains(new User("Alex")); // ❌ всё ещё может быть false
👉 Потому что
HashSet сначала смотрит на hashCode(), а потом уже на equals().⚡ Контракт, который нельзя нарушать
1. Если
equals() возвращает true → hashCode() обязан быть одинаковым2. Если
hashCode() одинаковый → equals() может быть как true, так и false💣 Классическая ошибка
Изменяем объект после добавления в
HashSet:
User user = new User("Alex");
users.add(user);
user.setName("Bob");
users.contains(user); // ❌ может вернуть false
👉 Объект "потерялся" в коллекции
🧠 Как избежать проблем
* Делай объекты immutable (final поля)
* Используй
record (Java 16+):
public record User(String name) {}
👉
equals() и hashCode() генерируются автоматически и корректно📌 Вывод
Коллекции в Java работают быстро благодаря
hashCode(),но требуют строгого соблюдения контракта.
Нарушишь - получишь баги, которые очень сложно отловить 🐛
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤1
<?>В Java
<?> называется неограниченным wildcard. Он обозначает, что параметр типа может быть любым, то есть неизвестным на этапе компиляции. Это удобно, когда метод или класс работают с обобщёнными типами, но конкретный тип элемента не важен.Например, выражение
List<?> означает список, элементы которого могут быть любого типа. Такой подход позволяет писать более универсальный и гибкий код, но при этом накладывает ограничения: мы не можем добавлять новые элементы в коллекцию, поскольку компилятор не знает конкретный тип элементов, чтобы обеспечить безопасность типов.
import java.util.List;
public class WildcardExample {
public static void printList(List<?> list) {
for (Object element : list) { // Элементы можно читать как Object
System.out.println(element);
}
}
public static void main(String[] args) {
List<Integer> intList = List.of(1, 2, 3);
List<String> strList = List.of("A", "B", "C");
printList(intList); // Вывод: 1 2 3
printList(strList); // Вывод: A B C
}
}
Здесь
List<?> позволяет передавать любой тип списка, но мы можем безопасно читать только как Object.
public static void addElement(List<?> list) {
// list.add("Hello"); // Ошибка компиляции!
}
#java #wildcard
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤1
nullВозвращение пустых коллекций вместо
null-это рекомендуемый подход для методов, возвращающих коллекции. Он упрощает обработку данных, предотвращает ошибки и делает код более предсказуемым.1. Улучшение читаемости: Код становится проще, так как не нужно проверять результат на null.
2. Предотвращение NullPointerException: Исключается вероятность ошибок, связанных с доступом к null.
3.Соответствие принципу наименьшего удивления: Методы всегда возвращают коллекцию, даже если она пуста.
4. Эффективность: Пустые коллекции создаются один раз и переиспользуются благодаря реализации через паттерн Singleton.
5. Совместимость с функциональным программированием: Пустые коллекции легко интегрируются в стримы и другие функциональные конструкции.
Пример:
public class CacheService {
private final Map<String, List<Object>> cache = new ConcurrentHashMap<>();
public List<Object> getCachedValues(String key) {
return cache.getOrDefault(key, Collections.emptyList());
}
public void addToCache(String key, Object value) {
cache.computeIfAbsent(key, k -> new ArrayList<>()).add(value);
}
}
Использование пустых коллекций вместо null делает код более устойчивым и предсказуемым. Это особенно важно в сложных многопоточных приложениях или системах с большим количеством взаимосвязанных компонентов.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤1
Многие воспринимают
try-with-resources как просто удобную замену finally. Но под капотом есть важная деталь, о которой часто забывают - подавленные исключения (suppressed exceptions).📦 Классический код
try {
InputStream is = new FileInputStream("file.txt");
// работа с потоком
} finally {
is.close();
}
❗ Проблема: если в
try и в close() произойдут исключения - одно из них потеряется.✅ try-with-resources
try (InputStream is = new FileInputStream("file.txt")) {
// работа с потоком
}
👉 Java сама закроет ресурс и корректно обработает исключения
🔥 Вот где магия
try (MyResource r = new MyResource()) {
throw new RuntimeException("Ошибка в try");
}
И допустим,
close() тоже кидает исключение:
@Override
public void close() {
throw new RuntimeException("Ошибка при закрытии");
}
🤯 Что произойдёт?
* Основное исключение:
"Ошибка в try"* Исключение из
close() НЕ потеряется* Оно попадёт в suppressed exceptions
📌 Как их получить
try (MyResource r = new MyResource()) {
...
} catch (Exception e) {
for (Throwable t : e.getSuppressed()) {
t.printStackTrace();
}
}
⚠️ Почему это важно
Если не знаешь про suppressed exceptions:
* можно потерять важную информацию об ошибках
* сложнее дебажить ресурсы (файлы, сокеты, DB)
🧠 Кастомные ресурсы
Чтобы использовать
try-with-resources, класс должен реализовывать AutoCloseable:
class MyResource implements AutoCloseable {
@Override
public void close() {
// cleanup
}
}
👉 Даже свои классы можно встроить в этот механизм
🚀 Маленький лайфхак (Java 9+)
Можно объявить ресурс заранее:
InputStream is = new FileInputStream("file.txt");
try (is) {
// используем
}
📌 Вывод
try-with-resources это не только удобство, а ещё и правильная модель обработки исключений, которую вручную реализовать сложно.Please open Telegram to view this post
VIEW IN TELEGRAM
❤2👍1
📌 Что такое
Ключевое слово
✔️ Основные особенности:
1️⃣ Обеспечивает чтение переменной из основной памяти, а не из кэша потока.
2️⃣ Гарантирует видимость изменений между потоками.
Пример:
💡 Ограничение:
#java #volatile #multithreading
volatile и как оно работает?Ключевое слово
volatile в Java используется для переменных, к которым обращаются несколько потоков. Оно гарантирует, что изменения переменной одним потоком будут видны другим.1️⃣ Обеспечивает чтение переменной из основной памяти, а не из кэша потока.
2️⃣ Гарантирует видимость изменений между потоками.
Пример:
class SharedObject {
volatile int count = 0;
}volatile не гарантирует атомарность операций. Для этого используйте synchronized или классы из java.util.concurrent.#java #volatile #multithreading
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤2
Метод
deepToString из класса Arrays используется для создания строкового представления многомерных массивов (например, массивов массивов). Он обходит каждый уровень вложенности массива и выводит его элементы в виде строки. Это удобно для работы с многомерными массивами, так как стандартный метод toString не раскрывает их структуру.Пример использования:
int[][] array = {{1, 2, 3}, {4, 5, 6}};
System.out.println(Arrays.deepToString(array));
// [[1, 2, 3], [4, 5, 6]]
Этот метод работает рекурсивно, обеспечивая полное отображение структуры массива любой вложенности.
#java #Arrays #deepToString
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤2
StringBuilder и StringBufferИ
StringBuilder, и StringBuffer используются для работы со строками, но между ними есть важные отличия.✔️ StringBuilder быстрее, но не потокобезопасен.
✔️ StringBuffer потокобезопасен, но медленнее из-за синхронизации.
StringBuilder:StringBuilder sb = new StringBuilder("Hello");
sb.append(" World");
System.out.println(sb); // Hello WorldStringBuffer:StringBuffer sb = new StringBuffer("Hello");
sb.append(" World");
System.out.println(sb); // Hello WorldStringBuilder для лучшей производительности.#java #stringbuilder #stringbuffer
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3👍1🆒1
✔️ В Java класс может одновременно реализовать несколько интерфейсов, но наследоваться только от одного класса.
✔️ Абстрактные классы используются только тогда, когда присутствует тип отношений «is a» (является). Интерфейсы могут реализоваться классами, которые не связаны друг с другом.
✔️ Абстрактный класс - средство, позволяющее избежать написания повторяющегося кода, инструмент для частичной реализации поведения. Интерфейс - это средство выражения семантики класса, контракт, описывающий возможности. Все методы интерфейса неявно объявляются как
public abstract или (начиная с Java 8) default - методами с реализацией по-умолчанию, а поля - public static final.✔️ Интерфейсы позволяют создавать структуры типов без иерархии.
✔️ Наследуясь от абстрактного, класс «растворяет» собственную индивидуальность. Реализуя интерфейс, он расширяет собственную функциональность.
Абстрактные классы содержат частичную реализацию, которая дополняется или расширяется в подклассах. При этом все подклассы схожи между собой в части реализации, унаследованной от абстрактного класса, и отличаются лишь в части собственной реализации абстрактных методов родителя. Поэтому абстрактные классы применяются в случае построения иерархии однотипных, очень похожих друг на друга классов. В этом случае наследование от абстрактного класса, реализующего поведение объекта по умолчанию может быть полезно, так как позволяет избежать написания повторяющегося кода. Во всех остальных случаях лучше использовать интерфейсы.
#java #interface #abstract
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2👍1🥴1