String Operations with Java Streams – 用Java流进行字符串操作

最后修改: 2017年 2月 15日

1. Overview

1.概述

Java 8 has introduced a new Stream API that lets us process data in a declarative manner.

Java 8引入了一个新的Stream API,使我们能够以声明的方式处理数据。

In this quick article, we would learn how to use the Stream API to split a comma-separated String into a list of Strings and how to join a String array into a comma-separated String.

在这篇快速文章中,我们将学习如何使用Stream API将一个逗号分隔的String分割成一个String列表,以及如何将一个String数组加入一个逗号分隔的String

We’ll also look at how to convert a string array to map using Stream API.

我们还将看看如何使用Stream API将字符串数组转换为地图。

Nearly all of the time we face situations, where we need to iterate some Java Collections and filter the Collection based on some filtering logic. In a traditional approach for this type of situation, we would use lots of loops and if-else operations to get the desired result.

几乎所有的时候,我们都会面临这样的情况:我们需要迭代一些Java集合,并根据一些过滤逻辑来过滤集合。在这种情况下的传统方法中,我们会使用大量的循环和if-else操作来获得期望的结果。

If you want to read more about the Stream API, check this article.

如果你想阅读更多关于Stream API的内容,请查看这篇文章

2. Joining Strings With the Stream API

2.用Stream API连接字符串

Let’s use the Stream API to create a function which would join a String array into a comma-separated String:

让我们使用Stream API来创建一个函数,将一个String数组连接成一个逗号分隔的String

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

Points to note here:

这里需要注意的几点。

  • The stream() function converts any Collection into a stream of data
  • map() function is used to process the data
  • There is also another function, named filter(), where we can include filtering criteria

There can be scenarios, where we may want to join a String with some fixed prefix and postfix. With the Stream API we can do that in the following way:

在某些情况下,我们可能想用一些固定的前缀和后缀来连接一个String。使用Stream API,我们可以通过以下方式实现。

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

As we can see in the Collectors.joining() method, we are declaring our prefix as ‘[‘ and postfix as ‘]’; hence the generated String will be created with declared […..] format.

正如我们在Collectors.join()方法中看到的,我们将前缀声明为‘[‘,后缀声明为‘]’;因此,生成的String将以声明的[…..]格式创建。

3. Splitting Strings With Stream API

3.用Stream API拆分字符串

Now, let’s create a function, which would split a comma separated String into a list of String using Stream API:

现在,让我们创建一个函数,使用Stream API将一个逗号分隔的字符串分割成字符串的列表。

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

It’s also possible to directly convert a String to a Character list using the Stream API:

也可以使用Stream API直接将字符串转换为字符列表。

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

One interesting fact to note here is that the chars() method converts the String into a stream of Integer where each Integer value denotes the ASCII value of each and every Char sequence. That’s why we need to explicitly typecast the mapper object in the mapToObj() method.

这里需要注意的一个有趣的事实是,chars()方法将String转换为Integer流,其中每个Integer值表示每个ASCII序列的Char值。这就是为什么我们需要在mapToObj()方法中明确地对映射器对象进行类型转换。

4. String Array to Map With Stream API

4.用Stream API将StringArray转为Map

We can also convert a String array to map using split and Collectors.toMap, provided each item in the array contains a key-value entity concatenated by a separator:

我们也可以使用splitCollectors.toMapString数组转换为map,前提是数组中的每项都包含一个由分隔符连接的键值实体。

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]));
}

Here, “:” is the key-value separator for all the elements in String array.

这里,“:”是String数组中所有元素的键值分隔符。

Please remember that in order to avoid compilation error, we need to ensure that code is compiled using Java 1.8. To do this, we need to add the following plugin in the pom.xml:

请记住,为了避免编译错误,我们需要确保代码是使用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. Testing

5.测试

Since we are done creating the functions, let’s create test cases to verify the outcome.

既然我们已经完成了函数的创建,让我们创建测试案例来验证结果。

First, let’s test our simple joining method:

首先,让我们测试一下我们的简单连接方法。

@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);
}

Next, let’s create another one to test our simple splitting functionality:

接下来,让我们再创建一个来测试我们的简单拆分功能。

@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);
}

Finally, let’s test our String array to map functionality:

最后,让我们测试一下我们的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);
    
}

In the same way, we need to create the rest of the test cases.

以同样的方式,我们需要创建其余的测试案例。

6. Conclusion

6.结论

Stream API provides us with sophisticated data processing techniques. This new way of writing code is very efficient in terms of heap memory management in a multi-threaded environment.

Stream API为我们提供了复杂的数据处理技术。这种新的代码编写方式在多线程环境下的堆内存管理方面非常有效。

Like always, the full source code is available over on Github.

像往常一样,完整的源代码可以在Github上找到