Java for Beginner
674 subscribers
554 photos
156 videos
12 files
845 links
Канал от новичков для новичков!
Изучайте Java вместе с нами!
Здесь мы обмениваемся опытом и постоянно изучаем что-то новое!

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

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
Collectors в Java

Collectors.joining

Collectors.joining – это специализированный коллектор для конкатенации строковых представлений элементов потока в единую строку. Это мощный инструмент для работы с текстовыми данными в Java Stream API.

1. Базовая форма: joining()

Конкатенирует элементы без разделителей.

Сигнатура:
public static Collector<CharSequence, ?, String> joining()


Пример:
List<String> words = List.of("Java", "Stream", "API");
String result = words.stream().collect(Collectors.joining());

// Результат: "JavaStreamAPI"


Особенности:
Работает только с CharSequence (String, StringBuilder и др.)
Если поток пуст, возвращает пустую строку ""


2. С разделителем: joining(delimiter)

Добавляет указанный разделитель между элементами.

Сигнатура:
public static Collector<CharSequence, ?, String> joining(CharSequence delimiter)


Пример:
String result = words.stream().collect(Collectors.joining(", "));

// Результат: "Java, Stream, API"


Применение:
CSV-форматирование
Построение SQL-запросов
Логирование коллекций


3. Полная форма: joining(delimiter, prefix, suffix)

Добавляет префикс и суффикс к результату.

Сигнатура:
public static Collector<CharSequence, ?, String> joining(
CharSequence delimiter,
CharSequence prefix,
CharSequence suffix
)


Пример:
String result = words.stream()
.collect(Collectors.joining(", ", "[", "]"));

// Результат: "[Java, Stream, API]"


Типичные сценарии:
JSON-массивы: joining(", ", "[", "]")
SQL IN-условия:
joining("', '", "'", "'") → 'Java', 'Stream', 'API'
Форматированные списки


4. Внутренняя реализация

Коллектор использует StringJoiner внутри:
StringJoiner joiner = new StringJoiner(delimiter, prefix, suffix);
stream.forEach(element -> joiner.add(element.toString()));
return joiner.toString();


Особенности работы:
Для пустого потока возвращает prefix + suffix (например, "[]")
Оптимизирован для String (избегает лишних преобразований)
В параллельных стримах работает корректно (слияние через StringJoiner.merge)


5. Работа с не-строковыми объектами

Если элементы не являются строками, нужно преобразовать их явно:
List<Integer> numbers = List.of(1, 2, 3);
String result = numbers.stream()
.map(Object::toString)
.collect(Collectors.joining("-"));

// Результат: "1-2-3"


Альтернатива через Collectors.mapping:
String result = numbers.stream()
.collect(Collectors.mapping(
Object::toString,
Collectors.joining("/")
));


6. Ограничения и нюансы

Null-элементы:

Вызывают NullPointerException

Решение – фильтрация:

.filter(Objects::nonNull)


Большие объемы данных:
Для гигантских потоков лучше использовать StringBuilder напрямую

Локализация:
Нет встроенной поддержки (для чисел/дат используйте NumberFormat перед joining)

7. Комбинирование с другими коллекторами

Группировка с объединением:

Map<String, String> joinedByCategory = products.stream()
.collect(Collectors.groupingBy(
Product::getCategory,
Collectors.mapping(
Product::getName,
Collectors.joining(", ")
)
));


Результат:
{
"Electronics": "Laptop, Phone",
"Office": "Pen, Paper"
}


Многоуровневое объединение:
String complex = persons.stream()
.collect(Collectors.mapping(
p -> p.name() + " (" + p.age() + ")",
Collectors.joining("; ", "Persons: ", ".")
));

// Результат: "Persons: Alice (25); Bob (30)."


8. Альтернативы

StringBuilder (для сложных сценариев):
StringBuilder sb = new StringBuilder();
list.forEach(sb::append);


String.join() (только для List<String>):
String.join(", ", words);


TextBlocks (Java 15+ для многострочных данных):
String sql = """
SELECT %s
FROM table
WHERE id IN (%s)
""".formatted(
columns.stream().collect(joining(", ")),
ids.stream().map(Object::toString).collect(joining(", "))
);


#Java #Training #Medium #Collectors #joining