merge conflict

This commit is contained in:
飘辰
2021-06-09 16:26:07 +08:00
241 changed files with 1907 additions and 1284 deletions

View File

@@ -3,15 +3,30 @@
-------------------------------------------------------------------------------------------------------------
# 5.6.7 (2021-06-02)
# 5.6.8 (2021-06-09)
### 🐣新特性
### 🐞Bug修复
-------------------------------------------------------------------------------------------------------------
# 5.6.7 (2021-06-08)
### 🐣新特性
* 【core 】 CharSequenceUtil增加join重载issue#I3TFJ5@Gitee
* 【http 】 HttpRequest增加form方法重载pr#337@Gitee
* 【http 】 ImgUtil增加getMainColor方法pr#338@Gitee
* 【core 】 改进TreeUtil.buid算法性能pr#1594@Github
* 【core 】 CsvConfig的setXXX返回thisissue#I3UIQF@Gitee
* 【all 】 增加jmh基准测试
* 【core 】 增加StreamUtil和CollectorUtil
* 【poi 】 增加content-type(pr#1639@Github)
### 🐞Bug修复
* 【core 】 修复FileUtil.normalize去掉末尾空格问题issue#1603@Github
* 【core 】 修复CharsetDetector流关闭问题issue#1603@Github
* 【core 】 修复RuntimeUtil.exec引号内空格被切分的问题issue#I3UAYB@Gitee
-------------------------------------------------------------------------------------------------------------

View File

@@ -122,18 +122,18 @@ Each module can be introduced individually, or all modules can be introduced by
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.6.7</version>
<version>5.6.8</version>
</dependency>
```
### 🍐Gradle
```
compile 'cn.hutool:hutool-all:5.6.7'
compile 'cn.hutool:hutool-all:5.6.8'
```
## 📥Download
- [Maven Repo](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.6.7/)
- [Maven Repo](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.6.8/)
> 🔔note:
> Hutool 5.x supports JDK8+ and is not tested on Android platforms, and cannot guarantee that all tool classes or tool methods are available.

View File

@@ -120,20 +120,20 @@ Hutool的存在就是为了减少代码搜索成本避免网络上参差不
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.6.7</version>
<version>5.6.8</version>
</dependency>
```
### 🍐Gradle
```
compile 'cn.hutool:hutool-all:5.6.7'
compile 'cn.hutool:hutool-all:5.6.8'
```
### 📥下载jar
点击以下链接,下载`hutool-all-X.X.X.jar`即可:
- [Maven中央库](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.6.7/)
- [Maven中央库](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.6.8/)
> 🔔️注意
> Hutool 5.x支持JDK8+对Android平台没有测试不能保证所有工具类或工具方法可用。

View File

@@ -1 +1 @@
5.6.7
5.6.8

View File

@@ -1 +1 @@
var version = '5.6.7'
var version = '5.6.8'

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.6.7-SNAPSHOT</version>
<version>5.6.8-SNAPSHOT</version>
</parent>
<artifactId>hutool-all</artifactId>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.6.7-SNAPSHOT</version>
<version>5.6.8-SNAPSHOT</version>
</parent>
<artifactId>hutool-aop</artifactId>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.6.7-SNAPSHOT</version>
<version>5.6.8-SNAPSHOT</version>
</parent>
<artifactId>hutool-bloomFilter</artifactId>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.6.7-SNAPSHOT</version>
<version>5.6.8-SNAPSHOT</version>
</parent>
<artifactId>hutool-bom</artifactId>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.6.7-SNAPSHOT</version>
<version>5.6.8-SNAPSHOT</version>
</parent>
<artifactId>hutool-cache</artifactId>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.6.7-SNAPSHOT</version>
<version>5.6.8-SNAPSHOT</version>
</parent>
<artifactId>hutool-captcha</artifactId>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.6.7-SNAPSHOT</version>
<version>5.6.8-SNAPSHOT</version>
</parent>
<artifactId>hutool-core</artifactId>

View File

@@ -273,19 +273,19 @@ public class BeanDesc implements Serializable {
if (fieldName.startsWith("is")) {
// 字段已经是is开头
if (methodName.equals(fieldName) // isName -》 isName
|| methodName.equals("get" + handledFieldName)// isName -》 getIsName
|| methodName.equals("is" + handledFieldName)// isName -》 isIsName
|| ("get" + handledFieldName).equals(methodName)// isName -》 getIsName
|| ("is" + handledFieldName).equals(methodName)// isName -》 isIsName
) {
return true;
}
} else if (methodName.equals("is" + handledFieldName)) {
} else if (("is" + handledFieldName).equals(methodName)) {
// 字段非is开头 name -》 isName
return true;
}
}
// 包括boolean的任何类型只有一种匹配情况name -》 getName
return methodName.equals("get" + handledFieldName);
return ("get" + handledFieldName).equals(methodName);
}
/**
@@ -324,15 +324,15 @@ public class BeanDesc implements Serializable {
// 针对Boolean类型特殊检查
if (isBooleanField && fieldName.startsWith("is")) {
// 字段是is开头
if (methodName.equals("set" + StrUtil.removePrefix(fieldName, "is"))// isName -》 setName
|| methodName.equals("set" + handledFieldName)// isName -》 setIsName
if (("set" + StrUtil.removePrefix(fieldName, "is")).equals(methodName)// isName -》 setName
|| ("set" + handledFieldName).equals(methodName)// isName -》 setIsName
) {
return true;
}
}
// 包括boolean的任何类型只有一种匹配情况name -》 setName
return methodName.equals("set" + fieldName);
return ("set" + fieldName).equals(methodName);
}
// ------------------------------------------------------------------------------------------------------ Private method end
}

View File

@@ -938,7 +938,7 @@ public class HashCodeBuilder implements Builder<Integer> {
*/
@Override
public Integer build() {
return Integer.valueOf(toHashCode());
return toHashCode();
}
/**

View File

@@ -132,7 +132,7 @@ public class Base64Encoder {
*
* @param arr 被编码的数组
* @param isMultiLine 在76个char之后是CRLF还是EOF
* @param isUrlSafe 是否使用URL安全字符一般为{@code false}
* @param isUrlSafe 是否使用URL安全字符在URL Safe模式下=为URL中的关键字符不需要补充。空余的byte位要去掉一般为{@code false}
* @return 编码后的bytes
*/
public static byte[] encode(byte[] arr, boolean isMultiLine, boolean isUrlSafe) {

View File

@@ -27,8 +27,8 @@ public class Morse {
* @param dict 二进制
*/
private static void registerMorse(Character abc, String dict) {
ALPHABETS.put(Integer.valueOf(abc), dict);
DICTIONARIES.put(dict, Integer.valueOf(abc));
ALPHABETS.put((int) abc, dict);
DICTIONARIES.put(dict, (int) abc);
}
static {

View File

@@ -510,6 +510,24 @@ public class CollUtil {
return IterUtil.countMap(null == collection ? null : collection.iterator());
}
/**
* 以 conjunction 为分隔符将集合转换为字符串
*
* @param <T> 集合元素类型
* @param iterable {@link Iterable}
* @param conjunction 分隔符
* @param func 集合元素转换器,将元素转换为字符串
* @return 连接后的字符串
* @see IterUtil#join(Iterator, CharSequence, Function)
* @since 5.6.7
*/
public static <T> String join(Iterable<T> iterable, CharSequence conjunction, Function<T, ? extends CharSequence> func) {
if (null == iterable) {
return null;
}
return IterUtil.join(iterable.iterator(), conjunction, func);
}
/**
* 以 conjunction 为分隔符将集合转换为字符串<br>
* 如果集合元素为数组、{@link Iterable}或{@link Iterator},则递归组合其为字符串
@@ -1617,9 +1635,9 @@ public class CollUtil {
* @since 5.6.6
*/
public static <T> int lastIndexOf(Collection<T> collection, Matcher<T> matcher) {
if(collection instanceof List){
if (collection instanceof List) {
// List的查找最后一个有优化算法
return ListUtil.lastIndexOf((List<T>)collection, matcher);
return ListUtil.lastIndexOf((List<T>) collection, matcher);
}
int matchIndex = -1;
if (isNotEmpty(collection)) {
@@ -2612,7 +2630,7 @@ public class CollUtil {
* @since 5.4.7
*/
public static <T> void forEach(Iterable<T> iterable, Consumer<T> consumer) {
if(iterable == null){
if (iterable == null) {
return;
}
forEach(iterable.iterator(), consumer);
@@ -2626,7 +2644,7 @@ public class CollUtil {
* @param consumer {@link Consumer} 遍历的每条数据处理器
*/
public static <T> void forEach(Iterator<T> iterator, Consumer<T> consumer) {
if(iterator == null){
if (iterator == null) {
return;
}
int index = 0;
@@ -2644,7 +2662,7 @@ public class CollUtil {
* @param consumer {@link Consumer} 遍历的每条数据处理器
*/
public static <T> void forEach(Enumeration<T> enumeration, Consumer<T> consumer) {
if(enumeration == null){
if (enumeration == null) {
return;
}
int index = 0;
@@ -2664,7 +2682,7 @@ public class CollUtil {
* @param kvConsumer {@link KVConsumer} 遍历的每条数据处理器
*/
public static <K, V> void forEach(Map<K, V> map, KVConsumer<K, V> kvConsumer) {
if(map == null){
if (map == null) {
return;
}
int index = 0;
@@ -2986,7 +3004,7 @@ public class CollUtil {
* @author Looly
*/
@FunctionalInterface
public interface KVConsumer<K, V> extends Serializable{
public interface KVConsumer<K, V> extends Serializable {
/**
* 接受并处理一对参数
*

View File

@@ -337,6 +337,31 @@ public class IterUtil {
* @since 4.0.10
*/
public static <T> String join(Iterator<T> iterator, CharSequence conjunction, String prefix, String suffix) {
return join(iterator, conjunction, (item)->{
if (ArrayUtil.isArray(item)) {
return ArrayUtil.join(ArrayUtil.wrap(item), conjunction, prefix, suffix);
} else if (item instanceof Iterable<?>) {
return join((Iterable<?>) item, conjunction, prefix, suffix);
} else if (item instanceof Iterator<?>) {
return join((Iterator<?>) item, conjunction, prefix, suffix);
} else {
return StrUtil.wrap(String.valueOf(item), prefix, suffix);
}
});
}
/**
* 以 conjunction 为分隔符将集合转换为字符串<br>
* 如果集合元素为数组、{@link Iterable}或{@link Iterator},则递归组合其为字符串
*
* @param <T> 集合元素类型
* @param iterator 集合
* @param conjunction 分隔符
* @param func 集合元素转换器,将元素转换为字符串
* @return 连接后的字符串
* @since 5.6.7
*/
public static <T> String join(Iterator<T> iterator, CharSequence conjunction, Function<T, ? extends CharSequence> func) {
if (null == iterator) {
return null;
}
@@ -352,15 +377,7 @@ public class IterUtil {
}
item = iterator.next();
if (ArrayUtil.isArray(item)) {
sb.append(ArrayUtil.join(ArrayUtil.wrap(item), conjunction, prefix, suffix));
} else if (item instanceof Iterable<?>) {
sb.append(join((Iterable<?>) item, conjunction, prefix, suffix));
} else if (item instanceof Iterator<?>) {
sb.append(join((Iterator<?>) item, conjunction, prefix, suffix));
} else {
sb.append(StrUtil.wrap(String.valueOf(item), prefix, suffix));
}
sb.append(func.apply(item));
}
return sb.toString();
}
@@ -826,7 +843,7 @@ public class IterUtil {
* @since 5.5.0
*/
public static int size(final Iterable<?> iterable) {
if(null == iterable){
if (null == iterable) {
return 0;
}

View File

@@ -27,7 +27,6 @@ import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
/**
* 时间工具类
@@ -931,7 +930,6 @@ public class DateUtil extends CalendarUtil {
//标准日期格式(包括单个数字的日期时间)
dateStr = normalize(dateStr);
final Matcher matcher = DatePattern.REGEX_NORM.matcher(dateStr);
if (ReUtil.isMatch(DatePattern.REGEX_NORM, dateStr)) {
final int colonCount = StrUtil.count(dateStr, CharUtil.COLON);
switch (colonCount) {

View File

@@ -299,7 +299,7 @@ public class FastDatePrinter extends AbstractDateBasic implements DatePrinter {
} else if (obj instanceof Calendar) {
return format((Calendar) obj);
} else if (obj instanceof Long) {
return format(((Long) obj).longValue());
return format(((Long) obj));
} else {
throw new IllegalArgumentException("Unknown class: " + (obj == null ? "<null>" : obj.getClass().getName()));
}

View File

@@ -113,7 +113,7 @@ abstract class FormatCache<F extends Format> {
*/
// package protected, for access from FastDateFormat; do not make public or protected
F getDateTimeInstance(final int dateStyle, final int timeStyle, final TimeZone timeZone, final Locale locale) {
return getDateTimeInstance(Integer.valueOf(dateStyle), Integer.valueOf(timeStyle), timeZone, locale);
return getDateTimeInstance(dateStyle, timeStyle, timeZone, locale);
}
/**

View File

@@ -43,8 +43,10 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
/**
@@ -1164,7 +1166,7 @@ public class ImgUtil {
* @since 4.3.2
*/
public static BufferedImage toBufferedImage(Image image, String imageType) {
final int type = imageType.equalsIgnoreCase(IMAGE_TYPE_PNG)
final int type = IMAGE_TYPE_PNG.equalsIgnoreCase(imageType)
? BufferedImage.TYPE_INT_ARGB
: BufferedImage.TYPE_INT_RGB;
return toBufferedImage(image, type);
@@ -1724,7 +1726,7 @@ public class ImgUtil {
}
if (null == result) {
throw new IllegalArgumentException("Image type of [" + imageUrl.toString() + "] is not supported!");
throw new IllegalArgumentException("Image type of [" + imageUrl + "] is not supported!");
}
return result;
@@ -2002,6 +2004,57 @@ public class ImgUtil {
);
}
/**
* 获取给定图片的主色调,背景填充用
*
* @param image {@link BufferedImage}
* @param rgbFilters 过滤多种颜色
* @return {@link String} #ffffff
* @since 5.6.7
*/
public static String getMainColor(BufferedImage image, int[]... rgbFilters) {
int r, g, b;
Map<String, Long> countMap = new HashMap<>();
int width = image.getWidth();
int height = image.getHeight();
int minx = image.getMinX();
int miny = image.getMinY();
for (int i = minx; i < width; i++) {
for (int j = miny; j < height; j++) {
int pixel = image.getRGB(i, j);
r = (pixel & 0xff0000) >> 16;
g = (pixel & 0xff00) >> 8;
b = (pixel & 0xff);
if (rgbFilters != null && rgbFilters.length > 0) {
for (int[] rgbFilter : rgbFilters) {
if (r == rgbFilter[0] && g == rgbFilter[1] && b == rgbFilter[2]) {
break;
}
}
}
countMap.merge(r + "-" + g + "-" + b, 1L, Long::sum);
}
}
String maxColor = null;
long maxCount = 0;
for (Map.Entry<String, Long> entry : countMap.entrySet()) {
String key = entry.getKey();
Long count = entry.getValue();
if (count > maxCount) {
maxColor = key;
maxCount = count;
}
}
final String[] splitRgbStr = StrUtil.splitToArray(maxColor, '-');
String rHex = Integer.toHexString(Integer.parseInt(splitRgbStr[0]));
String gHex = Integer.toHexString(Integer.parseInt(splitRgbStr[1]));
String bHex = Integer.toHexString(Integer.parseInt(splitRgbStr[2]));
rHex = rHex.length() == 1 ? "0" + rHex : rHex;
gHex = gHex.length() == 1 ? "0" + gHex : gHex;
bHex = bHex.length() == 1 ? "0" + bHex : bHex;
return "#" + rHex + gHex + bHex;
}
// ------------------------------------------------------------------------------------------------------ 背景图换算
/**

View File

@@ -778,9 +778,6 @@ public class GifDecoder {
lastRect = new Rectangle(ix, iy, iw, ih);
lastImage = image;
lastBgColor = bgColor;
int dispose = 0;
boolean transparency = false;
int delay = 0;
lct = null;
}

View File

@@ -350,10 +350,7 @@ public class NeuQuant {
/* Unbias network to give byte values 0..255 and record position i to prepare for sort
----------------------------------------------------------------------------------- */
public void unbiasnet() {
int i, j;
for (i = 0; i < NETSIZE; i++) {
for (int i = 0; i < NETSIZE; i++) {
network[i][0] >>= NETBIASSHIFT;
network[i][1] >>= NETBIASSHIFT;
network[i][2] >>= NETBIASSHIFT;

View File

@@ -38,7 +38,7 @@ public class MutableBool implements Comparable<MutableBool>, Mutable<Boolean>, S
@Override
public Boolean get() {
return Boolean.valueOf(this.value);
return this.value;
}
/**
@@ -51,7 +51,7 @@ public class MutableBool implements Comparable<MutableBool>, Mutable<Boolean>, S
@Override
public void set(final Boolean value) {
this.value = value.booleanValue();
this.value = value;
}
// -----------------------------------------------------------------------

View File

@@ -46,7 +46,7 @@ public class MutableByte extends Number implements Comparable<MutableByte>, Muta
@Override
public Byte get() {
return Byte.valueOf(this.value);
return this.value;
}
/**

View File

@@ -46,7 +46,7 @@ public class MutableDouble extends Number implements Comparable<MutableDouble>,
@Override
public Double get() {
return Double.valueOf(this.value);
return this.value;
}
/**

View File

@@ -46,7 +46,7 @@ public class MutableFloat extends Number implements Comparable<MutableFloat>, Mu
@Override
public Float get() {
return Float.valueOf(this.value);
return this.value;
}
/**

View File

@@ -46,7 +46,7 @@ public class MutableInt extends Number implements Comparable<MutableInt>, Mutabl
@Override
public Integer get() {
return Integer.valueOf(this.value);
return this.value;
}
/**

View File

@@ -46,7 +46,7 @@ public class MutableLong extends Number implements Comparable<MutableLong>, Muta
@Override
public Long get() {
return Long.valueOf(this.value);
return this.value;
}
/**

View File

@@ -46,7 +46,7 @@ public class MutableShort extends Number implements Comparable<MutableShort>, Mu
@Override
public Short get() {
return Short.valueOf(this.value);
return this.value;
}
/**

View File

@@ -1,8 +1,15 @@
package cn.hutool.core.lang.tree;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
@@ -152,8 +159,32 @@ public class Tree<T> extends LinkedHashMap<String, Object> implements Node<T> {
return (List<Tree<T>>) this.get(treeNodeConfig.getChildrenKey());
}
public void setChildren(List<Tree<T>> children) {
public Tree<T> setChildren(List<Tree<T>> children) {
this.put(treeNodeConfig.getChildrenKey(), children);
return this;
}
/**
* 增加子节点,同时关联子节点的父节点为当前节点
*
* @param children 子节点列表
* @return this
* @since 5.6.7
*/
@SafeVarargs
public final Tree<T> addChildren(Tree<T>... children){
if(ArrayUtil.isNotEmpty(children)){
List<Tree<T>> childrenList = this.getChildren();
if(null == childrenList){
childrenList = new ArrayList<>();
setChildren(childrenList);
}
for (Tree<T> child : children) {
child.setParent(this);
childrenList.add(child);
}
}
return this;
}
/**
@@ -166,4 +197,29 @@ public class Tree<T> extends LinkedHashMap<String, Object> implements Node<T> {
Assert.notEmpty(key, "Key must be not empty !");
this.put(key, value);
}
@Override
public String toString() {
final StringWriter stringWriter = new StringWriter();
printTree(this, new PrintWriter(stringWriter), 0);
return stringWriter.toString();
}
/**
* 打印
* @param tree 树
* @param writer Writer
* @param intent 缩进量
*/
private static void printTree(Tree<?> tree, PrintWriter writer, int intent){
writer.println(StrUtil.format("{}{}[{}]", StrUtil.repeat(CharUtil.SPACE, intent), tree.getName(), tree.getId()));
writer.flush();
final List<? extends Tree<?>> children = tree.getChildren();
if(CollUtil.isNotEmpty(children)){
for (Tree<?> child : children) {
printTree(child, writer, intent + 2);
}
}
}
}

View File

@@ -3,11 +3,13 @@ package cn.hutool.core.lang.tree;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.parser.DefaultNodeParser;
import cn.hutool.core.lang.tree.parser.NodeParser;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.stream.Collectors;
import java.util.Map;
/**
* 树工具类
@@ -58,65 +60,49 @@ public class TreeUtil {
* @param <T> 转换的实体 为数据源里的对象类型
* @param <E> ID类型
* @param list 源数据集合
* @param parentId 最顶层父id值 一般为 0 之类
* @param rootId 最顶层父id值 一般为 0 之类
* @param treeNodeConfig 配置
* @param nodeParser 转换器
* @return List
*/
public static <T, E> List<Tree<E>> build(List<T> list, E parentId, TreeNodeConfig treeNodeConfig, NodeParser<T, E> nodeParser) {
final List<Tree<E>> treeList = CollUtil.newArrayList();
Tree<E> tree;
for (T obj : list) {
tree = new Tree<>(treeNodeConfig);
nodeParser.parse(obj, tree);
treeList.add(tree);
public static <T, E> List<Tree<E>> build(List<T> list, E rootId, TreeNodeConfig treeNodeConfig, NodeParser<T, E> nodeParser) {
final Map<E, Tree<E>> map = new LinkedHashMap<>(list.size(), 1);
Tree<E> node;
for (T t : list) {
node = new Tree<>(treeNodeConfig);
nodeParser.parse(t, node);
map.put(node.getId(), node);
}
List<Tree<E>> finalTreeList = CollUtil.newArrayList();
for (Tree<E> node : treeList) {
if (ObjectUtil.equals(parentId,node.getParentId())) {
finalTreeList.add(node);
innerBuild(treeList, node, 0, treeNodeConfig.getDeep());
}
}
// 内存每层已经排过了 这是最外层排序
finalTreeList = finalTreeList.stream().sorted().collect(Collectors.toList());
return finalTreeList;
return build(map, rootId);
}
/**
* 递归处理
* 树构建,按照权重排序
*
* @param treeNodes 数据集合
* @param parentNode 当前节点
* @param deep 已递归深度
* @param maxDeep 最大递归深度 可能为null即不限制
* @param <E> ID类型
* @param map 源数据Map
* @param rootId 最顶层父id值 一般为 0 之类
* @return List
* @since 5.6.7
*/
private static <T> void innerBuild(List<Tree<T>> treeNodes, Tree<T> parentNode, int deep, Integer maxDeep) {
public static <E> List<Tree<E>> build(Map<E, Tree<E>> map, E rootId) {
final Map<E, Tree<E>> eTreeMap = MapUtil.sortByValue(map, false);
List<Tree<E>> rootTreeList = CollUtil.newArrayList();
E parentId;
for (Tree<E> node : eTreeMap.values()) {
parentId = node.getParentId();
if(ObjectUtil.equals(rootId, parentId)){
rootTreeList.add(node);
continue;
}
if (CollUtil.isEmpty(treeNodes)) {
return;
}
//maxDeep 可能为空
if (maxDeep != null && deep >= maxDeep) {
return;
}
// 每层排序 TreeNodeMap 实现了Comparable接口
treeNodes = treeNodes.stream().sorted().collect(Collectors.toList());
for (Tree<T> childNode : treeNodes) {
if (parentNode.getId().equals(childNode.getParentId())) {
List<Tree<T>> children = parentNode.getChildren();
if (children == null) {
children = CollUtil.newArrayList();
parentNode.setChildren(children);
}
children.add(childNode);
// childNode.setParentId(parentNode.getId());
childNode.setParent(parentNode);
innerBuild(treeNodes, childNode, deep + 1, maxDeep);
final Tree<E> parentNode = map.get(parentId);
if(null != parentNode){
parentNode.addChildren(node);
}
}
return rootTreeList;
}
/**
@@ -182,5 +168,4 @@ public class TreeUtil {
}
return result;
}
}

View File

@@ -243,7 +243,7 @@ public class NetUtil {
long cBegin = NetUtil.ipv4ToLong("192.168.0.0");
long cEnd = NetUtil.ipv4ToLong("192.168.255.255");
isInnerIp = isInner(ipNum, aBegin, aEnd) || isInner(ipNum, bBegin, bEnd) || isInner(ipNum, cBegin, cEnd) || ipAddress.equals(LOCAL_IP);
isInnerIp = isInner(ipNum, aBegin, aEnd) || isInner(ipNum, bBegin, bEnd) || isInner(ipNum, cBegin, cEnd) || LOCAL_IP.equals(ipAddress);
return isInnerIp;
}

View File

@@ -0,0 +1,64 @@
package cn.hutool.core.stream;
import cn.hutool.core.util.StrUtil;
import java.util.Collections;
import java.util.StringJoiner;
import java.util.function.Function;
import java.util.stream.Collector;
/**
* 可变的汇聚操作{@link Collector} 相关工具封装
*
* @author looly
* @since 5.6.7
*/
public class CollectorUtil {
/**
* 提供任意对象的Join操作的{@link Collector}实现对象默认调用toString方法
*
* @param delimiter 分隔符
* @param <T> 对象类型
* @return {@link Collector}
*/
public static <T> Collector<T, ?, String> joining(CharSequence delimiter) {
return joining(delimiter, Object::toString);
}
/**
* 提供任意对象的Join操作的{@link Collector}实现
*
* @param delimiter 分隔符
* @param toStringFunc 自定义指定对象转换为字符串的方法
* @param <T> 对象类型
* @return {@link Collector}
*/
public static <T> Collector<T, ?, String> joining(CharSequence delimiter,
Function<T, ? extends CharSequence> toStringFunc) {
return joining(delimiter, StrUtil.EMPTY, StrUtil.EMPTY, toStringFunc);
}
/**
* 提供任意对象的Join操作的{@link Collector}实现
*
* @param delimiter 分隔符
* @param prefix 前缀
* @param suffix 后缀
* @param toStringFunc 自定义指定对象转换为字符串的方法
* @param <T> 对象类型
* @return {@link Collector}
*/
public static <T> Collector<T, ?, String> joining(CharSequence delimiter,
CharSequence prefix,
CharSequence suffix,
Function<T, ? extends CharSequence> toStringFunc) {
return new SimpleCollector<>(
() -> new StringJoiner(delimiter, prefix, suffix),
(joiner, ele) -> joiner.add(toStringFunc.apply(ele)),
StringJoiner::merge,
StringJoiner::toString,
Collections.emptySet()
);
}
}

View File

@@ -0,0 +1,109 @@
package cn.hutool.core.stream;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;
/**
* 简单{@link Collector}接口实现
*
* @param <T> 输入数据类型
* @param <A> 累积结果的容器类型
* @param <R> 数据结果类型
* @since 5.6.7
*/
public class SimpleCollector<T, A, R> implements Collector<T, A, R> {
/**
* 创建新的结果容器容器类型为A
*/
private final Supplier<A> supplier;
/**
* 将输入元素合并到结果容器中
*/
private final BiConsumer<A, T> accumulator;
/**
* 合并两个结果容器(并行流使用,将多个线程产生的结果容器合并)
*/
private final BinaryOperator<A> combiner;
/**
* 将结果容器转换成最终的表示
*/
private final Function<A, R> finisher;
/**
* 特征值枚举,见{@link Characteristics}
* <ul>
* <li>CONCURRENT 表示结果容器只有一个(即使是在并行流的情况下)。
* 只有在并行流且收集器不具备此特性的情况下combiner()返回的lambda表达式才会执行中间结果容器只有一个就无需合并
* 设置此特性时意味着多个线程可以对同一个结果容器调用,因此结果容器必须是线程安全的。</li>
* <li>UNORDERED 表示流中的元素无序</li>
* <li>IDENTITY_FINISH表示中间结果容器类型与最终结果类型一致。设置此特性时finiser()方法不会被调用</li>
* </ul>
*/
private final Set<Characteristics> characteristics;
/**
* 构造
*
* @param supplier 创建新的结果容器函数
* @param accumulator 将输入元素合并到结果容器中函数
* @param combiner 合并两个结果容器函数(并行流使用,将多个线程产生的结果容器合并)
* @param finisher 将结果容器转换成最终的表示函数
* @param characteristics 特征值枚举
*/
public SimpleCollector(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;
}
/**
* 构造
*
* @param supplier 创建新的结果容器函数
* @param accumulator 将输入元素合并到结果容器中函数
* @param combiner 合并两个结果容器函数(并行流使用,将多个线程产生的结果容器合并)
* @param characteristics 特征值枚举
*/
@SuppressWarnings("unchecked")
public SimpleCollector(Supplier<A> supplier,
BiConsumer<A, T> accumulator,
BinaryOperator<A> combiner,
Set<Characteristics> characteristics) {
this(supplier, accumulator, combiner, i -> (R) i, 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;
}
}

View File

@@ -0,0 +1,144 @@
package cn.hutool.core.stream;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.CharsetUtil;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Spliterators;
import java.util.function.Function;
import java.util.function.UnaryOperator;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
/**
* {@link Stream} 工具类
*
* @author looly
* @since 5.6.7
*/
public class StreamUtil {
@SafeVarargs
public static <T> Stream<T> of(T... array) {
Assert.notNull(array, "Array must be not null!");
return Stream.of(array);
}
/**
* {@link Iterable}转换为{@link Stream},默认非并行
*
* @param iterable 集合
* @param <T> 集合元素类型
* @return {@link Stream}
*/
public static <T> Stream<T> of(Iterable<T> iterable) {
return of(iterable, false);
}
/**
* {@link Iterable}转换为{@link Stream}
*
* @param iterable 集合
* @param parallel 是否并行
* @param <T> 集合元素类型
* @return {@link Stream}
*/
public static <T> Stream<T> of(Iterable<T> iterable, boolean parallel) {
Assert.notNull(iterable, "Iterable must be not null!");
return StreamSupport.stream(
Spliterators.spliterator(CollUtil.toCollection(iterable), 0),
parallel);
}
/**
* 按行读取文件为{@link Stream}
*
* @param file 文件
* @return {@link Stream}
*/
public static Stream<String> of(File file) {
return of(file, CharsetUtil.CHARSET_UTF_8);
}
/**
* 按行读取文件为{@link Stream}
*
* @param path 路径
* @return {@link Stream}
*/
public static Stream<String> of(Path path) {
return of(path, CharsetUtil.CHARSET_UTF_8);
}
/**
* 按行读取文件为{@link Stream}
*
* @param file 文件
* @param charset 编码
* @return {@link Stream}
*/
public static Stream<String> of(File file, Charset charset) {
Assert.notNull(file, "File must be not null!");
return of(file.toPath(), charset);
}
/**
* 按行读取文件为{@link Stream}
*
* @param path 路径
* @param charset 编码
* @return {@link Stream}
*/
public static Stream<String> of(Path path, Charset charset) {
try {
return Files.lines(path, charset);
} catch (IOException e) {
throw new IORuntimeException(e);
}
}
/**
* 通过函数创建Stream
*
* @param seed 初始值
* @param elementCreator 递进函数,每次调用此函数获取下一个值
* @param limit 限制个数
* @param <T> 创建元素类型
* @return {@link Stream}
*/
public static <T> Stream<T> of(T seed, UnaryOperator<T> elementCreator, int limit) {
return Stream.iterate(seed, elementCreator).limit(limit);
}
/**
* 将Stream中所有元素以指定分隔符合并为一个字符串对象默认调用toString方法
*
* @param stream {@link Stream}
* @param delimiter 分隔符
* @param <T> 元素类型
* @return 字符串
*/
public static <T> String join(Stream<T> stream, CharSequence delimiter) {
return stream.collect(CollectorUtil.joining(delimiter));
}
/**
* 将Stream中所有元素以指定分隔符合并为一个字符串
*
* @param stream {@link Stream}
* @param delimiter 分隔符
* @param toStringFunc 元素转换为字符串的函数
* @param <T> 元素类型
* @return 字符串
*/
public static <T> String join(Stream<T> stream, CharSequence delimiter,
Function<T, ? extends CharSequence> toStringFunc) {
return stream.collect(CollectorUtil.joining(delimiter, toStringFunc));
}
}

View File

@@ -0,0 +1,7 @@
/**
* Java8的stream相关封装
*
* @author looly
*
*/
package cn.hutool.core.stream;

View File

@@ -1628,17 +1628,6 @@ public class CharSequenceUtil {
// ------------------------------------------------------------------------ split
/**
* 切分字符串
*
* @param str 被切分的字符串
* @param separator 分隔符字符
* @return 切分后的数组
*/
public static String[] splitToArray(CharSequence str, char separator) {
return splitToArray(str, separator, 0);
}
/**
* 切分字符串为long数组
*
@@ -1700,6 +1689,33 @@ public class CharSequenceUtil {
return split(str, separator, 0);
}
/**
* 切分字符串,如果分隔符不存在则返回原字符串
*
* @param str 被切分的字符串
* @param separator 分隔符
* @return 字符串
* @since 5.6.7
*/
public static String[] splitToArray(CharSequence str, CharSequence separator) {
if (str == null) {
return new String[]{};
}
return StrSpliter.splitToArray(str.toString(), str(separator), 0, false, false);
}
/**
* 切分字符串
*
* @param str 被切分的字符串
* @param separator 分隔符字符
* @return 切分后的数组
*/
public static String[] splitToArray(CharSequence str, char separator) {
return splitToArray(str, separator, 0);
}
/**
* 切分字符串
*
@@ -1809,6 +1825,20 @@ public class CharSequenceUtil {
return StrSpliter.split(str.toString(), separator, limit, isTrim, ignoreEmpty);
}
/**
* 切分字符串
*
* @param str 被切分的字符串
* @param separator 分隔符字符
* @param isTrim 是否去除切分字符串后每个元素两边的空格
* @param ignoreEmpty 是否忽略空串
* @return 切分后的集合
* @since 5.6.7
*/
public static List<String> split(CharSequence str, CharSequence separator, boolean isTrim, boolean ignoreEmpty) {
return split(str, separator, 0, isTrim, ignoreEmpty);
}
/**
* 切分字符串
*
@@ -1834,14 +1864,11 @@ public class CharSequenceUtil {
* @param str 被切分的字符串
* @param separator 分隔符
* @return 字符串
* @deprecated 请使用 {@link #splitToArray(CharSequence, char)}
*/
@Deprecated
public static String[] split(CharSequence str, CharSequence separator) {
if (str == null) {
return new String[]{};
}
final String separatorStr = (null == separator) ? null : separator.toString();
return StrSpliter.splitToArray(str.toString(), separatorStr, 0, false, false);
return splitToArray(str, separator);
}
/**
@@ -4237,6 +4264,7 @@ public class CharSequenceUtil {
/**
* 以 conjunction 为分隔符将多个对象转换为字符串
*
* @param <T> 元素类型
* @param conjunction 分隔符
* @param iterable 集合
* @return 连接后的字符串

View File

@@ -12,7 +12,7 @@ import java.util.regex.Pattern;
/**
* 字符串切分器
*
*x
* @author Looly
*/
public class StrSpliter {

View File

@@ -30,27 +30,33 @@ public class CsvConfig implements Serializable {
* 设置字段分隔符,默认逗号','
*
* @param fieldSeparator 字段分隔符,默认逗号','
* @return this
*/
public void setFieldSeparator(final char fieldSeparator) {
public CsvConfig setFieldSeparator(final char fieldSeparator) {
this.fieldSeparator = fieldSeparator;
return this;
}
/**
* 设置 文本分隔符,文本包装符,默认双引号'"'
*
* @param textDelimiter 文本分隔符,文本包装符,默认双引号'"'
* @return this
*/
public void setTextDelimiter(char textDelimiter) {
public CsvConfig setTextDelimiter(char textDelimiter) {
this.textDelimiter = textDelimiter;
return this;
}
/**
* 设置 注释符号,用于区分注释行
*
* @param commentCharacter 注释符号,用于区分注释行
* @return this
* @since 5.5.7
*/
public void setCommentCharacter(char commentCharacter) {
public CsvConfig setCommentCharacter(char commentCharacter) {
this.commentCharacter = commentCharacter;
return this;
}
}

View File

@@ -31,26 +31,32 @@ public class CsvReadConfig extends CsvConfig implements Serializable {
* 设置是否首行做为标题行默认false
*
* @param containsHeader 是否首行做为标题行默认false
* @return this
*/
public void setContainsHeader(boolean containsHeader) {
public CsvReadConfig setContainsHeader(boolean containsHeader) {
this.containsHeader = containsHeader;
return this;
}
/**
* 设置是否跳过空白行默认true
*
* @param skipEmptyRows 是否跳过空白行默认true
* @return this
*/
public void setSkipEmptyRows(boolean skipEmptyRows) {
public CsvReadConfig setSkipEmptyRows(boolean skipEmptyRows) {
this.skipEmptyRows = skipEmptyRows;
return this;
}
/**
* 设置每行字段个数不同时是否抛出异常默认false
*
* @param errorOnDifferentFieldCount 每行字段个数不同时是否抛出异常默认false
* @return this
*/
public void setErrorOnDifferentFieldCount(boolean errorOnDifferentFieldCount) {
public CsvReadConfig setErrorOnDifferentFieldCount(boolean errorOnDifferentFieldCount) {
this.errorOnDifferentFieldCount = errorOnDifferentFieldCount;
return this;
}
}

View File

@@ -1,21 +1,24 @@
package cn.hutool.core.text.csv;
import java.io.Serializable;
import cn.hutool.core.util.CharUtil;
import java.io.Serializable;
/**
* CSV写出配置项
*
* @author looly
*
*/
public class CsvWriteConfig extends CsvConfig implements Serializable {
private static final long serialVersionUID = 5396453565371560052L;
/** 是否始终使用文本分隔符文本包装符默认false按需添加 */
/**
* 是否始终使用文本分隔符文本包装符默认false按需添加
*/
protected boolean alwaysDelimitText;
/** 换行符 */
/**
* 换行符
*/
protected char[] lineDelimiter = {CharUtil.CR, CharUtil.LF};
/**
@@ -31,17 +34,21 @@ public class CsvWriteConfig extends CsvConfig implements Serializable {
* 设置是否始终使用文本分隔符文本包装符默认false按需添加
*
* @param alwaysDelimitText 是否始终使用文本分隔符文本包装符默认false按需添加
* @return this
*/
public void setAlwaysDelimitText(boolean alwaysDelimitText) {
public CsvWriteConfig setAlwaysDelimitText(boolean alwaysDelimitText) {
this.alwaysDelimitText = alwaysDelimitText;
return this;
}
/**
* 设置换行符
*
* @param lineDelimiter 换行符
* @return this
*/
public void setLineDelimiter(char[] lineDelimiter) {
public CsvWriteConfig setLineDelimiter(char[] lineDelimiter) {
this.lineDelimiter = lineDelimiter;
return this;
}
}

View File

@@ -12,6 +12,7 @@ import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
/**
* 线程池工具
@@ -366,6 +367,19 @@ public class ThreadUtil {
}
}
/**
* 创建本地线程对象
*
* @param <T> 持有对象类型
* @param supplier 初始化线程对象函数
* @return 本地线程
* @see ThreadLocal#withInitial(Supplier)
* @since 5.6.7
*/
public static <T> ThreadLocal<T> createThreadLocal(Supplier<? extends T> supplier) {
return ThreadLocal.withInitial(supplier);
}
/**
* 创建ThreadFactoryBuilder
*
@@ -562,20 +576,19 @@ public class ThreadUtil {
* <li>fixedDelay模式下一次任务不等待上一次任务到周期自动执行。</li>
* </ul>
*
*
* @param executor 定时任务线程池,{@code null}新建一个默认线程池
* @param command 需要定时执行的逻辑
* @param initialDelay 初始延迟,单位毫秒
* @param period 执行周期,单位毫秒
* @param executor 定时任务线程池,{@code null}新建一个默认线程池
* @param command 需要定时执行的逻辑
* @param initialDelay 初始延迟,单位毫秒
* @param period 执行周期,单位毫秒
* @param fixedRateOrFixedDelay {@code true}表示fixedRate模式{@code false}表示fixedDelay模式
* @return {@link ScheduledThreadPoolExecutor}
* @since 5.5.8
*/
public static ScheduledThreadPoolExecutor schedule(ScheduledThreadPoolExecutor executor,
Runnable command,
long initialDelay,
long period,
boolean fixedRateOrFixedDelay){
Runnable command,
long initialDelay,
long period,
boolean fixedRateOrFixedDelay) {
return schedule(executor, command, initialDelay, period, TimeUnit.MILLISECONDS, fixedRateOrFixedDelay);
}
@@ -587,12 +600,11 @@ public class ThreadUtil {
* <li>fixedDelay模式下一次任务不等待上一次任务到周期自动执行。</li>
* </ul>
*
*
* @param executor 定时任务线程池,{@code null}新建一个默认线程池
* @param command 需要定时执行的逻辑
* @param initialDelay 初始延迟
* @param period 执行周期
* @param timeUnit 时间单位
* @param executor 定时任务线程池,{@code null}新建一个默认线程池
* @param command 需要定时执行的逻辑
* @param initialDelay 初始延迟
* @param period 执行周期
* @param timeUnit 时间单位
* @param fixedRateOrFixedDelay {@code true}表示fixedRate模式{@code false}表示fixedDelay模式
* @return {@link ScheduledThreadPoolExecutor}
* @since 5.6.5
@@ -602,13 +614,13 @@ public class ThreadUtil {
long initialDelay,
long period,
TimeUnit timeUnit,
boolean fixedRateOrFixedDelay){
if(null == executor){
boolean fixedRateOrFixedDelay) {
if (null == executor) {
executor = createScheduledExecutor(2);
}
if(fixedRateOrFixedDelay){
if (fixedRateOrFixedDelay) {
executor.scheduleAtFixedRate(command, initialDelay, period, timeUnit);
} else{
} else {
executor.scheduleWithFixedDelay(command, initialDelay, period, timeUnit);
}

View File

@@ -1203,31 +1203,6 @@ public class ArrayUtil extends PrimitiveArrayUtil {
return sb.toString();
}
/**
* 以 conjunction 为分隔符将数组转换为字符串
*
* @param array 数组
* @param conjunction 分隔符
* @return 连接后的字符串
*/
public static String join(long[] array, CharSequence conjunction) {
if (null == array) {
return null;
}
final StringBuilder sb = new StringBuilder();
boolean isFirst = true;
for (long item : array) {
if (isFirst) {
isFirst = false;
} else {
sb.append(conjunction);
}
sb.append(item);
}
return sb.toString();
}
/**
* 以 conjunction 为分隔符将数组转换为字符串
*

View File

@@ -387,7 +387,6 @@ public class IdcardUtil {
// 首字母A-ZA表示1以此类推
char start = idcard.charAt(0);
int iStart = start - 'A' + 1;
String mid = card.substring(1, 7);
String end = card.substring(7, 8);
char[] chars = mid.toCharArray();

View File

@@ -356,11 +356,11 @@ public class ObjectUtil {
* 如果给定对象为{@code null}或者""或者空白符返回默认值
*
* <pre>
* ObjectUtil.defaultIfEmpty(null, null) = null
* ObjectUtil.defaultIfEmpty(null, "") = ""
* ObjectUtil.defaultIfEmpty("", "zz") = "zz"
* ObjectUtil.defaultIfEmpty(" ", "zz") = "zz"
* ObjectUtil.defaultIfEmpty("abc", *) = "abc"
* ObjectUtil.defaultIfBlank(null, null) = null
* ObjectUtil.defaultIfBlank(null, "") = ""
* ObjectUtil.defaultIfBlank("", "zz") = "zz"
* ObjectUtil.defaultIfBlank(" ", "zz") = "zz"
* ObjectUtil.defaultIfBlank("abc", *) = "abc"
* </pre>
*
* @param <T> 对象类型必须实现CharSequence接口

View File

@@ -1613,6 +1613,31 @@ public class PrimitiveArrayUtil {
return sb.toString();
}
/**
* 以 conjunction 为分隔符将数组转换为字符串
*
* @param array 数组
* @param conjunction 分隔符
* @return 连接后的字符串
*/
public static String join(long[] array, CharSequence conjunction) {
if (null == array) {
return null;
}
final StringBuilder sb = new StringBuilder();
boolean isFirst = true;
for (long item : array) {
if (isFirst) {
isFirst = false;
} else {
sb.append(conjunction);
}
sb.append(item);
}
return sb.toString();
}
/**
* 以 conjunction 为分隔符将数组转换为字符串
*
@@ -2038,7 +2063,6 @@ public class PrimitiveArrayUtil {
}
int i = Math.max(startIndexInclusive, 0);
int j = Math.min(array.length, endIndexExclusive) - 1;
long tmp;
while (j > i) {
swap(array, i, j);
j--;
@@ -2073,7 +2097,6 @@ public class PrimitiveArrayUtil {
}
int i = Math.max(startIndexInclusive, 0);
int j = Math.min(array.length, endIndexExclusive) - 1;
int tmp;
while (j > i) {
swap(array, i, j);
j--;
@@ -2108,7 +2131,6 @@ public class PrimitiveArrayUtil {
}
int i = Math.max(startIndexInclusive, 0);
int j = Math.min(array.length, endIndexExclusive) - 1;
short tmp;
while (j > i) {
swap(array, i, j);
j--;
@@ -2143,7 +2165,6 @@ public class PrimitiveArrayUtil {
}
int i = Math.max(startIndexInclusive, 0);
int j = Math.min(array.length, endIndexExclusive) - 1;
char tmp;
while (j > i) {
swap(array, i, j);
j--;
@@ -2178,7 +2199,6 @@ public class PrimitiveArrayUtil {
}
int i = Math.max(startIndexInclusive, 0);
int j = Math.min(array.length, endIndexExclusive) - 1;
byte tmp;
while (j > i) {
swap(array, i, j);
j--;
@@ -2213,7 +2233,6 @@ public class PrimitiveArrayUtil {
}
int i = Math.max(startIndexInclusive, 0);
int j = Math.min(array.length, endIndexExclusive) - 1;
double tmp;
while (j > i) {
swap(array, i, j);
j--;
@@ -2248,7 +2267,6 @@ public class PrimitiveArrayUtil {
}
int i = Math.max(startIndexInclusive, 0);
int j = Math.min(array.length, endIndexExclusive) - 1;
float tmp;
while (j > i) {
swap(array, i, j);
j--;
@@ -2283,7 +2301,6 @@ public class PrimitiveArrayUtil {
}
int i = Math.max(startIndexInclusive, 0);
int j = Math.min(array.length, endIndexExclusive) - 1;
boolean tmp;
while (j > i) {
swap(array, i, j);
j--;

View File

@@ -54,8 +54,7 @@ public class RadixUtil {
public static String encode(final String radixs, final int num) {
//考虑到负数问题
long tmpNum = (num >= 0 ? num : (0x100000000L - (~num + 1)));
return encode(radixs, num, 32);
return encode(radixs, tmpNum, 32);
}
/**
@@ -73,7 +72,7 @@ public class RadixUtil {
return encode(radixs, num, 64);
}
private static String encode(final String radixs, final long num, int maxLength) {
private static String encode(final String radixs, long num, int maxLength) {
if (radixs.length() < 2) {
throw new RuntimeException("自定义进制最少两个字符哦!");
}

View File

@@ -2,6 +2,7 @@ package cn.hutool.core.util;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.text.StrBuilder;
import java.io.File;
import java.io.IOException;
@@ -9,6 +10,7 @@ import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
/**
* 系统运行时工具类,用于执行系统命令的工具
@@ -74,22 +76,9 @@ public class RuntimeUtil {
* @return {@link Process}
*/
public static Process exec(String... cmds) {
if (ArrayUtil.isEmpty(cmds)) {
throw new NullPointerException("Command is empty !");
}
// 单条命令的情况
if (1 == cmds.length) {
final String cmd = cmds[0];
if (StrUtil.isBlank(cmd)) {
throw new NullPointerException("Command is empty !");
}
cmds = StrUtil.splitToArray(cmd, StrUtil.C_SPACE);
}
Process process;
try {
process = new ProcessBuilder(cmds).redirectErrorStream(true).start();
process = new ProcessBuilder(handleCmds(cmds)).redirectErrorStream(true).start();
} catch (IOException e) {
throw new IORuntimeException(e);
}
@@ -120,20 +109,8 @@ public class RuntimeUtil {
* @since 4.1.6
*/
public static Process exec(String[] envp, File dir, String... cmds) {
if (ArrayUtil.isEmpty(cmds)) {
throw new NullPointerException("Command is empty !");
}
// 单条命令的情况
if (1 == cmds.length) {
final String cmd = cmds[0];
if (StrUtil.isBlank(cmd)) {
throw new NullPointerException("Command is empty !");
}
cmds = StrUtil.splitToArray(cmd, StrUtil.C_SPACE);
}
try {
return Runtime.getRuntime().exec(cmds, envp, dir);
return Runtime.getRuntime().exec(handleCmds(cmds), envp, dir);
} catch (IOException e) {
throw new IORuntimeException(e);
}
@@ -301,4 +278,80 @@ public class RuntimeUtil {
public static long getUsableMemory() {
return getMaxMemory() - getTotalMemory() + getFreeMemory();
}
/**
* 处理命令,多行命令原样返回,单行命令拆分处理
* @param cmds 命令
* @return 处理后的命令
*/
private static String[] handleCmds(String... cmds){
if (ArrayUtil.isEmpty(cmds)) {
throw new NullPointerException("Command is empty !");
}
// 单条命令的情况
if (1 == cmds.length) {
final String cmd = cmds[0];
if (StrUtil.isBlank(cmd)) {
throw new NullPointerException("Command is blank !");
}
cmds = cmdSplit(cmd);
}
return cmds;
}
/**
* 命令分割,使用空格分割,考虑双引号和单引号的情况
*
* @param cmd 命令,如 git commit -m 'test commit'
* @return 分割后的命令
*/
private static String[] cmdSplit(String cmd){
final List<String> cmds = new ArrayList<>();
final int length = cmd.length();
final Stack<Character> stack = new Stack<>();
boolean inWrap = false;
final StrBuilder cache = StrUtil.strBuilder();
char c;
for (int i = 0; i < length; i++) {
c = cmd.charAt(i);
switch (c){
case CharUtil.SINGLE_QUOTE:
case CharUtil.DOUBLE_QUOTES:
if(inWrap){
if(c == stack.peek()){
//结束包装
stack.pop();
inWrap = false;
}
cache.append(c);
} else{
stack.push(c);
cache.append(c);
inWrap = true;
}
break;
case CharUtil.SPACE:
if(inWrap){
// 处于包装内
cache.append(c);
} else{
cmds.add(cache.toString());
cache.reset();
}
break;
default:
cache.append(c);
break;
}
}
if(cache.hasContent()){
cmds.add(cache.toString());
}
return cmds.toArray(new String[0]);
}
}

View File

@@ -1508,7 +1508,7 @@ public class XmlUtil {
*/
@Override
public String getNamespaceURI(String prefix) {
if (prefix == null || prefix.equals(XMLConstants.DEFAULT_NS_PREFIX)) {
if (prefix == null || XMLConstants.DEFAULT_NS_PREFIX.equals(prefix)) {
return prefixUri.get(DEFAULT_NS);
} else {
return prefixUri.get(prefix);

View File

@@ -660,7 +660,6 @@ public class ZipUtil {
public static void read(ZipInputStream zipStream, Consumer<ZipEntry> consumer) {
try {
ZipEntry zipEntry;
File outItemFile;
while (null != (zipEntry = zipStream.getNextEntry())) {
consumer.accept(zipEntry);
}

View File

@@ -164,7 +164,7 @@ public class BeanUtilTest {
public void mapToBeanWinErrorTest() {
Map<String, String> map = new HashMap<>();
map.put("age", "哈哈");
Person user = BeanUtil.toBean(map, Person.class);
BeanUtil.toBean(map, Person.class);
}
@Test
@@ -559,7 +559,6 @@ public class BeanUtilTest {
@Test
public void toMapTest() {
// 测试转map的时候返回key
String name = null;
PrivilegeIClassification a = new PrivilegeIClassification();
a.setId("1");
a.setName("2");

View File

@@ -23,6 +23,16 @@ public class Base64Test {
Assert.assertEquals(a, decodeStr);
}
@Test
public void encodeAndDecodeWithoutPaddingTest() {
String a = "伦家是一个非常长的字符串66";
String encode = Base64.encodeWithoutPadding(StrUtil.utf8Bytes(a));
Assert.assertEquals("5Lym5a625piv5LiA5Liq6Z2e5bi46ZW/55qE5a2X56ym5LiyNjY", encode);
String decodeStr = Base64.decodeStr(encode);
Assert.assertEquals(a, decodeStr);
}
@Test
public void encodeAndDecodeTest2() {
String a = "a61a5db5a67c01445ca2-HZ20181120172058/pdf/中国电信影像云单体网关Docker版-V1.2.pdf";

View File

@@ -102,7 +102,7 @@ public class CollUtilTest {
Collection<String> union = CollUtil.union(list1, list2);
Assert.assertEquals(3, CollUtil.count(union, t -> t.equals("b")));
Assert.assertEquals(3, CollUtil.count(union, t -> "b".equals(t)));
}
@Test
@@ -111,7 +111,7 @@ public class CollUtilTest {
ArrayList<String> list2 = CollUtil.newArrayList("a", "b", "b", "b", "c", "d");
Collection<String> intersection = CollUtil.intersection(list1, list2);
Assert.assertEquals(2, CollUtil.count(intersection, t -> t.equals("b")));
Assert.assertEquals(2, CollUtil.count(intersection, t -> "b".equals(t)));
}
@Test
@@ -236,7 +236,7 @@ public class CollUtilTest {
final String[] result = new String[1];
CollUtil.forEach(map, (key, value, index) -> {
if (key.equals("a")) {
if ("a".equals(key)) {
result[0] = value;
}
});

View File

@@ -3,7 +3,6 @@ package cn.hutool.core.date;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.BetweenFormatter.Level;
import cn.hutool.core.date.format.FastDateFormat;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.RandomUtil;
import org.junit.Assert;
import org.junit.Test;

View File

@@ -13,6 +13,8 @@ import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
public class ImgUtilTest {
@@ -136,4 +138,11 @@ public class ImgUtilTest {
new File("d:/test/3.jpg"),
new Color(200, 0, 0), 10);
}
@Test
public void getMainColor() throws MalformedURLException {
BufferedImage read = ImgUtil.read(new URL("https://pic2.zhimg.com/v2-94f5552f2b142ff575306850c5bab65d_b.png"));
String mainColor = ImgUtil.getMainColor(read, new int[]{64,84,116});
System.out.println(mainColor);
}
}

View File

@@ -18,8 +18,8 @@ public class TreeTest {
static {
// 模拟数据
nodeList.add(new TreeNode<>("1", "0", "系统管理", 5));
nodeList.add(new TreeNode<>("11", "1", "用户管理", 222222));
nodeList.add(new TreeNode<>("111", "11", "用户添加", 0));
nodeList.add(new TreeNode<>("11", "1", "用户管理", 222222));
nodeList.add(new TreeNode<>("2", "0", "店铺管理", 1));
nodeList.add(new TreeNode<>("21", "2", "商品管理", 44));
@@ -33,6 +33,7 @@ public class TreeTest {
for (Tree<String> tree : treeList) {
Assert.assertNotNull(tree);
Assert.assertEquals("0", tree.getParentId());
// Console.log(tree);
}
// 测试通过子节点查找父节点

View File

@@ -0,0 +1,16 @@
package cn.hutool.core.stream;
import org.junit.Assert;
import org.junit.Test;
import java.util.stream.Stream;
public class StreamUtilTest {
@Test
public void ofTest(){
final Stream<Integer> stream = StreamUtil.of(2, x -> x * 2, 4);
final String result = stream.collect(CollectorUtil.joining(","));
Assert.assertEquals("2,4,8,16", result);
}
}

View File

@@ -85,4 +85,16 @@ public class CsvReaderTest {
Console.log(strings);
}
}
@Test
@Ignore
public void readTest3(){
final CsvReadConfig csvReadConfig = CsvReadConfig.defaultConfig();
csvReadConfig.setContainsHeader(true);
final CsvReader reader = CsvUtil.getReader(csvReadConfig);
final CsvData read = reader.read(FileUtil.file("d:/test/ceshi.csv"));
for (CsvRow row : read) {
Console.log(row.getByName("案件ID"));
}
}
}

View File

@@ -29,7 +29,7 @@ public class RuntimeUtilTest {
@Test
@Ignore
public void execCmdTest2() {
String str = RuntimeUtil.execForStr("cmd /c cd C:\\Program Files (x86)");
String str = RuntimeUtil.execForStr("cmd /c", "cd \"C:\\Program Files (x86)\"", "chdir");
Console.log(str);
}

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.6.7-SNAPSHOT</version>
<version>5.6.8-SNAPSHOT</version>
</parent>
<artifactId>hutool-cron</artifactId>

View File

@@ -47,7 +47,6 @@ public class TaskListenerManager implements Serializable {
*/
public void notifyTaskStart(TaskExecutor executor) {
synchronized (listeners) {
int size = listeners.size();
TaskListener listener;
for (TaskListener taskListener : listeners) {
listener = taskListener;
@@ -64,7 +63,6 @@ public class TaskListenerManager implements Serializable {
*/
public void notifyTaskSucceeded(TaskExecutor executor) {
synchronized (listeners) {
int size = listeners.size();
for (TaskListener listener : listeners) {
listener.onSucceeded(executor);
}

View File

@@ -76,7 +76,7 @@ public class TimerTaskList implements Delayed {
*/
public void removeTask(TimerTask timerTask) {
synchronized (this) {
if (timerTask.timerTaskList.equals(this)) {
if (this.equals(timerTask.timerTaskList)) {
timerTask.next.prev = timerTask.prev;
timerTask.prev.next = timerTask.next;
timerTask.timerTaskList = null;

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.6.7-SNAPSHOT</version>
<version>5.6.8-SNAPSHOT</version>
</parent>
<artifactId>hutool-crypto</artifactId>

View File

@@ -247,7 +247,7 @@ public class SymmetricCrypto implements Serializable {
}
/**
* 加密,针对大数据量,结束后关闭流
* 加密,针对大数据量,可选结束后是否关闭流
*
* @param data 被加密的字符串
* @param out 输出流,可以是文件或网络位置

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.6.7-SNAPSHOT</version>
<version>5.6.8-SNAPSHOT</version>
</parent>
<artifactId>hutool-db</artifactId>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.6.7-SNAPSHOT</version>
<version>5.6.8-SNAPSHOT</version>
</parent>
<artifactId>hutool-dfa</artifactId>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.6.7-SNAPSHOT</version>
<version>5.6.8-SNAPSHOT</version>
</parent>
<artifactId>hutool-extra</artifactId>

View File

@@ -42,10 +42,11 @@ public enum BeanCopierCache {
* @return 属性名和Map映射的key
*/
private String genKey(Class<?> srcClass, Class<?> targetClass, Converter converter) {
String key = StrUtil.format("{}#{}", srcClass.getName(), targetClass.getName());
final StringBuilder key = StrUtil.builder()
.append(srcClass.getName()).append('#').append(targetClass.getName());
if(null != converter){
key += "#" + converter.getClass().getName();
key.append('#').append(converter.getClass().getName());
}
return key;
return key.toString();
}
}

View File

@@ -339,7 +339,7 @@ public class Sftp extends AbstractFtp {
return true;
}
try {
channel.cd(directory.replaceAll("\\\\", "/"));
channel.cd(directory.replace('\\', '/'));
return true;
} catch (SftpException e) {
throw new FtpException(e);

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.6.7-SNAPSHOT</version>
<version>5.6.8-SNAPSHOT</version>
</parent>
<artifactId>hutool-http</artifactId>

View File

@@ -387,7 +387,7 @@ public class HttpRequest extends HttpBase<HttpRequest> {
public boolean isKeepAlive() {
String connection = header(Header.CONNECTION);
if (connection == null) {
return !httpVersion.equalsIgnoreCase(HTTP_1_0);
return !HTTP_1_0.equalsIgnoreCase(httpVersion);
}
return false == "close".equalsIgnoreCase(connection);
@@ -552,7 +552,7 @@ public class HttpRequest extends HttpBase<HttpRequest> {
}
/**
* 设置map<String, String>类型表单数据
* 设置map&lt;String, String&gt;类型表单数据
*
* @param formMapStr 表单内容
* @return this

View File

@@ -109,7 +109,7 @@ public class Platform extends UserAgentInfo {
* @since 5.2.3
*/
public boolean isIPhoneOrIPod() {
return IPHONE.equals(this) || IPOD.equals(this);
return this.equals(IPHONE) || this.equals(IPOD);
}
/**
@@ -119,7 +119,7 @@ public class Platform extends UserAgentInfo {
* @since 5.2.3
*/
public boolean isIPad() {
return IPAD.equals(this);
return this.equals(IPAD);
}
/**
@@ -139,7 +139,7 @@ public class Platform extends UserAgentInfo {
* @since 5.2.3
*/
public boolean isAndroid() {
return ANDROID.equals(this) || GOOGLE_TV.equals(this);
return this.equals(ANDROID) || this.equals(GOOGLE_TV);
}
}

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.6.7-SNAPSHOT</version>
<version>5.6.8-SNAPSHOT</version>
</parent>
<artifactId>hutool-json</artifactId>

View File

@@ -675,14 +675,12 @@ public class JSONUtil {
return writer;
}
char b; // 前一个字符
char c; // 当前字符
int len = str.length();
if (isWrap) {
writer.write('"');
}
for (int i = 0; i < len; i++) {
// b = c;
c = str.charAt(i);
switch (c) {
case '\\':
@@ -690,13 +688,6 @@ public class JSONUtil {
writer.write("\\");
writer.write(c);
break;
//此处转义导致输出不和预期一致
// case '/':
// if (b == '<') {
// writer.write('\\');
// }
// writer.write(c);
// break;
default:
writer.write(escape(c));
}

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.6.7-SNAPSHOT</version>
<version>5.6.8-SNAPSHOT</version>
</parent>
<artifactId>hutool-log</artifactId>

View File

@@ -8,7 +8,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.6.7-SNAPSHOT</version>
<version>5.6.8-SNAPSHOT</version>
</parent>
<artifactId>hutool-poi</artifactId>

View File

@@ -21,16 +21,26 @@ import java.io.InputStream;
* Excel工具类,不建议直接使用index直接操作sheet在wps/excel中sheet显示顺序与index无关还有隐藏sheet
*
* @author Looly
*
*/
public class ExcelUtil {
/**
* xlx的ContentType
*/
public static final String XLS_CONTENT_TYPE = "application/vnd.ms-excel";
/**
* xlsx的ContentType
*/
public static final String XLSX_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
// ------------------------------------------------------------------------------------ Read by Sax start
/**
* 通过Sax方式读取Excel同时支持03和07格式
*
* @param path Excel文件路径
* @param rid sheet rid-1表示全部Sheet, 0表示第一个Sheet
* @param path Excel文件路径
* @param rid sheet rid-1表示全部Sheet, 0表示第一个Sheet
* @param rowHandler 行处理器
* @since 3.2.0
*/
@@ -41,8 +51,8 @@ public class ExcelUtil {
/**
* 通过Sax方式读取Excel同时支持03和07格式
*
* @param path Excel文件路径
* @param idOrRid Excel中的sheet id或者rid编号rid必须加rId前缀例如rId1如果为-1处理所有编号的sheet
* @param path Excel文件路径
* @param idOrRid Excel中的sheet id或者rid编号rid必须加rId前缀例如rId1如果为-1处理所有编号的sheet
* @param rowHandler 行处理器
* @since 5.4.4
*/
@@ -53,8 +63,8 @@ public class ExcelUtil {
/**
* 通过Sax方式读取Excel同时支持03和07格式
*
* @param file Excel文件
* @param rid sheet rid-1表示全部Sheet, 0表示第一个Sheet
* @param file Excel文件
* @param rid sheet rid-1表示全部Sheet, 0表示第一个Sheet
* @param rowHandler 行处理器
* @since 3.2.0
*/
@@ -66,8 +76,8 @@ public class ExcelUtil {
/**
* 通过Sax方式读取Excel同时支持03和07格式
*
* @param file Excel文件
* @param idOrRid Excel中的sheet id或者rid编号rid必须加rId前缀例如rId1如果为-1处理所有编号的sheet
* @param file Excel文件
* @param idOrRid Excel中的sheet id或者rid编号rid必须加rId前缀例如rId1如果为-1处理所有编号的sheet
* @param rowHandler 行处理器
* @since 5.4.4
*/
@@ -79,8 +89,8 @@ public class ExcelUtil {
/**
* 通过Sax方式读取Excel同时支持03和07格式
*
* @param in Excel流
* @param rid sheet rid-1表示全部Sheet, 0表示第一个Sheet
* @param in Excel流
* @param rid sheet rid-1表示全部Sheet, 0表示第一个Sheet
* @param rowHandler 行处理器
* @since 3.2.0
*/
@@ -93,8 +103,8 @@ public class ExcelUtil {
/**
* 通过Sax方式读取Excel同时支持03和07格式
*
* @param in Excel流
* @param idOrRid Excel中的sheet id或者rid编号rid必须加rId前缀例如rId1如果为-1处理所有编号的sheet
* @param in Excel流
* @param idOrRid Excel中的sheet id或者rid编号rid必须加rId前缀例如rId1如果为-1处理所有编号的sheet
* @param rowHandler 行处理器
* @since 5.4.4
*/
@@ -107,8 +117,8 @@ public class ExcelUtil {
/**
* Sax方式读取Excel07
*
* @param in 输入流
* @param rid Sheet rid-1表示全部Sheet, 0表示第一个Sheet
* @param in 输入流
* @param rid Sheet rid-1表示全部Sheet, 0表示第一个Sheet
* @param rowHandler 行处理器
* @return {@link Excel07SaxReader}
* @since 3.2.0
@@ -126,8 +136,8 @@ public class ExcelUtil {
/**
* Sax方式读取Excel07
*
* @param file 文件
* @param rid Sheet rid-1表示全部Sheet, 0表示第一个Sheet
* @param file 文件
* @param rid Sheet rid-1表示全部Sheet, 0表示第一个Sheet
* @param rowHandler 行处理器
* @return {@link Excel07SaxReader}
* @since 3.2.0
@@ -145,8 +155,8 @@ public class ExcelUtil {
/**
* Sax方式读取Excel07
*
* @param path 路径
* @param rid Sheet rid-1表示全部Sheet, 0表示第一个Sheet
* @param path 路径
* @param rid Sheet rid-1表示全部Sheet, 0表示第一个Sheet
* @param rowHandler 行处理器
* @return {@link Excel07SaxReader}
* @since 3.2.0
@@ -164,7 +174,7 @@ public class ExcelUtil {
/**
* Sax方式读取Excel03
*
* @param in 输入流
* @param in 输入流
* @param sheetIndex Sheet索引-1表示全部Sheet, 0表示第一个Sheet
* @param rowHandler 行处理器
* @return {@link Excel03SaxReader}
@@ -183,7 +193,7 @@ public class ExcelUtil {
/**
* Sax方式读取Excel03
*
* @param file 文件
* @param file 文件
* @param sheetIndex Sheet索引-1表示全部Sheet, 0表示第一个Sheet
* @param rowHandler 行处理器
* @return {@link Excel03SaxReader}
@@ -202,7 +212,7 @@ public class ExcelUtil {
/**
* Sax方式读取Excel03
*
* @param path 路径
* @param path 路径
* @param sheetIndex Sheet索引-1表示全部Sheet, 0表示第一个Sheet
* @param rowHandler 行处理器
* @return {@link Excel03SaxReader}
@@ -220,6 +230,7 @@ public class ExcelUtil {
// ------------------------------------------------------------------------------------ Read by Sax end
// ------------------------------------------------------------------------------------------------ getReader
/**
* 获取Excel读取器通过调用{@link ExcelReader}的read或readXXX方法读取Excel内容<br>
* 默认调用第一个sheet
@@ -247,7 +258,7 @@ public class ExcelUtil {
* 获取Excel读取器通过调用{@link ExcelReader}的read或readXXX方法读取Excel内容
*
* @param bookFilePath Excel文件路径绝对路径或相对于ClassPath路径
* @param sheetIndex sheet序号0表示第一个sheet
* @param sheetIndex sheet序号0表示第一个sheet
* @return {@link ExcelReader}
* @since 3.1.1
*/
@@ -262,7 +273,7 @@ public class ExcelUtil {
/**
* 获取Excel读取器通过调用{@link ExcelReader}的read或readXXX方法读取Excel内容
*
* @param bookFile Excel文件
* @param bookFile Excel文件
* @param sheetIndex sheet序号0表示第一个sheet
* @return {@link ExcelReader}
*/
@@ -277,7 +288,7 @@ public class ExcelUtil {
/**
* 获取Excel读取器通过调用{@link ExcelReader}的read或readXXX方法读取Excel内容
*
* @param bookFile Excel文件
* @param bookFile Excel文件
* @param sheetName sheet名第一个默认是sheet1
* @return {@link ExcelReader}
*/
@@ -304,7 +315,7 @@ public class ExcelUtil {
* 获取Excel读取器通过调用{@link ExcelReader}的read或readXXX方法读取Excel内容<br>
* 默认调用第一个sheet
*
* @param bookStream Excel文件的流
* @param bookStream Excel文件的流
* @param closeAfterRead 读取结束是否关闭流
* @return {@link ExcelReader}
* @since 4.0.3
@@ -336,8 +347,8 @@ public class ExcelUtil {
/**
* 获取Excel读取器通过调用{@link ExcelReader}的read或readXXX方法读取Excel内容
*
* @param bookStream Excel文件的流
* @param sheetIndex sheet序号0表示第一个sheet
* @param bookStream Excel文件的流
* @param sheetIndex sheet序号0表示第一个sheet
* @param closeAfterRead 读取结束是否关闭流
* @return {@link ExcelReader}
* @since 4.0.3
@@ -357,7 +368,7 @@ public class ExcelUtil {
* 读取结束自动关闭流
*
* @param bookStream Excel文件的流
* @param sheetName sheet名第一个默认是sheet1
* @param sheetName sheet名第一个默认是sheet1
* @return {@link ExcelReader}
*/
public static ExcelReader getReader(InputStream bookStream, String sheetName) {
@@ -371,8 +382,8 @@ public class ExcelUtil {
/**
* 获取Excel读取器通过调用{@link ExcelReader}的read或readXXX方法读取Excel内容
*
* @param bookStream Excel文件的流
* @param sheetName sheet名第一个默认是sheet1
* @param bookStream Excel文件的流
* @param sheetName sheet名第一个默认是sheet1
* @param closeAfterRead 读取结束是否关闭流
* @return {@link ExcelReader}
* @deprecated 使用完毕无论是否closeAfterReadpoi会关闭流此参数无意义。
@@ -387,6 +398,7 @@ public class ExcelUtil {
}
// ------------------------------------------------------------------------------------------------ getWriter
/**
* 获得{@link ExcelWriter}默认写出到第一个sheet<br>
* 不传入写出的Excel文件路径只能调用ExcelWriter#flush(OutputStream)方法写出到流<br>
@@ -443,7 +455,7 @@ public class ExcelUtil {
*/
public static ExcelWriter getWriterWithSheet(String sheetName) {
try {
return new ExcelWriter((File)null, sheetName);
return new ExcelWriter((File) null, sheetName);
} catch (NoClassDefFoundError e) {
throw new DependencyException(ObjectUtil.defaultIfNull(e.getCause(), e), PoiChecker.NO_POI_ERROR_MSG);
}
@@ -467,7 +479,7 @@ public class ExcelUtil {
* 获得{@link ExcelWriter}
*
* @param destFilePath 目标文件路径
* @param sheetName sheet表名
* @param sheetName sheet表名
* @return {@link ExcelWriter}
*/
public static ExcelWriter getWriter(String destFilePath, String sheetName) {
@@ -481,7 +493,7 @@ public class ExcelUtil {
/**
* 获得{@link ExcelWriter}
*
* @param destFile 目标文件
* @param destFile 目标文件
* @param sheetName sheet表名
* @return {@link ExcelWriter}
*/
@@ -494,6 +506,7 @@ public class ExcelUtil {
}
// ------------------------------------------------------------------------------------------------ getBigWriter
/**
* 获得{@link BigExcelWriter}默认写出到第一个sheet<br>
* 不传入写出的Excel文件路径只能调用ExcelWriter#flush(OutputStream)方法写出到流<br>
@@ -559,7 +572,7 @@ public class ExcelUtil {
* 获得{@link BigExcelWriter}
*
* @param destFilePath 目标文件路径
* @param sheetName sheet表名
* @param sheetName sheet表名
* @return {@link BigExcelWriter}
*/
public static BigExcelWriter getBigWriter(String destFilePath, String sheetName) {
@@ -573,7 +586,7 @@ public class ExcelUtil {
/**
* 获得{@link BigExcelWriter}
*
* @param destFile 目标文件
* @param destFile 目标文件
* @param sheetName sheet表名
* @return {@link BigExcelWriter}
*/
@@ -637,9 +650,9 @@ public class ExcelUtil {
* @return 坐标点x表示行从0开始y表示列从0开始
* @since 5.1.4
*/
public static CellLocation toLocation(String locationRef){
public static CellLocation toLocation(String locationRef) {
final int x = colNameToIndex(locationRef);
final int y = ReUtil.getFirstNumber(locationRef) -1;
final int y = ReUtil.getFirstNumber(locationRef) - 1;
return new CellLocation(x, y);
}
}

View File

@@ -382,6 +382,20 @@ public class ExcelWriter extends ExcelBase<ExcelWriter> {
return StrUtil.format("attachment; filename=\"{}\"; filename*={}''{}", fileName, charset.name(), fileName);
}
/**
* 获取Content-Type头对应的值可以通过调用以下方法快速设置下载Excel的头信息
*
* <pre>
* response.setContentType(excelWriter.getContentType());
* </pre>
*
* @return Content-Type值
* @since 5.6.7
*/
public String getContentType() {
return isXlsx() ? ExcelUtil.XLSX_CONTENT_TYPE : ExcelUtil.XLS_CONTENT_TYPE;
}
/**
* 设置当前所在行
*
@@ -395,10 +409,11 @@ public class ExcelWriter extends ExcelBase<ExcelWriter> {
/**
* 定位到最后一行的后边,用于追加数据
*
* @return this
* @since 5.5.0
*/
public ExcelWriter setCurrentRowToEnd(){
public ExcelWriter setCurrentRowToEnd() {
return setCurrentRow(getRowCount());
}
@@ -730,12 +745,12 @@ public class ExcelWriter extends ExcelBase<ExcelWriter> {
* 合并单元格,并写入对象到单元格,使用指定的样式<br>
* 指定样式传入null则不使用任何样式
*
* @param firstRow 起始行0开始
* @param lastRow 结束行0开始
* @param firstColumn 起始列0开始
* @param lastColumn 结束列0开始
* @param content 合并单元格后的内容
* @param cellStyle 合并后单元格使用的样式可以为null
* @param firstRow 起始行0开始
* @param lastRow 结束行0开始
* @param firstColumn 起始列0开始
* @param lastColumn 结束列0开始
* @param content 合并单元格后的内容
* @param cellStyle 合并后单元格使用的样式可以为null
* @return this
* @since 5.6.5
*/
@@ -873,14 +888,14 @@ public class ExcelWriter extends ExcelBase<ExcelWriter> {
* 样式为默认标题样式,可使用{@link #getHeadCellStyle()}方法调用后自定义默认样式
*
* <p>
* 此方法的逻辑是:将一行数据写出到当前行,遇到已存在的单元格跳过,不存在的创建并赋值。
* 此方法的逻辑是:将一行数据写出到当前行,遇到已存在的单元格跳过,不存在的创建并赋值。
* </p>
*
* @param rowData 一行的数据
* @return this
*/
public ExcelWriter writeSecHeadRow(Iterable<?> rowData){
final Row row = RowUtil.getOrCreateRow(this.sheet,this.currentRow.getAndIncrement());
public ExcelWriter writeSecHeadRow(Iterable<?> rowData) {
final Row row = RowUtil.getOrCreateRow(this.sheet, this.currentRow.getAndIncrement());
Iterator<?> iterator = rowData.iterator();
//如果获取的row存在单元格则执行复杂表头逻辑否则直接调用writeHeadRow(Iterable<?> rowData)
if (row.getLastCellNum() != 0) {
@@ -1093,12 +1108,12 @@ public class ExcelWriter extends ExcelBase<ExcelWriter> {
/**
* 设置列的默认样式
*
* @param x 列号从0开始
* @param x 列号从0开始
* @param style 样式
* @return this
* @since 5.6.4
*/
public ExcelWriter setColumnStyle(int x, CellStyle style){
public ExcelWriter setColumnStyle(int x, CellStyle style) {
this.sheet.setDefaultColumnStyle(x, style);
return this;
}

View File

@@ -385,7 +385,6 @@ public class Excel03SaxReader implements HSSFListener, ExcelSaxReader<Excel03Sax
return Integer.parseInt(StrUtil.removePrefixIgnoreCase(idOrRidOrSheetName, RID_PREFIX));
}
final int sheetIndex;
try {
return Integer.parseInt(idOrRidOrSheetName);
} catch (NumberFormatException ignore) {

View File

@@ -247,7 +247,6 @@ public class ExcelSaxUtil {
* @since 5.5.0
*/
public static Object getNumberOrDateValue(CellValueRecordInterface cell, double value, FormatTrackingHSSFListener formatListener) {
Object result;
if (isDateFormat(cell, formatListener)) {
// 可能为日期格式
return getDateValue(value);

View File

@@ -8,7 +8,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.6.7-SNAPSHOT</version>
<version>5.6.8-SNAPSHOT</version>
</parent>
<artifactId>hutool-script</artifactId>

View File

@@ -81,19 +81,19 @@ public class ScriptRuntimeException extends RuntimeException {
*/
@Override
public String getMessage() {
String ret = super.getMessage();
StringBuilder ret = new StringBuilder().append(super.getMessage());
if (fileName != null) {
ret += (" in " + fileName);
ret.append(" in ").append(fileName);
if (lineNumber != -1) {
ret += " at line number " + lineNumber;
ret.append(" at line number ").append(lineNumber);
}
if (columnNumber != -1) {
ret += " at column number " + columnNumber;
ret.append(" at column number ").append(columnNumber);
}
}
return ret;
return ret.toString();
}
/**

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.6.7-SNAPSHOT</version>
<version>5.6.8-SNAPSHOT</version>
</parent>
<artifactId>hutool-setting</artifactId>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.6.7-SNAPSHOT</version>
<version>5.6.8-SNAPSHOT</version>
</parent>
<artifactId>hutool-socket</artifactId>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.6.7-SNAPSHOT</version>
<version>5.6.8-SNAPSHOT</version>
</parent>
<artifactId>hutool-system</artifactId>

View File

@@ -8,7 +8,7 @@
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.6.7-SNAPSHOT</version>
<version>5.6.8-SNAPSHOT</version>
<name>hutool</name>
<description>Hutool是一个小而全的Java工具类库通过静态方法封装降低相关API的学习成本提高工作效率使Java拥有函数式语言般的优雅让Java语言也可以“甜甜的”。</description>
<url>https://github.com/looly/hutool</url>