zoukankan      html  css  js  c++  java
  • StringJoiner使用详解

    StringJoiner是java.util包下的一个工具类,jdk1.8出来的

    作用是在构造字符串时,可以自动添加前缀、后缀及分隔符,而不需要自己去实现这些添加字符的逻辑

    先看一个简单的demo

    StringJoiner sj1 = new StringJoiner(",");
    StringJoiner sj2 = new StringJoiner(",", "[", "]");
    
    System.out.println(sj1.add("a").add("b").add("c"));
    System.out.println(sj2.add("a").add("b").add("c"));
    System.out.println(sj1.merge(sj2));
    System.out.println(sj2.merge(sj1));
    System.out.println(sj1.length());
    

    image-20200208234335412

    StringJoiner有两个构造方法

    1. 只传入分隔符

      public StringJoiner(CharSequence delimiter) {
          // 这里只是调用了第二个构造方法,前缀和后缀传入空字符串,表示没有前后缀
          this(delimiter, "", "");
      }
      
    2. 传入分隔符,还有前缀和后缀

      public StringJoiner(CharSequence delimiter,
                          CharSequence prefix,
                          CharSequence suffix) {
          // 做了以下判断,如果分隔符,前后缀为null,则抛出NullPointerException异常
          Objects.requireNonNull(prefix, "The prefix must not be null");
          Objects.requireNonNull(delimiter, "The delimiter must not be null");
          Objects.requireNonNull(suffix, "The suffix must not be null");
          
      	// 赋值给当前对象的属性
          this.prefix = prefix.toString();
          this.delimiter = delimiter.toString();
          this.suffix = suffix.toString();
          this.emptyValue = this.prefix + this.suffix;
      }
      

    成员属性,其实StringJoiner主要是通过维护了一个StringBuilder对象value去添加元素的

    // 当前StringJoiner对象前缀
    private final String prefix;
    // 每个添加元素的分隔符
    private final String delimiter;
    // 当前StringJoiner对象后缀
    private final String suffix;
    // 前缀+元素+分隔符+后缀的值,如果没有添加元素,那么value是null
    private StringBuilder value;
    // 前缀+后缀的值,如果没有前后缀,那么这个值为空字符串,可以理解为value的副本,在value为null时,用它来代替
    private String emptyValue;
    

    方法描述及源码分析

    • public StringJoiner add(CharSequence newElement):添加一个元素,初始化value的工作也是在这里做的,如果当前StringJoiner没有调用过一次add方法,那么value为null

      public StringJoiner add(CharSequence newElement) {
          // 在此调用prepareBuilder方法,prepareBuilder会自动判断value是否已经初始化,并添加好分隔符
          prepareBuilder().append(newElement);
          return this;
      }
      
    • private StringBuilder prepareBuilder():在调用add方法时会自动调用,判断value是否为null,如果不为null,直接添加分隔符。如果为null,构造一个StringBuilder对象,初始值为prefix。

      private StringBuilder prepareBuilder() {
          // 如果不为null,在添加元素前添加分隔符
          if (value != null) {
              value.append(delimiter);
          } else {
              // 反之,构建StringBuilder对象,初始值为prefix
              value = new StringBuilder().append(prefix);
          }
          return value;
      }
      
    • public StringJoiner merge(StringJoiner other):合并一个StringJoiner对象到当前StringJoiner对象

      public StringJoiner merge(StringJoiner other) {
          Objects.requireNonNull(other);
          if (other.value != null) {
              final int length = other.value.length();
              StringBuilder builder = prepareBuilder();
             	// 将传过来的StringJoiner对象拼接到末尾
              builder.append(other.value, other.prefix.length(), length);
          }
          return this;
      }
      
    • public int length():如果value不为null,当前值=value的长度+suffix的长度,如果为null,返回emptyValue的长度

      public int length() {
          // 如果value为null,返回emptyValue的长度,反之返回value的长度
          return (value != null ? value.length() + suffix.length() :
                  emptyValue.length());
      }
      
    • public String toString():如果value不为null,返回value+suffix的值,如果为null,返回emptyValue

      @Override
      public String toString() {
          // value为null用emptyValue来代替
          if (value == null) {
              return emptyValue;
          } else {
              // 没有后缀直接返回value字符串
              if (suffix.equals("")) {
                  return value.toString();
              } else {
                  // 有后缀需要在toString里面再补上,把当前对象作为字符串使用时,toString方法会自动调用
                  int initialLength = value.length();
                  String result = value.append(suffix).toString();
                  // reset value to pre-append initialLength
                  value.setLength(initialLength);
                  return result;
              }
          }
      }
      

    如果是想将一个list中的元素快速的以这种方式添加,可以通过String.join来实现

    // 第一个参数是分隔符,第二个参数是list
    System.out.println(String.join(",", Arrays.asList("a", "b", "c")));
    // 第二个参数是可变数组
    System.out.println(String.join(",", "a", "b", "c"));
    

    image-20200209083456237

    String.join方法也是jdk1.8出来的

    查看String.join的源码可以看见,里面其实就是构建了一个StringJoiner对象,它只指定了分隔符,所以String.join不能实现有前后缀的情况

    public static String join(CharSequence delimiter,
            Iterable<? extends CharSequence> elements) {
    
        Objects.requireNonNull(delimiter);
        Objects.requireNonNull(elements);
        
        // 构建了一个指定分隔符的StringJoiner对象
        StringJoiner joiner = new StringJoiner(delimiter);
        // 循环添加list中的元素
        for (CharSequence cs: elements) {
            joiner.add(cs);
        }
        return joiner.toString();
    }
    

    如果想处理list添加前后缀的问题,可以通过list的stream流的collect方法来处理,需要配合Collectors.joining方法

    Collectors.joining(CharSequence delimiter);
    Collectors.joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix);
    

    将list通过stream方法转成流之后调用collect来返回想要的结果集

    List<String> list1 = Arrays.asList("a", "b", "c");
    List<String> list2 = Arrays.asList("a", "b", "c");
    
    System.out.println(list1.stream().collect(Collectors.joining(",")));
    System.out.println(list2.stream().collect(Collectors.joining(",", "[", "]")));
    

    image-20200209085226721

    查看Collectors.joining源码实现,发现其中也是维护了一个StringJoiner实例去做这些事

    public static Collector<CharSequence, ?, String> joining(CharSequence delimiter,
                                                             CharSequence prefix,
                                                             CharSequence suffix) {
        return new CollectorImpl<>(
                () -> new StringJoiner(delimiter, prefix, suffix),
                StringJoiner::add, StringJoiner::merge,
                StringJoiner::toString, CH_NOID);
    }
    
  • 相关阅读:
    pands数据框(DataFrame)02
    mysql 临时表
    【转】Mysql 多表连接查询的执行细节 (一)
    【转】cuckoo hash
    [转]全域哈希
    【转】 bloom filter
    【转】bitmap
    golang 反汇编代码阅读-- defer
    assignment3
    Lecture 12: Visualizing and Understanding
  • 原文地址:https://www.cnblogs.com/dagger9527/p/12285758.html
Copyright © 2011-2022 走看看