你还不会使用Guava处理字符串? 那你还不进来学习?

Posted c.

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了你还不会使用Guava处理字符串? 那你还不进来学习?相关的知识,希望对你有一定的参考价值。

你还不会使用Guava处理字符串? 那你还不进来学习?

连接器[Joiner]

用分隔符把字符串序列连接起来也可能会遇上不必要的麻烦。如果字符串序列中含有null,那连接操作会更难。但是连接器Joiner让我们连接字符串变得更加简单

比如我们现在一个字符串的集合,然后我们需要用‘#’来把这个集合中的数据连接起来,用Joiner怎么做呢?

public class JoinerTest {

    private final List<String> stringList = Arrays.asList("Google", "Guava", "Java", "Scala", "Kafka");

    @Test
    public void testJoinOnJoin() {
        String result = Joiner.on("#").join(stringList);
        Assertions.assertEquals("Google#Guava#Java#Scala#Kafka", result);
    }
}

通过Joiner.on("#").join(stringList);就可以把一个集合通过某个连接符来连接成字符串

那如果现在我们的集合中包含null,该如何处理,正常我们写程序可能会没考虑到这种空指针的问题。

public class JoinerTest {

    private final List<String> stringListWithNullValue = Arrays.asList("Google", "Guava", "Java", "Scala", null);
    
    @Test
    public void testJoinOnJoinWithNullValue() {
        assertThrows(NullPointerException.class, () -> {
            String result = Joiner.on("#").join(stringListWithNullValue);
        });
    }
}

比如如果用Joiner.on("#").join(stringListWithNullValue),对于集合中有null的情况是会报空指针异常的,那种情况我们要怎么处理?

我们可以通过skipNulls()来过滤掉集合中的null元素。

public class JoinerTest {

    private final List<String> stringListWithNullValue = Arrays.asList("Google", "Guava", "Java", "Scala", null);

    @Test
    public void testJoinOnJoinWithNullValueButSkip() {
        String result = Joiner.on("#").skipNulls().join(stringListWithNullValue);
        Assertions.assertEquals("Google#Guava#Java#Scala", result);
    }

}

而且通过这种Fluent风格的Joiner让连接字符串更简单。

那再比如说,我们有个要求是当集合元素有null元素的时候,我们需要用默认值去代替,该怎么做呢?

package org.example.joiner;

import com.google.common.base.Joiner;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertThrows;

public class JoinerTest {

    private final List<String> stringListWithNullValue = Arrays.asList("Google", "Guava", "Java", "Scala", null);

    @Test
    public void testJoin_On_Join_WithNullValue_UseDefaultValue() {
        String result = Joiner.on("#").useForNull("DEFAULT").join(stringListWithNullValue);
        Assertions.assertEquals("Google#Guava#Java#Scala#DEFAULT", result);
    }
}

我们可以使用useForNull("默认代替的字符串")来完成连接。

  public class Joiner {
  
    public static Joiner on(String separator) {
        return new Joiner(separator);
    }

    public static Joiner on(char separator) {
        return new Joiner(String.valueOf(separator));
    }
  }

Joiner的on方法总会返回一个新的joiner实例。这使得joiner实例都是线程安全的

使用的方式还有很多,还可以把集合连接后返回一个StringBuilder对象

@Test
    public void testJoin_On_Append_To_StringBuilder() {
        final StringBuilder builder = new StringBuilder();
        StringBuilder resultBuilder = Joiner.on("#").useForNull("DEFAULT").appendTo(builder, stringListWithNullValue);
        assertSame(resultBuilder,builder);//传入的对象和返回出来的对象是同一个对象
        assertEquals("Google#Guava#Java#Scala#DEFAULT",resultBuilder.toString());
        assertEquals("Google#Guava#Java#Scala#DEFAULT",builder.toString());
    }

当然还可以把集合连接后写入一个文件流中

 @Test
    public void testJoin_On_Append_To_Writer() {
        final String targetFileName = "guava-joiner.txt";
        try (FileWriter writer = new FileWriter(new File(targetFileName))) {
            Joiner.on("#").useForNull("DEFAULT").appendTo(writer, stringListWithNullValue);
            assertTrue(Files.isFile().test(new File(targetFileName)));
        } catch (IOException e) {
            fail("append to the writer occur fetal error.");
        }
    }

题外话题,现在我们考虑一下,如果不用Guava的Joiner我们平时该怎么处理这种字符串的连接呢?其实利用java8也是可以很快实现的,只是没有Guava这么简单便捷。

public class JoinerTest {

    private final List<String> stringListWithNullValue = Arrays.asList("Google", "Guava", "Java", "Scala", null);


    @Test
    public void testJoiningByStreamWithDefaultValue() {
        String result = stringListWithNullValue.stream().map(this::defaultValue).collect(joining("#"));
        assertEquals("Google#Guava#Java#Scala#DEFAULT", result);
    }

    private String defaultValue(final String item) {
        return item == null || item.isEmpty() ? "DEFAULT" : item;
    }
}

还有对于map这种key,value形式,Guava的Joiner可以用withKeyValueSeparator方法进行连接。

