Guava源码解析四:Joiner源码解析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/dancheng1/article/details/84819034

将字符串数组按指定分隔符连接起来,或字符串串按指定索引开始使用指定分隔符连接起来

变量

//分割符
private final String separator;

构造方法

两个构造函数都是静态构造器,所以不能直接使用这两个构造器去创建Joiner,所以想要创建Joiner只能使用静态方法。

可接收字符串和字符,字符串可以为空,字符不可为空字符

private Joiner(String separator) {
    //对字符判空
    this.separator = (String)Preconditions.checkNotNull(separator);
}

private Joiner(Joiner prototype) {
    this.separator = prototype.separator;
}

静态创建Joiner方法

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

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

这两个方法一个传入字符串,一个传入字符,然后直接分别使用两个构造器构造

功能函数

这些功能函数都是非静态的需要在Joiner对象的调用下使用

join()方法

对于4个join方法实际可以分为两类,一类是join实现类,另一类是join解析参数类

解析参数类:

//因为 Iterable是所有集合类的顶级接口(除了Map系列),所以此参数为集合类或实现Iterable的类即可
public final String join(Iterable<?> parts) {
     //调用join实现类
     return this.join((Iterator)parts.iterator());
}

//传入数组
public final String join(Object[] parts) {
     //将数组转为ArrayList然后强转为Iterable  
     return this.join((Iterable)Arrays.asList(parts));
}

//传入两个参数和一个数组,最终这两个参数个数组一起构成一个新的数组
public final String join(@Nullable Object first, @Nullable Object second, Object... rest) {
     //使用iterable方法将参数和数组融合成一个数组
     return this.join((Iterable)iterable(first, second, rest));
}

由于join第三个实现方法需要 iterable方法对数组进行融合,所以看一下 iterable的实现方式:

private static Iterable<Object> iterable(final Object first, final Object second, final Object[] rest) {
    Preconditions.checkNotNull(rest);
    //返回一个AbstractList对象,并且这个对象重写了size和get方法
    return new AbstractList() {
        //使得当前容量比rest数组多2个
        public int size() {
        return rest.length + 2;
    }

    public Object get(int index) {
        switch(index) {
            case 0:
                return first;
            case 1:
                return second;
           default:
               return rest[index - 2];
        }
    }};  
}


 

join实现类

public final String join(Iterator<?> parts) {
     //实际使用appendTo(StringBuilder,Iterator)方法
     return this.appendTo((StringBuilder)(new StringBuilder()), (Iterator)parts).toString();
}

分析appendTo(StringBuilder, Iterator)的源码
public final StringBuilder appendTo(StringBuilder builder, Iterator<?> parts) {
     try {
         //调用了appendTo(A, Iterator)方法
         this.appendTo((Appendable)builder, (Iterator)parts);
         return builder;
     } catch (IOException var4) {
         throw new AssertionError(var4);
     }
}

继续分析<A extends Appendable> A appendTo(A, Interator)方法
public <A extends Appendable> A appendTo(A appendable, Iterator<?> parts) throws IOException {  
     Preconditions.checkNotNull(appendable);
     if(parts.hasNext()) {
         //如果第一个迭代器存在,将其添加到出传入的StringBuilder中
         appendable.append(this.toString(parts.next()));
         //从第二个迭代器开始就会循环方式就会发生变化,每个元素前都会添加规定的分隔符
         while(parts.hasNext()) {
             appendable.append(this.separator);
             appendable.append(this.toString(parts.next()));
         }
     }
     return appendable;
}

useForNull方法

将传入的字符串代替集合中的null输出

源码解析:

public Joiner useForNull(final String nullText) {
    Preconditions.checkNotNull(nullText);
    // 返回一个Joiner重写了toString方法,将null的参数由nullText代替。
    return new Joiner(this, null) {
        CharSequence toString(@Nullable Object part) {
            return (CharSequence)(part == null?nullText:Joiner.this.toString(part));
        }

        public Joiner useForNull(String nullTextx) {
            throw new UnsupportedOperationException("already specified useForNull");
        }

        public Joiner skipNulls() {
            throw new UnsupportedOperationException("already specified useForNull");
        }
    };
}

使用 useForNull方法后由于重写了useForNull和skipNulls方法,并且在两个方法中都抛出了异常。所以不能再次调用这两个方法。

skipNulls方法

自动跳过null元素进行拼接

源码解析:

public Joiner skipNulls() {
    //返回一个Joiner,重写了 appendTo方法,讲null元素无视掉
    return new Joiner(this, null) {
        public <A extends Appendable> A appendTo(A appendable, Iterator<?> parts) throws IOException {
            Preconditions.checkNotNull(appendable, "appendable");
            Preconditions.checkNotNull(parts, "parts");
            Object part;
            while(parts.hasNext()) {
                part = parts.next();
                if(part != null) {
                    appendable.append(Joiner.this.toString(part));
                    break;
                }
            }
            while(parts.hasNext()) {
                part = parts.next(); 
                if(part != null) {
                    appendable.append(Joiner.this.separator);
                    appendable.append(Joiner.this.toString(part));
                }
            }
            return appendable;
        }

        public Joiner useForNull(String nullText) {
            throw new UnsupportedOperationException("already specified skipNulls");
        }

        public Joiner.MapJoiner withKeyValueSeparator(String kvs) {
            throw new UnsupportedOperationException("can\'t use .skipNulls() with maps");
        }
    };
}

使用 skipNulls方法后由于重写了useForNull和skipNulls方法,并且在两个方法中都抛出了异常。所以不能再次调用这两个方法。

对Map解析的函数和类

public Joiner.MapJoiner withKeyValueSeparator(String keyValueSeparator) {
    return new Joiner.MapJoiner(this, keyValueSeparator, null);
}

可以看到这个函数返回的是Joiner中的一个内部类,这个类里的大多方法都是在处理Map连接的函数

MapJoiner中的join方法实际上是对Map的entrySet即可以的集合进行拼接

猜你喜欢

转载自blog.csdn.net/dancheng1/article/details/84819034