Joiner
只提供两个静态方法,参数是分隔符。静态方法内部new一个自身对象,返回该对象,之后可以通过该对象访问非静态方法和访问非静态数据
//方法一
public static Joiner on(String separator) {
return new Joiner(separator);
}
//方法二
public static Joiner on(char separator) {
return new Joiner(String.valueOf(separator));
}
两个私有有参构造(一个参数是分隔符,一个参数是对象自身类型)
private Joiner(String separator) {
this.separator = checkNotNull(separator);
}
private Joiner(Joiner prototype) {
this.separator = prototype.separator;
}
测试skipNulls:
//添加分隔符
Joiner joiner = Joiner.on("*");
//重写了appendTo方法,允许参数有null值
joiner = joiner.skipNulls();
//调用重写后的appendTo方法拼接参数
String join = joiner.join(Lists.newArrayList("aaa", "bbb", "ccc", null, "ddd"));
System.out.println(join);
//输出aaa*bbb*ccc*ddd
第一步,通过调用静态方法,静态方法内部通过有参构造生成一个新的Joiner对象
第二步,执行skipNulls方法,该方法生成一个新的Joiner对象,将原先的分隔符赋值给新的Joiner对象,且重写了apperdTo方法,。重写后的方法就在原先apperdTo方法的基础上,加了null值的判断,如果为null就跳过。此时该方法流程是:
- 非空判断拼接的流对象和虚拼接的数组对象
- 进入第一个循环,直到拿到不为null的元素后跳出
- 进入第二个循环,每当拿到不为null的元素时,都先拼接分隔符,再拼接元素值
- 最后拼接返回结果
ps:如果是没有重写的appendTo方法,不会进行null,判断,直接执行字符串的拼接append方法,如果遇到null,就会抛出空指针异常
public Joiner skipNulls() {
return new Joiner(this) {
@Override
public <A extends Appendable> A appendTo(
A appendable, Iterator<? extends @Nullable Object> 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");
}
};
}
测试useForNull:
//添加分隔符
Joiner joiner = Joiner.on("*");
//将null替换为指定值
joiner = joiner.useForNull("XXX");
String join = joiner.join(Lists.newArrayList("aaa", "bbb", "ccc", null, "ddd"));
System.out.println(join);
//输出aaa*bbb*ccc*XXX*ddd
该方法在原先未重写appendTo方法的基础上重写了toString方法,本身为重写appendTo方法是不会跳过null值,重写后的toString方法就会将null值替换为指定的值
public Joiner useForNull(String nullText) {
checkNotNull(nullText);
return new Joiner(this) {
@Override
CharSequence toString(@CheckForNull Object part) {
return (part == null) ? nullText : Joiner.this.toString(part);
}
@Override
public Joiner useForNull(String nullText) {
throw new UnsupportedOperationException("already specified useForNull");
}
@Override
public Joiner skipNulls() {
throw new UnsupportedOperationException("already specified useForNull");
}
};
}
测试useForNull:
Joiner joiner = Joiner.on("*");
Map<String,String> map = new HashMap<>();
map.put("aaa","bbb");
map.put("ccc",null);
map.put("ddd","eee");
String result = joiner.withKeyValueSeparator("XXX").useForNull("LLL").join(map);
System.out.println(result);
//输出aaaXXXbbb*cccXXXLLL*dddXXXeee
该方法可以将map集合改为 key+分隔符+value格式,配合useForNull,可以将value等于null的值替换为指定值
public <A extends Appendable> A appendTo(A appendable, Iterator<? extends Entry<?, ?>> parts)
throws IOException {
checkNotNull(appendable);
if (parts.hasNext()) {
Entry<?, ?> entry = parts.next();
appendable.append(joiner.toString(entry.getKey()));
appendable.append(keyValueSeparator);
appendable.append(joiner.toString(entry.getValue()));
while (parts.hasNext()) {
appendable.append(joiner.separator);
Entry<?, ?> e = parts.next();
appendable.append(joiner.toString(e.getKey()));
appendable.append(keyValueSeparator);
appendable.append(joiner.toString(e.getValue()));
}
}
return appendable;
}
迭代获取每个map元素,进行拼接,同理,如果执行了useForNull方法,会重写toString方法,将null值替换为指定值
思考:
- 为什么需要通过静态方法调用构造方法来生成对象,访问非静态方法和非静态成员
- 使用静态工厂模式
- 减少对外暴露的属性
- 线程安全性
由于每次调用on方法时,返回的都是一个新的构造对象,后续的非静态方法都是依赖新的对象,所以不存在线程安全问题
网友评论