基本功:你不知道StringJoiner

StringJoiner是Java8新出的一个类,用于构造由分隔符分隔的字符序列,并可选择性地从提供的前缀开始和以提供的后缀结尾。

StringJoiner nameJoiner = new StringJoiner(":", "[", "]");
nameJoiner.add("George").add("Sally").add("Fred");
System.out.println(nameJoiner.toString());

说实话,为何要讲这个呢?主要是要从很频繁很常见的地方了解到你不知道的基本知识。要实现String Join需求一定也不复杂,google的guava也给出了实现:

System.out.println(Joiner.on(";").join(Lists.newArrayList("alex", "top")));
//源码也不复杂,主要是依赖StringBuilder
public class Joiner {
    private final String separator;

    public static Joiner on(String separator) {
        return new Joiner(separator);
    }
    @CanIgnoreReturnValue
    public final StringBuilder appendTo(StringBuilder builder, Iterator<?> parts) {
        try {
            this.appendTo((Appendable)builder, (Iterator)parts);
            return builder;
        } catch (IOException var4) {
            throw new AssertionError(var4);
        }
    }
}

Joiner更简洁,个人更喜欢,我猜想StringJoiner 也有它的影子(作者估计用过,看完整篇会懂)。

public final class StringJoiner {
    private final String prefix;//前缀
    private final String delimiter;//后缀
    private final String suffix;//间隔符
    private StringBuilder value;//值

    private String emptyValue;//空值

    public StringJoiner(CharSequence delimiter) {
        this(delimiter, "", "");//默认前缀和后缀为"",重载调用
    }

    public StringJoiner(CharSequence delimiter,
                        CharSequence prefix,
                        CharSequence suffix) {     
        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;//空值被设置为只有前后缀
    }
    //设置空值,检查是否为null
    public StringJoiner setEmptyValue(CharSequence emptyValue) {
        this.emptyValue = Objects.requireNonNull(emptyValue,
            "The empty value must not be null").toString();
        return this;
    }

    @Override
    public String toString() {
        if (value == null) {
            return emptyValue;//没有值将返回空值或者后续设置的空值
        } else {
            if (suffix.equals("")) {
                return value.toString();//后缀为""直接返回字符串,不用添加
            } else {
                //后缀不为"",添加后缀,然后直接返回字符串,修改长度
                int initialLength = value.length();
                String result = value.append(suffix).toString();
                // reset value to pre-append initialLength
                value.setLength(initialLength);
                return result;
            }
        }
    }
    初始化,先添加前缀,有了之后每次先添加间隔符,StringBuilder后续append字符串
    public StringJoiner add(CharSequence newElement) {
        prepareBuilder().append(newElement);
        return this;
    }
    //合并StringJoiner,注意后面StringJoiner 的前缀就不要了,后面的appen进来
    public StringJoiner merge(StringJoiner other) {
        Objects.requireNonNull(other);
        if (other.value != null) {
            final int length = other.value.length();
            // lock the length so that we can seize the data to be appended
            // before initiate copying to avoid interference, especially when
            // merge 'this'
            StringBuilder builder = prepareBuilder();
            builder.append(other.value, other.prefix.length(), length);
        }
        return this;
    }
    //初始化,先添加前缀,有了之后每次先添加间隔符
    private StringBuilder prepareBuilder() {
        if (value != null) {
            value.append(delimiter);
        } else {
            value = new StringBuilder().append(prefix);
        }
        return value;
    }

    public int length() {      
        return (value != null ? value.length() + suffix.length() :
                emptyValue.length());
    }
}

StringJoiner 的用法仅此而已,难道不支持List吗?感觉它有一般目的是为此而生,只不过它通过Stream来完成:

System.out.println(Lists.newArrayList("alex", "top").stream().collect(Collectors.joining(";")));
//源码
public final class Collectors {
    public static Collector<CharSequence, ?, String> joining(CharSequence delimiter) {
        return joining(delimiter, "", "");
    }
    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);
    }
    /**它是一个可变的汇聚操作,它会在所有元素都处理完毕后,将累积的结果转换为一个最终的表示
    * T:输入类型(流中每个元素的类型)
    * A:表示中间结果容器的类型
    * R:返回类型
    **/
    static class CollectorImpl<T, A, R> implements Collector<T, A, R> {
        CollectorImpl(Supplier<A> supplier,
                      BiConsumer<A, T> accumulator,
                      BinaryOperator<A> combiner,
                      Function<A,R> finisher,
                      Set<Characteristics> characteristics) {
            this.supplier = supplier; //延迟创建中间结果容器
            this.accumulator = accumulator; //将流中的元素添加中间结果容器
            this.combiner = combiner; //对于两个中间结果容器并成一个(非必然运行)
            this.finisher = finisher;//可选的最终转换(中间结果与最终结果类型是否一致决定是否运行)
            this.characteristics = characteristics;//标示中间结果是可以直接向最终结果进行强制类型转换
        }
        @Override
        public BiConsumer<A, T> accumulator() {
            return accumulator;
        }
        @Override
        public Supplier<A> supplier() {
            return supplier;
        }
        @Override
        public BinaryOperator<A> combiner() {
            return combiner;
        }
        @Override
        public Function<A, R> finisher() {
            return finisher;
        }
        @Override
        public Set<Characteristics> characteristics() {
            return characteristics;
        }
}

完!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值