mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
add StrJoiner
This commit is contained in:
parent
757bfdc723
commit
40a14e1508
@ -8,6 +8,7 @@
|
||||
### 🐣新特性
|
||||
* 【core 】 增加UserPassAuthenticator
|
||||
* 【db 】 获取分组数据源时,移除公共属性项
|
||||
* 【core 】 增加StrJoiner
|
||||
|
||||
### 🐞Bug修复
|
||||
* 【db 】 修复Oracle下别名错误造成的SQL语法啊错误(issue#I3VTQW@Gitee)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
237
hutool-core/src/main/java/cn/hutool/core/text/StrJoiner.java
Normal file
237
hutool-core/src/main/java/cn/hutool/core/text/StrJoiner.java
Normal 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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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<>();
|
||||
|
Loading…
x
Reference in New Issue
Block a user