Google Guava之Joiner

简介: 日常开发中,我们经常需要将几个字符串,或者字符串数组、列表之类的数据,拼接成一个以指定符号分隔各个元素的字符串,比如把[1, 2, 3]拼接成"1-2-3",如果自己实现的话,基本上就需要编写循环去实现这个功能,代码就变得晦涩起来。

前言

iShot2022-12-06 02.24.29.png
日常开发中,我们经常需要将几个字符串,或者字符串数组、列表之类的数据,拼接成一个以指定符号分隔各个元素的字符串,比如把[1, 2, 3]拼接成"1-2-3",如果自己实现的话,基本上就需要编写循环去实现这个功能,代码就变得晦涩起来。

Joiner

Google Guava提供了一套优雅的API,让我们能够轻而易举的完成字符串拼接。你可以借助Guava的Joiner 类,让代码优雅起来。

skipNulls

它会过滤掉空的参数,其中也包括数组中的null值。

    public static void main(String[] args) throws Exception {

        List<String> strs = Lists.newArrayList("1", "2", null, "3");

        // 当有存在对象数组Object里面的元素不会被拼接到字符串中,而是以地址的形式拼接。
        String joinStr = Joiner.on("-").skipNulls().join(strs);

        System.out.println(joinStr);
    }

注:如果不指定skipNulls, 当要处理的元素中有null值时会抛出空指针异常。

useForNull

它会将设置的参数替换空的数据,其中也包括数组中的null值。

    public static void main(String[] args) throws Exception {

        List<String> strs = Lists.newArrayList("1", "2", null, "3");

        String joinStr = Joiner.on("-").useForNull("0").join(strs);

        // 1-2-0-3
        System.out.println(joinStr);
    }

注:如果不指定skipNulls, 当要处理的元素中有null值时会抛出空指针异常。

MapJoiner

MapJoiner是Joiner的内部类,它没有静态的方法,它执行操作与Joiner相同,但是它主要是针对的Map的KV。

public static void main(String[] args) throws Exception {

    Map<String, String> user = new HashMap<String, String>() {
        private static final long serialVersionUID = 6396999608476245809L;
        {
            put("name", "小明");
            put("age", "22");
        }
    };

    final String join = Joiner.on("&").withKeyValueSeparator("=").join(user);
    // name=小明&age=22
    System.out.println(join);

}
它底层就是用了MapJoiner
  /**
   * Returns a {@code MapJoiner} using the given key-value separator, and the same configuration as
   * this {@code Joiner} otherwise.
   */
  @CheckReturnValue
  public MapJoiner withKeyValueSeparator(String keyValueSeparator) {
    return new MapJoiner(this, keyValueSeparator);
  }

ps:聪明的同学已经可以看出来上面的这种处理方式在拼接url极度舒服了。

Splitter(详见下一篇)

它与Joiner操作相反的类,它是根据给定的分隔符,把一个字符串分隔成若个子字符串。

public static void main(String[] args) throws Exception {

        List<String> ints = Splitter.on("|").splitToList("1|2|3");

        // [1, 2, 3]
        System.out.println(ints);
}

MapSplitter

MapSplitter是Splitter的内部类,它没有静态的方法,它执行操作与Splitter相同,但是它主要是针对的Map的KV。

public static void main(String[] args) throws IOException {

        Map<String, String> params = Splitter.on("&")
            .withKeyValueSeparator("=").split("name=小明&age=22");
    
        // {name=小明, age=22}
        System.out.println(params);
    }

可同样的适用于解析url参数的场景。

小结

需要注意的是Joiner的构造方法被设置成了私有,所以你需要通过静态的on函数初始化,它也不能二次创建的,如下:

// 此下代码会导致空指针异常
public static void main(String[] args) throws IOException {
        Joiner joiner = Joiner.on('-');
        joiner.skipNulls(); // 此行代码没有生效的
        String joinStr = joiner.join("1", null, "2", "3");
        System.out.println(joinStr);
}
这是为什么呢?分步调用joiner的静态函数为什么是不起作用的?

