Перейти к основному содержимому

Строковые операции с потоками Java

· 4 мин. чтения

Задача: Наибольшая подстрока без повторений

Для заданной строки s, найдите длину наибольшей подстроки без повторяющихся символов. Подстрока — это непрерывная непустая последовательность символов внутри строки...

ANDROMEDA 42

1. Обзор

Java 8 представила новый Stream API, который позволяет нам обрабатывать данные декларативным образом.

В этой быстрой статье мы узнаем, как использовать Stream API для разбиения строки с разделителями-запятыми на список строк и как объединить массив строк в строку с разделителями-запятыми .

Мы также рассмотрим, как преобразовать массив строк в карту с помощью Stream API.

Почти все время мы сталкиваемся с ситуациями, когда нам нужно выполнить итерацию некоторых коллекций Java и отфильтровать коллекцию на основе некоторой логики фильтрации. При традиционном подходе к такого рода ситуациям мы использовали бы множество циклов и операций if-else, чтобы получить желаемый результат.

Если вы хотите узнать больше о Stream API, прочтите эту статью .

2. Соединение строк с помощью Stream API

Давайте воспользуемся Stream API для создания функции, которая объединит массив String в String с разделителями-запятыми :

public static String join(String[] arrayOfString){
return Arrays.asList(arrayOfString)
.stream()
//.map(...)
.collect(Collectors.joining(","));
}

Здесь следует отметить:

  • Функция stream() преобразует любую коллекцию в поток данных.
  • Функция map() используется для обработки данных
  • Существует также еще одна функция с именем filter() , в которую мы можем включить критерии фильтрации.

Могут быть сценарии, в которых мы можем захотеть присоединиться к строке с некоторым фиксированным префиксом и постфиксом. С помощью Stream API мы можем сделать это следующим образом:

public static String joinWithPrefixPostfix(String[] arrayOfString){
return Arrays.asList(arrayOfString)
.stream()
//.map(...)
.collect(Collectors.joining(",","[","]"));
}

Как видно из метода Collectors.joining() , мы объявляем наш префикс как '[', а постфикс как ']' ; следовательно, сгенерированная строка будет создана с объявленным форматом […..] .

3. Разделение строк с помощью Stream API

Теперь давайте создадим функцию, которая разделит строку , разделенную запятыми , на список строк , используя Stream API:

public static List<String> split(String str){
return Stream.of(str.split(","))
.map (elem -> new String(elem))
.collect(Collectors.toList());
}

Также можно напрямую преобразовать строку в список символов с помощью Stream API:

public static List<Character> splitToListOfChar(String str) {
return str.chars()
.mapToObj(item -> (char) item)
.collect(Collectors.toList());
}

Здесь следует отметить один интересный факт: метод chars() преобразует строку в поток целых чисел , где каждое целочисленное значение обозначает значение ASCII каждой последовательности символов . Вот почему нам нужно явно привести тип объекта сопоставления в методе mapToObj() .

4. Массив строк для сопоставления с Stream API

Мы также можем преобразовать массив String в карту, используя split и Collectors.toMap , при условии, что каждый элемент в массиве содержит сущность ключ-значение, объединенную разделителем:

public static Map<String, String> arrayToMap(String[] arrayOfString) {
return Arrays.asList(arrayOfString)
.stream()
.map(str -> str.split(":"))
.collect(toMap(str -> str[0], str -> str[1]));
}

Здесь «:» — это разделитель значений ключа для всех элементов массива String.

Помните, что во избежание ошибок компиляции нам необходимо убедиться, что код компилируется с использованием Java 1.8 . Для этого нам нужно добавить следующий плагин в pom.xml :

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>

5. Тестирование

Поскольку мы закончили создание функций, давайте создадим тестовые примеры, чтобы проверить результат.

Во-первых, давайте протестируем наш простой метод соединения:

@Test
public void givenArray_transformedToStream_convertToString() {
String[] programmingLanguages = {"java", "python", "nodejs", "ruby"};
String expectation = "java,python,nodejs,ruby";

String result = JoinerSplitter.join(programmingLanguages);
assertEquals(result, expectation);
}

Затем давайте создадим еще один, чтобы проверить нашу простую функциональность разделения:

@Test
public void givenString_transformedToStream_convertToList() {
String programmingLanguages = "java,python,nodejs,ruby";

List<String> expectation = new ArrayList<>();
expectation.add("java");
expectation.add("python");
expectation.add("nodejs");
expectation.add("ruby");

List<String> result = JoinerSplitter.split(programmingLanguages);

assertEquals(result, expectation);
}

Наконец, давайте проверим наш массив String для отображения функциональности:

@Test
public void givenStringArray_transformedToStream_convertToMap() {

String[] programming_languages = new String[] {"language:java","os:linux","editor:emacs"};

Map<String,String> expectation=new HashMap<>();
expectation.put("language", "java");
expectation.put("os", "linux");
expectation.put("editor", "emacs");

Map<String, String> result = JoinerSplitter.arrayToMap(programming_languages);
assertEquals(result, expectation);

}

Точно так же нам нужно создать остальные тестовые случаи.

6. Заключение

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

Как всегда, полный исходный код доступен на Github .