add StrJoiner

This commit is contained in:
Looly 2021-06-17 20:41:01 +08:00
parent 757bfdc723
commit 40a14e1508
6 changed files with 268 additions and 20 deletions

View File

@ -8,6 +8,7 @@
### 🐣新特性
* 【core 】 增加UserPassAuthenticator
* 【db 】 获取分组数据源时,移除公共属性项
* 【core 】 增加StrJoiner
### 🐞Bug修复
* 【db 】 修复Oracle下别名错误造成的SQL语法啊错误issue#I3VTQW@Gitee

View File

@ -1371,7 +1371,7 @@ public class CollUtil {
* @since 5.0.6
*/
public static <K, V> Map<K, V> fieldValueMap(Iterable<V> iterable, String fieldName) {
return IterUtil.fieldValueMap(null == iterable ? null : iterable.iterator(), fieldName);
return IterUtil.fieldValueMap(IterUtil.getIter(iterable), fieldName);
}
/**
@ -1386,7 +1386,7 @@ public class CollUtil {
* @since 5.0.6
*/
public static <K, V> Map<K, V> fieldValueAsMap(Iterable<?> iterable, String fieldNameForKey, String fieldNameForValue) {
return IterUtil.fieldValueAsMap(null == iterable ? null : iterable.iterator(), fieldNameForKey, fieldNameForValue);
return IterUtil.fieldValueAsMap(IterUtil.getIter(iterable), fieldNameForKey, fieldNameForValue);
}
/**

View File

@ -5,6 +5,7 @@ import cn.hutool.core.lang.Editor;
import cn.hutool.core.lang.Filter;
import cn.hutool.core.lang.func.Func1;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.text.StrJoiner;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
@ -30,6 +31,18 @@ import java.util.function.Function;
*/
public class IterUtil {
/**
* 获取{@link Iterator}
*
* @param iterable {@link Iterable}
* @param <T> 元素类型
* @return 当iterable为null返回{@code null}否则返回对应的{@link Iterator}
* @since 5.7.2
*/
public static <T> Iterator<T> getIter(Iterable<T> iterable) {
return null == iterable ? null : iterable.iterator();
}
/**
* Iterable是否为空
*
@ -199,7 +212,7 @@ public class IterUtil {
* @since 4.6.2
*/
public static <V> List<Object> fieldValueList(Iterable<V> iterable, String fieldName) {
return fieldValueList(null == iterable ? null : iterable.iterator(), fieldName);
return fieldValueList(getIter(iterable), fieldName);
}
/**
@ -252,9 +265,9 @@ public class IterUtil {
return join(iterator, conjunction, (item) -> {
if (ArrayUtil.isArray(item)) {
return ArrayUtil.join(ArrayUtil.wrap(item), conjunction, prefix, suffix);
} else if (item instanceof Iterable<?>) {
} else if (item instanceof Iterable) {
return CollUtil.join((Iterable<?>) item, conjunction, prefix, suffix);
} else if (item instanceof Iterator<?>) {
} else if (item instanceof Iterator) {
return join((Iterator<?>) item, conjunction, prefix, suffix);
} else {
return StrUtil.wrap(String.valueOf(item), prefix, suffix);
@ -278,20 +291,7 @@ public class IterUtil {
return null;
}
final StringBuilder sb = new StringBuilder();
boolean isFirst = true;
T item;
while (iterator.hasNext()) {
if (isFirst) {
isFirst = false;
} else {
sb.append(conjunction);
}
item = iterator.next();
sb.append(func.apply(item));
}
return sb.toString();
return new StrJoiner(conjunction).append(iterator, func).toString();
}
/**

View File

@ -0,0 +1,237 @@
package cn.hutool.core.text;
import cn.hutool.core.collection.ArrayIter;
import cn.hutool.core.collection.IterUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import java.io.IOException;
import java.util.Iterator;
import java.util.function.Function;
/**
* 字符串连接器拼接器通过给定的字符串和多个元素拼接为一个字符串
*
* @author looly
* @since 5.7.2
*/
public class StrJoiner implements Appendable {
private Appendable appendable;
private CharSequence delimiter;
private CharSequence prefix;
private CharSequence suffix;
/**
* appendable中是否包含内容
*/
private boolean hasContent;
/**
* 构造
*
* @param delimiter 分隔符{@code null}表示无连接符直接拼接
*/
public StrJoiner(CharSequence delimiter) {
this(null, delimiter);
}
/**
* 构造
*
* @param appendable 字符串追加器拼接的字符串都将加入到此{@code null}使用默认{@link StringBuilder}
* @param delimiter 分隔符{@code null}表示无连接符直接拼接
*/
public StrJoiner(Appendable appendable, CharSequence delimiter) {
this(appendable, delimiter, null, null);
}
/**
* 构造
*
* @param delimiter 分隔符{@code null}表示无连接符直接拼接
* @param prefix 前缀
* @param suffix 后缀
*/
public StrJoiner(CharSequence delimiter, CharSequence prefix, CharSequence suffix) {
this(null, delimiter, prefix, suffix);
}
/**
* 构造
*
* @param appendable 字符串追加器拼接的字符串都将加入到此{@code null}使用默认{@link StringBuilder}
* @param delimiter 分隔符{@code null}表示无连接符直接拼接
* @param prefix 前缀
* @param suffix 后缀
*/
public StrJoiner(Appendable appendable, CharSequence delimiter,
CharSequence prefix, CharSequence suffix) {
if (null != appendable) {
this.appendable = appendable;
final String initStr = appendable.toString();
if (StrUtil.isNotEmpty(initStr) && false == StrUtil.endWith(initStr, delimiter)) {
// 用户传入的Appendable中已经存在内容且末尾不是分隔符
this.hasContent = true;
}
}
this.delimiter = delimiter;
this.prefix = prefix;
this.suffix = suffix;
}
/**
* 设置分隔符
*
* @param delimiter 分隔符
* @return this
*/
public StrJoiner setDelimiter(CharSequence delimiter) {
this.delimiter = delimiter;
return this;
}
/**
* 设置前缀
*
* @param prefix 前缀
* @return this
*/
public StrJoiner setPrefix(CharSequence prefix) {
this.prefix = prefix;
return this;
}
/**
* 设置后缀
*
* @param suffix 后缀
* @return this
*/
public StrJoiner setSuffix(CharSequence suffix) {
this.suffix = suffix;
return this;
}
/**
* 追加{@link Iterator}中的元素到拼接器中
*
* @param <T> 元素类型
* @param iterable 元素列表
* @return this
*/
public <T> StrJoiner append(Iterable<T> iterable) {
return append(IterUtil.getIter(iterable));
}
/**
* 追加{@link Iterator}中的元素到拼接器中
*
* @param <T> 元素类型
* @param iterator 元素列表
* @return this
*/
public <T> StrJoiner append(Iterator<T> iterator) {
return append(iterator, (t)->{
if(ArrayUtil.isArray(t)){
return new StrJoiner(this.delimiter).append((Iterator<?>) new ArrayIter<>(t)).toString();
} else if(t instanceof Iterator){
return new StrJoiner(this.delimiter).append((Iterator<?>)t).toString();
} else if(t instanceof Iterable){
return new StrJoiner(this.delimiter).append((Iterable<?>)t).toString();
}
return String.valueOf(t);
});
}
/**
* 追加{@link Iterator}中的元素到拼接器中
*
* @param <T> 元素类型
* @param iterable 元素列表
* @param toStrFunc 元素对象转换为字符串的函数
* @return this
*/
public <T> StrJoiner append(Iterable<T> iterable, Function<T, ? extends CharSequence> toStrFunc) {
return append(IterUtil.getIter(iterable), toStrFunc);
}
/**
* 追加{@link Iterator}中的元素到拼接器中
*
* @param <T> 元素类型
* @param iterator 元素列表
* @param toStrFunc 元素对象转换为字符串的函数
* @return this
*/
public <T> StrJoiner append(Iterator<T> iterator, Function<T, ? extends CharSequence> toStrFunc) {
if (null != iterator) {
while (iterator.hasNext()) {
append(toStrFunc.apply(iterator.next()));
}
}
return this;
}
@Override
public StrJoiner append(CharSequence csq) {
try {
prepare().append(csq);
} catch (IOException e) {
throw new IORuntimeException(e);
}
return this;
}
@Override
public StrJoiner append(CharSequence csq, int start, int end) {
try {
prepare().append(csq, start, end);
} catch (IOException e) {
throw new IORuntimeException(e);
}
return this;
}
@Override
public StrJoiner append(char c) {
try {
prepare().append(c);
} catch (IOException e) {
throw new IORuntimeException(e);
}
return this;
}
@Override
public String toString() {
if (StrUtil.isNotEmpty(this.suffix)) {
try {
appendable.append(this.suffix);
} catch (IOException e) {
throw new IORuntimeException(e);
}
}
return appendable.toString();
}
/**
* 准备连接器如果连接器非空追加元素否则初始化前缀
*
* @return {@link Appendable}
* @throws IOException IO异常
*/
private Appendable prepare() throws IOException {
if (hasContent) {
this.appendable.append(delimiter);
} else {
this.appendable = new StringBuilder();
if (StrUtil.isNotEmpty(this.prefix)) {
this.appendable.append(this.prefix);
}
this.hasContent = true;
}
return this.appendable;
}
}

View File

@ -130,7 +130,9 @@ public class StrUtil extends CharSequenceUtil implements StrPool {
* @param obj 对象
* @param charsetName 字符集
* @return 字符串
* @deprecated 请使用 {@link #str(Object, Charset)}
*/
@Deprecated
public static String str(Object obj, String charsetName) {
return str(obj, Charset.forName(charsetName));
}
@ -263,9 +265,10 @@ public class StrUtil extends CharSequenceUtil implements StrPool {
* @param obj 对象
* @return 字符串
* @since 4.1.3
* @see String#valueOf(Object)
*/
public static String toString(Object obj) {
return null == obj ? NULL : obj.toString();
return String.valueOf(obj);
}
/**

View File

@ -37,6 +37,13 @@ public class IterUtilTest {
Assert.assertEquals("\"1\":\"2\":\"3\":\"4\"", join2);
}
@Test
public void joinWithFuncTest() {
ArrayList<String> list = CollUtil.newArrayList("1", "2", "3", "4");
String join = IterUtil.join(list.iterator(), ":", String::valueOf);
Assert.assertEquals("1:2:3:4", join);
}
@Test
public void testToListMap() {
Map<String, List<String>> expectedMap = new HashMap<>();