这是因为Joiner创建后就是不可更改的了,所以为了实现useForNull和skipNulls等语义,在底层会再次创建一个匿名内部类,并覆盖相应的方法,如下:

  /**
   * Returns a joiner with the same behavior as this joiner, except automatically skipping over any
   * provided null elements.
   */
  @CheckReturnValue
  public Joiner skipNulls() {
    return new Joiner(this) {
      @Override
      public <A extends Appendable> A appendTo(A appendable, Iterator<?> parts) throws IOException {
        checkNotNull(appendable, "appendable");
        checkNotNull(parts, "parts");
        while (parts.hasNext()) {
          Object part = parts.next();
          if (part != null) {
            appendable.append(Joiner.this.toString(part));
            break;
          }
        }
        while (parts.hasNext()) {
          Object part = parts.next();
          if (part != null) {
            appendable.append(separator);
            appendable.append(Joiner.this.toString(part));
          }
        }
        return appendable;
      }

      @Override
      public Joiner useForNull(String nullText) {
        // 为了防止重复调用,一旦调用就抛异常,重复调用没有意义。
        throw new UnsupportedOperationException("already specified skipNulls");
      }

      @Override
      public MapJoiner withKeyValueSeparator(String kvs) {
        throw new UnsupportedOperationException("can't use .skipNulls() with maps");
      }
    };
  }
所以,你如果非想要分步骤处理,那只是如下这样:
 public static void main(String[] args) throws IOException {
        Joiner joinerTemp = Joiner.on('-');
        Joiner joiner = joinerTemp.skipNulls();
        String joinStr = joiner.join("1", null, "2", "3");
        // 1-2-3
        System.out.println(joinStr);
}
目录
相关文章
|
存储 缓存 算法
Google Guava之RateLimiter
在日常开发中,限流是高并发系统的三把守护利器之一,它的另外两个好兄弟缓存、降级下次再说。而限流在绝大多数场景中用来限制并发和请求量,像秒杀之类的高流量业务的场景,都能见到它的身影,所以它就是保护系统和下游的业务系统不被流量冲垮的利器。
325 6
Google Guava之RateLimiter
|
4月前
Google Guava ListeningExecutorService
Google Guava ListeningExecutorService
28 0
|
6月前
|
Java 数据库连接
提升编程效率的利器: 解析Google Guava库之IO工具类(九)
提升编程效率的利器: 解析Google Guava库之IO工具类(九)
|
6月前
|
缓存 Java Maven
深入解析Google Guava库与Spring Retry重试框架
深入解析Google Guava库与Spring Retry重试框架
|
6月前
|
监控 安全 算法
提升编程效率的利器: 解析Google Guava库之RateLimiter优雅限流(十)
提升编程效率的利器: 解析Google Guava库之RateLimiter优雅限流(十)
|
6月前
|
缓存 安全 Java
提升编程效率的利器: 解析Google Guava库之集合工具类-50个示例(八)
提升编程效率的利器: 解析Google Guava库之集合工具类-50个示例(八)
|
6月前
|
缓存 算法 Java
提升编程效率的利器: 解析Google Guava库之常用工具类-40个示例(七)
提升编程效率的利器: 解析Google Guava库之常用工具类-40个示例(七)
|
6月前
|
存储
提升编程效率的利器: 解析Google Guava库之集合篇RangeMap范围映射(六)
提升编程效率的利器: 解析Google Guava库之集合篇RangeMap范围映射(六)
提升编程效率的利器: 解析Google Guava库之集合篇RangeSet范围集合(五)
提升编程效率的利器: 解析Google Guava库之集合篇RangeSet范围集合(五)
|
6月前
|
存储 安全 Java
提升编程效率的利器: 解析Google Guava库之集合篇Table二维映射(四)
提升编程效率的利器: 解析Google Guava库之集合篇Table二维映射(四)