@Test
    public void testJoinOnWithMap() {
        final Map<String, String> stringMap = of("Hello", "Guava", "Java", "Scala");
        assertEquals("Hello=Guava#Java=Scala", Joiner.on('#').withKeyValueSeparator("=").join(stringMap));
    }

拆分器[Splitter]

JDK内建的字符串拆分工具有一些古怪的特性。比如,String.split悄悄丢弃了尾部的分隔符。 问题:”,a, ,b,”.split(“,”)返回什么呢?

package org.example.splitter;

import org.junit.jupiter.api.Test;

import java.util.Arrays;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class SplitterTest {
    @Test
    public void test_string_split() {
        String str = ",a, ,b,";
        String[] split = str.split(",");
        assertEquals(4, split.length);
        assertEquals("[, a,  , b]", Arrays.toString(split));
    }

}

所以这不是我们期望的结果,我们期望的结果只是需要拿到a和b两个字符,那如果通过Guava的Splitter,我们就可以很容易的做到。

 @Test
    public void testSplitOnSplit() {
        List<String> result = Splitter.on(",").omitEmptyStrings().trimResults().splitToList(",a, ,b,");
        assertEquals(2,result.size());
        assertEquals("a",result.get(0));
        assertEquals("b",result.get(1));
    }

看到了吧,这就是Splitter的厉害之处。再继续看多几个例子

 	@Test
    public void testSplit_On_Split_OmitEmpty() {
        List<String> result = Splitter.on("|").splitToList("hello|world|||");
        assertNotNull(result);
        assertEquals(5, result.size());
        //过滤掉split之后的空字符串
        result = Splitter.on("|").omitEmptyStrings().splitToList("hello|world|||");
        assertNotNull(result);
        assertEquals(2, result.size());
    }

    @Test
    public void testSplit_On_Split_OmitEmpty_TrimResult() {
        List<String> result = Splitter.on("|").omitEmptyStrings().splitToList("hello | world|||");
        assertNotNull(result);
        assertEquals(2, result.size());
        assertEquals("hello ", result.get(0));
        assertEquals(" world", result.get(1));

        //过滤掉split之后的空字符串并把结果进行trim操作
        result = Splitter.on("|").trimResults().omitEmptyStrings().splitToList("hello | world|||");
        assertEquals("hello", result.get(0));
        assertEquals("world", result.get(1));
    }

	@Test
    public void testSplitFixLength() {
        //还可以按照长度进行分割
        List<String> result = Splitter.fixedLength(4).splitToList("aaaabbbbccccdddd");
        assertNotNull(result);
        assertEquals(4, result.size());
        assertEquals("aaaa", result.get(0));
        assertEquals("bbbb", result.get(1));
        assertEquals("cccc", result.get(2));
        assertEquals("dddd", result.get(3));
    }

	@Test
    public void testSplitOnSplitLimit() {
        //限制分割后的结果集个数
        List<String> result = Splitter.on("#").limit(3).splitToList("hello#world#java#google#scala");
        assertNotNull(result);
        assertEquals(3, result.size());
        assertEquals("hello", result.get(0));
        assertEquals("world", result.get(1));
        assertEquals("java#google#scala", result.get(2));
    }

	@Test
    public void testSplitOnSplitLimit() {
        //限制分割后的结果集个数
        List<String> result = Splitter.on("#").limit(3).splitToList("hello#world#java#google#scala");
        assertNotNull(result);
        assertEquals(3, result.size());
        assertEquals("hello", result.get(0));
        assertEquals("world", result.get(1));
        assertEquals("java#google#scala", result.get(2));
    }



    @Test
    public void testSplitOnPatternString() {
        //还可以按照正则表达式分割
        List<String> result = Splitter.onPattern("\\\\|").trimResults().omitEmptyStrings().splitToList("hello | world|||");
        assertNotNull(result);
        assertEquals(2,result.size());
        assertEquals("hello",result.get(0));
        assertEquals("world",result.get(1));
    }

    @Test
    public void testSplitOnPattern() {
        List<String> result = Splitter.on(Pattern.compile("\\\\|")).trimResults().omitEmptyStrings().splitToList("hello | world|||");
        assertNotNull(result);
        assertEquals(2,result.size());
        assertEquals("hello",result.get(0));
        assertEquals("world",result.get(1));
    }


    @Test
    public void testSplitOnSplitToMap() {
        Map<String, String> result = Splitter.on(Pattern.compile("\\\\|")).trimResults()
                .omitEmptyStrings().withKeyValueSeparator("=").split("hello=HELLO| world=WORLD|||");
        assertNotNull(result);
        assertEquals(2,result.size());
        assertEquals("HELLO",result.get("hello"));
        assertEquals("WORLD",result.如果你还不知道如何控制springboot中bean的加载顺序,那你一定要看此篇

面试官:淦!0202年你还不知道面向对象?

当面试中问到关于多线程安全问题时,你还不知道怎么回答嘛?快点进来,我带你多维度深层次来解决这个问题

DDD ,人都学习了,你还不赶紧抓紧学

DDD ,人都学习了,你还不赶紧抓紧学

还在苦恼学python不知道方向,你还不看吗?未来python就业方向