From 0d7ef8f0928d6a4e51112ba53c4ec47643117bbd Mon Sep 17 00:00:00 2001
From: Looly
Date: Thu, 26 Mar 2020 23:46:36 +0800
Subject: [PATCH 001/157] add LockUtil and fix Cache
---
CHANGELOG.md | 1 +
.../cn/hutool/cache/impl/AbstractCache.java | 154 +++++++-----------
.../cache/test/CacheConcurrentTest.java | 74 ++++-----
.../java/cn/hutool/cache/test/CacheTest.java | 2 +-
.../java/cn/hutool/core/lang/SimpleCache.java | 66 ++++----
.../cn/hutool/core/thread/lock/LockUtil.java | 43 +++++
.../cn/hutool/core/thread/lock/NoLock.java | 6 +-
.../cn/hutool/core/lang/SimpleCacheTest.java | 46 ++++++
hutool-script/pom.xml | 32 +++-
.../cn/hutool/script/JavaScriptEngine.java | 29 ++--
.../hutool/script/ScriptRuntimeException.java | 5 +-
.../java/cn/hutool/script/ScriptUtil.java | 111 ++++++++++---
.../cn/hutool/script/test/ScriptUtilTest.java | 28 +++-
13 files changed, 379 insertions(+), 218 deletions(-)
create mode 100644 hutool-core/src/main/java/cn/hutool/core/thread/lock/LockUtil.java
create mode 100644 hutool-core/src/test/java/cn/hutool/core/lang/SimpleCacheTest.java
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 394e1b4f2..19257f5e9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,7 @@
* 【core 】 CollUtil.newHashSet重载歧义,更换为set方法
* 【core 】 增加ListUtil,增加Hash32、Hash64、Hash128接口
* 【crypto 】 BCUtil增加readPemPrivateKey和readPemPublicKey方法
+* 【cache 】 替换读写锁为StampedLock,增加LockUtil
### Bug修复
* 【core 】 修复NumberWordFormatter拼写错误(issue#799@Github)
diff --git a/hutool-cache/src/main/java/cn/hutool/cache/impl/AbstractCache.java b/hutool-cache/src/main/java/cn/hutool/cache/impl/AbstractCache.java
index bb67d4e91..143afde03 100644
--- a/hutool-cache/src/main/java/cn/hutool/cache/impl/AbstractCache.java
+++ b/hutool-cache/src/main/java/cn/hutool/cache/impl/AbstractCache.java
@@ -6,9 +6,7 @@ import cn.hutool.core.lang.func.Func0;
import java.util.Iterator;
import java.util.Map;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
+import java.util.concurrent.locks.StampedLock;
/**
* 超时和限制大小的缓存的默认实现
@@ -17,32 +15,39 @@ import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
* 创建一个新的Map
* 实现 prune 策略
*
- *
- * @author Looly,jodd
*
* @param 键类型
* @param 值类型
+ * @author Looly, jodd
*/
public abstract class AbstractCache implements Cache {
private static final long serialVersionUID = 1L;
protected Map> cacheMap;
- private final ReentrantReadWriteLock cacheLock = new ReentrantReadWriteLock();
- private final ReadLock readLock = cacheLock.readLock();
- private final WriteLock writeLock = cacheLock.writeLock();
+ private final StampedLock lock = new StampedLock();
- /** 返回缓存容量,0表示无大小限制 */
+ /**
+ * 返回缓存容量,0表示无大小限制
+ */
protected int capacity;
- /** 缓存失效时长, 0 表示无限制,单位毫秒 */
+ /**
+ * 缓存失效时长, 0 表示无限制,单位毫秒
+ */
protected long timeout;
- /** 每个对象是否有单独的失效时长,用于决定清理过期对象是否有必要。 */
+ /**
+ * 每个对象是否有单独的失效时长,用于决定清理过期对象是否有必要。
+ */
protected boolean existCustomTimeout;
- /** 命中数 */
+ /**
+ * 命中数
+ */
protected int hitCount;
- /** 丢失数 */
+ /**
+ * 丢失数
+ */
protected int missCount;
// ---------------------------------------------------------------- put start
@@ -53,20 +58,19 @@ public abstract class AbstractCache implements Cache {
@Override
public void put(K key, V object, long timeout) {
- writeLock.lock();
-
+ final long stamp = lock.writeLock();
try {
putWithoutLock(key, object, timeout);
} finally {
- writeLock.unlock();
+ lock.unlockWrite(stamp);
}
}
/**
* 加入元素,无锁
- *
- * @param key 键
- * @param object 值
+ *
+ * @param key 键
+ * @param object 值
* @param timeout 超时时长
* @since 4.5.16
*/
@@ -85,8 +89,7 @@ public abstract class AbstractCache implements Cache {
// ---------------------------------------------------------------- get start
@Override
public boolean containsKey(K key) {
- readLock.lock();
-
+ final long stamp = lock.readLock();
try {
// 不存在或已移除
final CacheObj co = cacheMap.get(key);
@@ -99,7 +102,7 @@ public abstract class AbstractCache implements Cache {
return true;
}
} finally {
- readLock.unlock();
+ lock.unlockRead(stamp);
}
// 过期
@@ -111,24 +114,14 @@ public abstract class AbstractCache implements Cache {
* @return 命中数
*/
public int getHitCount() {
- this.readLock.lock();
- try {
- return hitCount;
- } finally {
- this.readLock.unlock();
- }
+ return hitCount;
}
/**
* @return 丢失数
*/
public int getMissCount() {
- this.readLock.lock();
- try {
- return missCount;
- } finally {
- this.readLock.unlock();
- }
+ return missCount;
}
@Override
@@ -140,11 +133,11 @@ public abstract class AbstractCache implements Cache {
public V get(K key, Func0 supplier) {
V v = get(key);
if (null == v && null != supplier) {
- writeLock.lock();
+ final long stamp = lock.writeLock();
try {
// 双重检查锁
final CacheObj co = cacheMap.get(key);
- if(null == co || co.isExpired() || null == co.getValue()) {
+ if (null == co || co.isExpired()) {
try {
v = supplier.call();
} catch (Exception e) {
@@ -155,7 +148,7 @@ public abstract class AbstractCache implements Cache {
v = co.get(true);
}
} finally {
- writeLock.unlock();
+ lock.unlockWrite(stamp);
}
}
return v;
@@ -163,23 +156,25 @@ public abstract class AbstractCache implements Cache {
@Override
public V get(K key, boolean isUpdateLastAccess) {
- readLock.lock();
-
+ // 尝试读取缓存,使用乐观读锁
+ long stamp = lock.readLock();
try {
// 不存在或已移除
final CacheObj co = cacheMap.get(key);
- if (co == null) {
+ if (null == co) {
missCount++;
return null;
}
- if (false == co.isExpired()) {
+ if (co.isExpired()) {
+ missCount++;
+ } else{
// 命中
hitCount++;
return co.get(isUpdateLastAccess);
}
} finally {
- readLock.unlock();
+ lock.unlock(stamp);
}
// 过期
@@ -199,30 +194,32 @@ public abstract class AbstractCache implements Cache {
@Override
public Iterator> cacheObjIterator() {
CopiedIter> copiedIterator;
- readLock.lock();
+ final long stamp = lock.readLock();
try {
copiedIterator = CopiedIter.copyOf(this.cacheMap.values().iterator());
} finally {
- readLock.unlock();
+ lock.unlockRead(stamp);
}
return new CacheObjIterator<>(copiedIterator);
}
// ---------------------------------------------------------------- prune start
+
/**
- * 清理实现
- *
+ * 清理实现
+ * 子类实现此方法时无需加锁
+ *
* @return 清理数
*/
protected abstract int pruneCache();
@Override
public final int prune() {
- writeLock.lock();
+ final long stamp = lock.writeLock();
try {
return pruneCache();
} finally {
- writeLock.unlock();
+ lock.unlockWrite(stamp);
}
}
// ---------------------------------------------------------------- prune end
@@ -235,7 +232,7 @@ public abstract class AbstractCache implements Cache {
/**
* @return 默认缓存失效时长。
- * 每个对象可以单独设置失效时长
+ * 每个对象可以单独设置失效时长
*/
@Override
public long timeout() {
@@ -244,26 +241,16 @@ public abstract class AbstractCache implements Cache {
/**
* 只有设置公共缓存失效时长或每个对象单独的失效时长时清理可用
- *
+ *
* @return 过期对象清理是否可用,内部使用
*/
protected boolean isPruneExpiredActive() {
- this.readLock.lock();
- try {
- return (timeout != 0) || existCustomTimeout;
- } finally {
- this.readLock.unlock();
- }
+ return (timeout != 0) || existCustomTimeout;
}
@Override
public boolean isFull() {
- this.readLock.lock();
- try {
- return (capacity > 0) && (cacheMap.size() >= capacity);
- } finally {
- this.readLock.unlock();
- }
+ return (capacity > 0) && (cacheMap.size() >= capacity);
}
@Override
@@ -273,49 +260,34 @@ public abstract class AbstractCache implements Cache {
@Override
public void clear() {
- writeLock.lock();
+ final long stamp = lock.writeLock();
try {
cacheMap.clear();
} finally {
- writeLock.unlock();
+ lock.unlockWrite(stamp);
}
}
@Override
public int size() {
- this.readLock.lock();
- try {
- return cacheMap.size();
- } finally {
- this.readLock.unlock();
- }
+ return cacheMap.size();
}
@Override
public boolean isEmpty() {
- this.readLock.lock();
- try {
- return cacheMap.isEmpty();
- } finally {
- this.readLock.unlock();
- }
+ return cacheMap.isEmpty();
}
@Override
public String toString() {
- this.readLock.lock();
- try {
- return this.cacheMap.toString();
- } finally {
- this.readLock.unlock();
- }
+ return this.cacheMap.toString();
}
// ---------------------------------------------------------------- common end
/**
* 对象移除回调。默认无动作
- *
- * @param key 键
+ *
+ * @param key 键
* @param cachedObject 被缓存的对象
*/
protected void onRemove(K key, V cachedObject) {
@@ -324,27 +296,27 @@ public abstract class AbstractCache implements Cache {
/**
* 移除key对应的对象
- *
- * @param key 键
+ *
+ * @param key 键
* @param withMissCount 是否计数丢失数
*/
private void remove(K key, boolean withMissCount) {
- writeLock.lock();
+ final long stamp = lock.writeLock();
CacheObj co;
try {
co = removeWithoutLock(key, withMissCount);
} finally {
- writeLock.unlock();
+ lock.unlockWrite(stamp);
}
if (null != co) {
onRemove(co.key, co.obj);
}
}
-
+
/**
* 移除key对应的对象,不加锁
- *
- * @param key 键
+ *
+ * @param key 键
* @param withMissCount 是否计数丢失数
* @return 移除的对象,无返回null
*/
diff --git a/hutool-cache/src/test/java/cn/hutool/cache/test/CacheConcurrentTest.java b/hutool-cache/src/test/java/cn/hutool/cache/test/CacheConcurrentTest.java
index 166c57a00..0fd8b80d9 100644
--- a/hutool-cache/src/test/java/cn/hutool/cache/test/CacheConcurrentTest.java
+++ b/hutool-cache/src/test/java/cn/hutool/cache/test/CacheConcurrentTest.java
@@ -1,15 +1,12 @@
package cn.hutool.cache.test;
-import java.util.Iterator;
-
-import org.junit.Ignore;
-import org.junit.Test;
-
import cn.hutool.cache.Cache;
import cn.hutool.cache.impl.FIFOCache;
import cn.hutool.cache.impl.LRUCache;
import cn.hutool.core.lang.Console;
import cn.hutool.core.thread.ThreadUtil;
+import org.junit.Ignore;
+import org.junit.Test;
/**
* 缓存单元测试
@@ -28,30 +25,22 @@ public class CacheConcurrentTest {
// 由于缓存容量只有3,当加入第四个元素的时候,根据FIFO规则,最先放入的对象将被移除
for (int i = 0; i < threadCount; i++) {
- ThreadUtil.execute(new Runnable() {
- @Override
- public void run() {
- cache.put("key1", "value1", System.currentTimeMillis() * 3);
- cache.put("key2", "value2", System.currentTimeMillis() * 3);
- cache.put("key3", "value3", System.currentTimeMillis() * 3);
- cache.put("key4", "value4", System.currentTimeMillis() * 3);
- ThreadUtil.sleep(1000);
- cache.put("key5", "value5", System.currentTimeMillis() * 3);
- cache.put("key6", "value6", System.currentTimeMillis() * 3);
- cache.put("key7", "value7", System.currentTimeMillis() * 3);
- cache.put("key8", "value8", System.currentTimeMillis() * 3);
- Console.log("put all");
- }
+ ThreadUtil.execute(() -> {
+ cache.put("key1", "value1", System.currentTimeMillis() * 3);
+ cache.put("key2", "value2", System.currentTimeMillis() * 3);
+ cache.put("key3", "value3", System.currentTimeMillis() * 3);
+ cache.put("key4", "value4", System.currentTimeMillis() * 3);
+ ThreadUtil.sleep(1000);
+ cache.put("key5", "value5", System.currentTimeMillis() * 3);
+ cache.put("key6", "value6", System.currentTimeMillis() * 3);
+ cache.put("key7", "value7", System.currentTimeMillis() * 3);
+ cache.put("key8", "value8", System.currentTimeMillis() * 3);
+ Console.log("put all");
});
}
for (int i = 0; i < threadCount; i++) {
- ThreadUtil.execute(new Runnable() {
- @Override
- public void run() {
- show(cache);
- }
- });
+ ThreadUtil.execute(() -> show(cache));
}
System.out.println("==============================");
@@ -66,23 +55,20 @@ public class CacheConcurrentTest {
for (int i = 0; i < threadCount; i++) {
final int index = i;
- ThreadUtil.execute(new Runnable() {
- @Override
- public void run() {
- cache.put("key1"+ index, "value1");
- cache.put("key2"+ index, "value2", System.currentTimeMillis() * 3);
-
- int size = cache.size();
- int capacity = cache.capacity();
- if(size > capacity) {
- Console.log("{} {}", size, capacity);
- }
- ThreadUtil.sleep(1000);
- size = cache.size();
- capacity = cache.capacity();
- if(size > capacity) {
- Console.log("## {} {}", size, capacity);
- }
+ ThreadUtil.execute(() -> {
+ cache.put("key1"+ index, "value1");
+ cache.put("key2"+ index, "value2", System.currentTimeMillis() * 3);
+
+ int size = cache.size();
+ int capacity = cache.capacity();
+ if(size > capacity) {
+ Console.log("{} {}", size, capacity);
+ }
+ ThreadUtil.sleep(1000);
+ size = cache.size();
+ capacity = cache.capacity();
+ if(size > capacity) {
+ Console.log("## {} {}", size, capacity);
}
});
}
@@ -91,10 +77,8 @@ public class CacheConcurrentTest {
}
private void show(Cache cache) {
- Iterator> its = cache.iterator();
- while (its.hasNext()) {
- Object tt = its.next();
+ for (Object tt : cache) {
Console.log(tt);
}
}
diff --git a/hutool-cache/src/test/java/cn/hutool/cache/test/CacheTest.java b/hutool-cache/src/test/java/cn/hutool/cache/test/CacheTest.java
index 12ccbe74c..c1832ce28 100644
--- a/hutool-cache/src/test/java/cn/hutool/cache/test/CacheTest.java
+++ b/hutool-cache/src/test/java/cn/hutool/cache/test/CacheTest.java
@@ -58,7 +58,7 @@ public class CacheTest {
//使用时间推近
lruCache.get("key1");
lruCache.put("key4", "value4", DateUnit.SECOND.getMillis() * 3);
-
+
String value1 = lruCache.get("key1");
Assert.assertNotNull(value1);
//由于缓存容量只有3,当加入第四个元素的时候,根据LRU规则,最少使用的将被移除(2被移除)
diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/SimpleCache.java b/hutool-core/src/main/java/cn/hutool/core/lang/SimpleCache.java
index cdcdc0efc..0c2cff152 100644
--- a/hutool-core/src/main/java/cn/hutool/core/lang/SimpleCache.java
+++ b/hutool-core/src/main/java/cn/hutool/core/lang/SimpleCache.java
@@ -1,13 +1,11 @@
package cn.hutool.core.lang;
+import cn.hutool.core.lang.func.Func0;
+
import java.io.Serializable;
import java.util.Map;
import java.util.WeakHashMap;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
-
-import cn.hutool.core.lang.func.Func0;
+import java.util.concurrent.locks.StampedLock;
/**
* 简单缓存,无超时实现,使用{@link WeakHashMap}实现缓存自动清理
@@ -21,10 +19,9 @@ public class SimpleCache implements Serializable{
/** 池 */
private final Map cache = new WeakHashMap<>();
-
- private final ReentrantReadWriteLock cacheLock = new ReentrantReadWriteLock();
- private final ReadLock readLock = cacheLock.readLock();
- private final WriteLock writeLock = cacheLock.writeLock();
+
+ // 乐观读写锁
+ private final StampedLock lock = new StampedLock ();
/**
* 从缓存池中查找值
@@ -33,15 +30,12 @@ public class SimpleCache implements Serializable{
* @return 值
*/
public V get(K key) {
- // 尝试读取缓存
- readLock.lock();
- V value;
+ long stamp = lock.readLock();
try {
- value = cache.get(key);
+ return cache.get(key);
} finally {
- readLock.unlock();
+ lock.unlockRead(stamp);
}
- return value;
}
/**
@@ -52,12 +46,25 @@ public class SimpleCache implements Serializable{
* @return 值对象
*/
public V get(K key, Func0 supplier) {
- V v = get(key);
- if (null == v && null != supplier) {
- writeLock.lock();
- try {
- // 双重检查锁
+ if(null == supplier){
+ return get(key);
+ }
+
+ long stamp = lock.readLock();
+ V v;
+ try{
+ v = cache.get(key);
+ if (null == v) {
+ // 尝试转换独占写锁
+ long writeStamp = lock.tryConvertToWriteLock(stamp);
+ if(0 == writeStamp){
+ // 转换失败,手动更新为写锁
+ lock.unlockRead(stamp);
+ writeStamp = lock.writeLock();
+ }
+ stamp = writeStamp;
v = cache.get(key);
+ // 双重检查,防止在竞争锁的过程中已经有其它线程写入
if(null == v) {
try {
v = supplier.call();
@@ -66,9 +73,9 @@ public class SimpleCache implements Serializable{
}
cache.put(key, v);
}
- } finally {
- writeLock.unlock();
}
+ } finally {
+ lock.unlock(stamp);
}
return v;
}
@@ -80,11 +87,12 @@ public class SimpleCache implements Serializable{
* @return 值
*/
public V put(K key, V value){
- writeLock.lock();
+ // 独占写锁
+ final long stamp = lock.writeLock();
try {
cache.put(key, value);
} finally {
- writeLock.unlock();
+ lock.unlockWrite(stamp);
}
return value;
}
@@ -96,11 +104,12 @@ public class SimpleCache implements Serializable{
* @return 移除的值
*/
public V remove(K key) {
- writeLock.lock();
+ // 独占写锁
+ final long stamp = lock.writeLock();
try {
return cache.remove(key);
} finally {
- writeLock.unlock();
+ lock.unlockWrite(stamp);
}
}
@@ -108,11 +117,12 @@ public class SimpleCache implements Serializable{
* 清空缓存池
*/
public void clear() {
- writeLock.lock();
+ // 独占写锁
+ final long stamp = lock.writeLock();
try {
this.cache.clear();
} finally {
- writeLock.unlock();
+ lock.unlockWrite(stamp);
}
}
}
diff --git a/hutool-core/src/main/java/cn/hutool/core/thread/lock/LockUtil.java b/hutool-core/src/main/java/cn/hutool/core/thread/lock/LockUtil.java
new file mode 100644
index 000000000..051134330
--- /dev/null
+++ b/hutool-core/src/main/java/cn/hutool/core/thread/lock/LockUtil.java
@@ -0,0 +1,43 @@
+package cn.hutool.core.thread.lock;
+
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.concurrent.locks.StampedLock;
+
+/**
+ * 锁相关工具
+ *
+ * @author looly
+ * @since 5.2.5
+ */
+public class LockUtil {
+
+ private static NoLock NO_LOCK = new NoLock();
+
+ /**
+ * 创建{@link StampedLock}锁
+ *
+ * @return {@link StampedLock}锁
+ */
+ public static StampedLock createStampLock() {
+ return new StampedLock();
+ }
+
+ /**
+ * 创建{@link ReentrantReadWriteLock}锁
+ *
+ * @param fair 是否公平锁
+ * @return {@link ReentrantReadWriteLock}锁
+ */
+ public static ReentrantReadWriteLock createReadWriteLock(boolean fair) {
+ return new ReentrantReadWriteLock(fair);
+ }
+
+ /**
+ * 获取单例的无锁对象
+ *
+ * @return {@link NoLock}
+ */
+ public static NoLock getNoLock(){
+ return NO_LOCK;
+ }
+}
diff --git a/hutool-core/src/main/java/cn/hutool/core/thread/lock/NoLock.java b/hutool-core/src/main/java/cn/hutool/core/thread/lock/NoLock.java
index 12032abb0..912d21359 100644
--- a/hutool-core/src/main/java/cn/hutool/core/thread/lock/NoLock.java
+++ b/hutool-core/src/main/java/cn/hutool/core/thread/lock/NoLock.java
@@ -17,7 +17,7 @@ public class NoLock implements Lock{
}
@Override
- public void lockInterruptibly() throws InterruptedException {
+ public void lockInterruptibly() {
}
@Override
@@ -25,8 +25,9 @@ public class NoLock implements Lock{
return true;
}
+ @SuppressWarnings("NullableProblems")
@Override
- public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
+ public boolean tryLock(long time, TimeUnit unit) {
return true;
}
@@ -34,6 +35,7 @@ public class NoLock implements Lock{
public void unlock() {
}
+ @SuppressWarnings("NullableProblems")
@Override
public Condition newCondition() {
return null;
diff --git a/hutool-core/src/test/java/cn/hutool/core/lang/SimpleCacheTest.java b/hutool-core/src/test/java/cn/hutool/core/lang/SimpleCacheTest.java
new file mode 100644
index 000000000..bac03887b
--- /dev/null
+++ b/hutool-core/src/test/java/cn/hutool/core/lang/SimpleCacheTest.java
@@ -0,0 +1,46 @@
+package cn.hutool.core.lang;
+
+import cn.hutool.core.thread.ThreadUtil;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class SimpleCacheTest {
+
+ @Before
+ public void putTest(){
+ final SimpleCache cache = new SimpleCache<>();
+ ThreadUtil.execute(()->cache.put("key1", "value1"));
+ ThreadUtil.execute(()->cache.get("key1"));
+ ThreadUtil.execute(()->cache.put("key2", "value2"));
+ ThreadUtil.execute(()->cache.get("key2"));
+ ThreadUtil.execute(()->cache.put("key3", "value3"));
+ ThreadUtil.execute(()->cache.get("key3"));
+ ThreadUtil.execute(()->cache.put("key4", "value4"));
+ ThreadUtil.execute(()->cache.get("key4"));
+ ThreadUtil.execute(()->cache.get("key5", ()->"value5"));
+
+ cache.get("key5", ()->"value5");
+ }
+
+ @Test
+ public void getTest(){
+ final SimpleCache cache = new SimpleCache<>();
+ cache.put("key1", "value1");
+ cache.get("key1");
+ cache.put("key2", "value2");
+ cache.get("key2");
+ cache.put("key3", "value3");
+ cache.get("key3");
+ cache.put("key4", "value4");
+ cache.get("key4");
+ cache.get("key5", ()->"value5");
+
+ Assert.assertEquals("value1", cache.get("key1"));
+ Assert.assertEquals("value2", cache.get("key2"));
+ Assert.assertEquals("value3", cache.get("key3"));
+ Assert.assertEquals("value4", cache.get("key4"));
+ Assert.assertEquals("value5", cache.get("key5"));
+ Assert.assertEquals("value6", cache.get("key6", ()-> "value6"));
+ }
+}
diff --git a/hutool-script/pom.xml b/hutool-script/pom.xml
index 8125484cc..f3424433c 100644
--- a/hutool-script/pom.xml
+++ b/hutool-script/pom.xml
@@ -1,9 +1,10 @@
-
+
4.0.0
jar
-
+
cn.hutool
hutool-parent
@@ -13,12 +14,37 @@
hutool-script
${project.artifactId}
Hutool 脚本执行封装
-
+
+
+ 2.7.0
+ 3.0.1
+ 3.0.2
+
+
cn.hutool
hutool-core
${project.parent.version}
+
+ org.python
+ jython
+ ${jython.version}
+ provided
+
+
+ org.luaj
+ luaj-jse
+ ${luaj.version}
+ provided
+
+
+ org.codehaus.groovy
+ groovy-all
+ ${groovy.version}
+ pom
+ provided
+
diff --git a/hutool-script/src/main/java/cn/hutool/script/JavaScriptEngine.java b/hutool-script/src/main/java/cn/hutool/script/JavaScriptEngine.java
index d6f0b9d46..c62283d0b 100644
--- a/hutool-script/src/main/java/cn/hutool/script/JavaScriptEngine.java
+++ b/hutool-script/src/main/java/cn/hutool/script/JavaScriptEngine.java
@@ -1,65 +1,64 @@
package cn.hutool.script;
-import java.io.Reader;
-
import javax.script.Bindings;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.Invocable;
import javax.script.ScriptContext;
import javax.script.ScriptEngineFactory;
-import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
+import java.io.Reader;
/**
* Javascript引擎类
- * @author Looly
*
+ * @author Looly
*/
-public class JavaScriptEngine extends FullSupportScriptEngine{
-
+public class JavaScriptEngine extends FullSupportScriptEngine {
+
public JavaScriptEngine() {
- super(new ScriptEngineManager().getEngineByName("javascript"));
+ super(ScriptUtil.getJsEngine());
}
-
+
/**
* 引擎实例
+ *
* @return 引擎实例
*/
- public static JavaScriptEngine instance(){
+ public static JavaScriptEngine instance() {
return new JavaScriptEngine();
}
//----------------------------------------------------------------------------------------------- Invocable
@Override
public Object invokeMethod(Object thiz, String name, Object... args) throws ScriptException, NoSuchMethodException {
- return ((Invocable)engine).invokeMethod(thiz, name, args);
+ return ((Invocable) engine).invokeMethod(thiz, name, args);
}
@Override
public Object invokeFunction(String name, Object... args) throws ScriptException, NoSuchMethodException {
- return ((Invocable)engine).invokeFunction(name, args);
+ return ((Invocable) engine).invokeFunction(name, args);
}
@Override
public T getInterface(Class clasz) {
- return ((Invocable)engine).getInterface(clasz);
+ return ((Invocable) engine).getInterface(clasz);
}
@Override
public T getInterface(Object thiz, Class clasz) {
- return ((Invocable)engine).getInterface(thiz, clasz);
+ return ((Invocable) engine).getInterface(thiz, clasz);
}
//----------------------------------------------------------------------------------------------- Compilable
@Override
public CompiledScript compile(String script) throws ScriptException {
- return ((Compilable)engine).compile(script);
+ return ((Compilable) engine).compile(script);
}
@Override
public CompiledScript compile(Reader script) throws ScriptException {
- return ((Compilable)engine).compile(script);
+ return ((Compilable) engine).compile(script);
}
//----------------------------------------------------------------------------------------------- ScriptEngine
diff --git a/hutool-script/src/main/java/cn/hutool/script/ScriptRuntimeException.java b/hutool-script/src/main/java/cn/hutool/script/ScriptRuntimeException.java
index fe530ee02..d252a9099 100644
--- a/hutool-script/src/main/java/cn/hutool/script/ScriptRuntimeException.java
+++ b/hutool-script/src/main/java/cn/hutool/script/ScriptRuntimeException.java
@@ -1,10 +1,10 @@
package cn.hutool.script;
-import javax.script.ScriptException;
-
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.StrUtil;
+import javax.script.ScriptException;
+
/**
* 脚本运行时异常
*
@@ -50,7 +50,6 @@ public class ScriptRuntimeException extends RuntimeException {
super(message);
this.fileName = fileName;
this.lineNumber = lineNumber;
- this.columnNumber = -1;
}
/**
diff --git a/hutool-script/src/main/java/cn/hutool/script/ScriptUtil.java b/hutool-script/src/main/java/cn/hutool/script/ScriptUtil.java
index 559a58ea9..991c425c6 100644
--- a/hutool-script/src/main/java/cn/hutool/script/ScriptUtil.java
+++ b/hutool-script/src/main/java/cn/hutool/script/ScriptUtil.java
@@ -1,5 +1,8 @@
package cn.hutool.script;
+import cn.hutool.core.lang.SimpleCache;
+import cn.hutool.core.util.StrUtil;
+
import javax.script.Bindings;
import javax.script.Compilable;
import javax.script.CompiledScript;
@@ -10,34 +13,92 @@ import javax.script.ScriptException;
/**
* 脚本工具类
- *
- * @author Looly
*
+ * @author Looly
*/
public class ScriptUtil {
+ private static final ScriptEngineManager manager = new ScriptEngineManager();
+ private static SimpleCache cache = new SimpleCache<>();
+
/**
* 获得 {@link ScriptEngine} 实例
- *
- * @param name 脚本名称
+ *
+ * @param nameOrExtOrMime 脚本名称
* @return {@link ScriptEngine} 实例
*/
- public static ScriptEngine getScript(String name) {
- return new ScriptEngineManager().getEngineByName(name);
+ public static ScriptEngine getScript(String nameOrExtOrMime) {
+ return cache.get(nameOrExtOrMime, ()->{
+ ScriptEngine engine = manager.getEngineByName(nameOrExtOrMime);
+ if (null == engine) {
+ engine = manager.getEngineByExtension(nameOrExtOrMime);
+ }
+ if (null == engine) {
+ engine = manager.getEngineByMimeType(nameOrExtOrMime);
+ }
+ if (null == engine) {
+ throw new NullPointerException(StrUtil.format("Script for [{}] not support !", nameOrExtOrMime));
+ }
+ return engine;
+ });
}
/**
* 获得 Javascript引擎 {@link JavaScriptEngine}
- *
+ *
* @return {@link JavaScriptEngine}
*/
public static JavaScriptEngine getJavaScriptEngine() {
return new JavaScriptEngine();
}
-
+
/**
- * 编译脚本
- *
+ * 获得 JavaScript引擎
+ *
+ * @return Python引擎
+ * @since 5.2.5
+ */
+ public static ScriptEngine getJsEngine() {
+ return getScript("js");
+ }
+
+ /**
+ * 获得 Python引擎
+ * 需要引入org.python:jython
+ *
+ * @return Python引擎
+ * @since 5.2.5
+ */
+ public static ScriptEngine getPythonEngine() {
+ System.setProperty("python.import.site", "false");
+ return getScript("python");
+ }
+
+ /**
+ * 获得Lua引擎
+ * 需要引入org.luaj:luaj-jse
+ *
+ * @return Lua引擎
+ * @since 5.2.5
+ */
+ public static ScriptEngine getLuaEngine() {
+ return getScript("lua");
+ }
+
+ /**
+ * 获得Groovy引擎
+ * 需要引入org.codehaus.groovy:groovy-all
+ *
+ * @return Groovy引擎
+ * @since 5.2.5
+ */
+ public static ScriptEngine getGroovyEngine() {
+ return getScript("groovy");
+ }
+
+ /**
+ * 执行脚本
+ *
* @param script 脚本内容
* @return {@link CompiledScript}
* @throws ScriptRuntimeException 脚本异常
@@ -45,16 +106,16 @@ public class ScriptUtil {
*/
public static Object eval(String script) throws ScriptRuntimeException {
try {
- return compile(script).eval();
+ return getJsEngine().eval(script);
} catch (ScriptException e) {
throw new ScriptRuntimeException(e);
}
}
-
+
/**
- * 编译脚本
- *
- * @param script 脚本内容
+ * 执行脚本
+ *
+ * @param script 脚本内容
* @param context 脚本上下文
* @return {@link CompiledScript}
* @throws ScriptRuntimeException 脚本异常
@@ -62,16 +123,16 @@ public class ScriptUtil {
*/
public static Object eval(String script, ScriptContext context) throws ScriptRuntimeException {
try {
- return compile(script).eval(context);
+ return getJsEngine().eval(script, context);
} catch (ScriptException e) {
throw new ScriptRuntimeException(e);
}
}
-
+
/**
- * 编译脚本
- *
- * @param script 脚本内容
+ * 执行脚本
+ *
+ * @param script 脚本内容
* @param bindings 绑定的参数
* @return {@link CompiledScript}
* @throws ScriptRuntimeException 脚本异常
@@ -79,7 +140,7 @@ public class ScriptUtil {
*/
public static Object eval(String script, Bindings bindings) throws ScriptRuntimeException {
try {
- return compile(script).eval(bindings);
+ return getJsEngine().eval(script, bindings);
} catch (ScriptException e) {
throw new ScriptRuntimeException(e);
}
@@ -87,7 +148,7 @@ public class ScriptUtil {
/**
* 编译脚本
- *
+ *
* @param script 脚本内容
* @return {@link CompiledScript}
* @throws ScriptRuntimeException 脚本异常
@@ -95,7 +156,7 @@ public class ScriptUtil {
*/
public static CompiledScript compile(String script) throws ScriptRuntimeException {
try {
- return compile(getJavaScriptEngine(), script);
+ return compile(getJsEngine(), script);
} catch (ScriptException e) {
throw new ScriptRuntimeException(e);
}
@@ -103,7 +164,7 @@ public class ScriptUtil {
/**
* 编译脚本
- *
+ *
* @param engine 引擎
* @param script 脚本内容
* @return {@link CompiledScript}
@@ -111,7 +172,7 @@ public class ScriptUtil {
*/
public static CompiledScript compile(ScriptEngine engine, String script) throws ScriptException {
if (engine instanceof Compilable) {
- Compilable compEngine = (Compilable) engine;
+ final Compilable compEngine = (Compilable) engine;
return compEngine.compile(script);
}
return null;
diff --git a/hutool-script/src/test/java/cn/hutool/script/test/ScriptUtilTest.java b/hutool-script/src/test/java/cn/hutool/script/test/ScriptUtilTest.java
index fda465b73..6fcbf57c3 100644
--- a/hutool-script/src/test/java/cn/hutool/script/test/ScriptUtilTest.java
+++ b/hutool-script/src/test/java/cn/hutool/script/test/ScriptUtilTest.java
@@ -1,12 +1,12 @@
package cn.hutool.script.test;
-import javax.script.CompiledScript;
-import javax.script.ScriptException;
-
-import org.junit.Test;
-
import cn.hutool.script.ScriptRuntimeException;
import cn.hutool.script.ScriptUtil;
+import org.junit.Test;
+
+import javax.script.CompiledScript;
+import javax.script.ScriptEngine;
+import javax.script.ScriptException;
/**
* 脚本单元测试类
@@ -30,4 +30,22 @@ public class ScriptUtilTest {
public void evalTest() {
ScriptUtil.eval("print('Script test!');");
}
+
+ @Test
+ public void pythonTest() throws ScriptException {
+ final ScriptEngine pythonEngine = ScriptUtil.getPythonEngine();
+ pythonEngine.eval("print('Hello Python')");
+ }
+
+ @Test
+ public void luaTest() throws ScriptException {
+ final ScriptEngine engine = ScriptUtil.getLuaEngine();
+ engine.eval("print('Hello Lua')");
+ }
+
+ @Test
+ public void groovyTest() throws ScriptException {
+ final ScriptEngine engine = ScriptUtil.getGroovyEngine();
+ engine.eval("println 'Hello Groovy'");
+ }
}
From 4d8b21f831343f43a61b3273eecaf26bf9537293 Mon Sep 17 00:00:00 2001
From: Looly
Date: Thu, 26 Mar 2020 23:58:44 +0800
Subject: [PATCH 002/157] release 5.2.5
---
CHANGELOG.md | 2 +-
hutool-all/pom.xml | 2 +-
hutool-aop/pom.xml | 2 +-
hutool-bloomFilter/pom.xml | 2 +-
hutool-bom/pom.xml | 2 +-
hutool-cache/pom.xml | 2 +-
hutool-captcha/pom.xml | 2 +-
hutool-core/pom.xml | 2 +-
.../src/main/java/cn/hutool/core/collection/CollUtil.java | 2 +-
hutool-cron/pom.xml | 2 +-
hutool-crypto/pom.xml | 2 +-
hutool-db/pom.xml | 2 +-
hutool-dfa/pom.xml | 2 +-
hutool-extra/pom.xml | 2 +-
hutool-http/pom.xml | 2 +-
hutool-json/pom.xml | 2 +-
hutool-log/pom.xml | 2 +-
hutool-poi/pom.xml | 2 +-
hutool-script/pom.xml | 2 +-
hutool-setting/pom.xml | 2 +-
hutool-socket/pom.xml | 2 +-
hutool-system/pom.xml | 2 +-
pom.xml | 2 +-
23 files changed, 23 insertions(+), 23 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 19257f5e9..25ce1489d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,7 +3,7 @@
-------------------------------------------------------------------------------------------------------------
-## 5.2.5
+## 5.2.5 (2020-03-26)
### 新特性
* 【core 】 增加逻辑,对于原始类型注入,使用默认值(issue#797@Github)
diff --git a/hutool-all/pom.xml b/hutool-all/pom.xml
index 7610de4f3..db751c6ec 100644
--- a/hutool-all/pom.xml
+++ b/hutool-all/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.2.5-SNAPSHOT
+ 5.2.5
hutool-all
diff --git a/hutool-aop/pom.xml b/hutool-aop/pom.xml
index dcba385ba..3c1b19771 100644
--- a/hutool-aop/pom.xml
+++ b/hutool-aop/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.2.5-SNAPSHOT
+ 5.2.5
hutool-aop
diff --git a/hutool-bloomFilter/pom.xml b/hutool-bloomFilter/pom.xml
index 2a6d645d9..a0d3b5c32 100644
--- a/hutool-bloomFilter/pom.xml
+++ b/hutool-bloomFilter/pom.xml
@@ -7,7 +7,7 @@
cn.hutool
hutool-parent
- 5.2.5-SNAPSHOT
+ 5.2.5
hutool-bloomFilter
diff --git a/hutool-bom/pom.xml b/hutool-bom/pom.xml
index 3662d2a7b..8665e9a56 100644
--- a/hutool-bom/pom.xml
+++ b/hutool-bom/pom.xml
@@ -7,7 +7,7 @@
cn.hutool
hutool-parent
- 5.2.5-SNAPSHOT
+ 5.2.5
hutool-bom
diff --git a/hutool-cache/pom.xml b/hutool-cache/pom.xml
index 780da5d5f..b062128a5 100644
--- a/hutool-cache/pom.xml
+++ b/hutool-cache/pom.xml
@@ -7,7 +7,7 @@
cn.hutool
hutool-parent
- 5.2.5-SNAPSHOT
+ 5.2.5
hutool-cache
diff --git a/hutool-captcha/pom.xml b/hutool-captcha/pom.xml
index dd94659d2..3aec64a4b 100644
--- a/hutool-captcha/pom.xml
+++ b/hutool-captcha/pom.xml
@@ -7,7 +7,7 @@
cn.hutool
hutool-parent
- 5.2.5-SNAPSHOT
+ 5.2.5
hutool-captcha
diff --git a/hutool-core/pom.xml b/hutool-core/pom.xml
index 9434f0194..4bbdc77ef 100644
--- a/hutool-core/pom.xml
+++ b/hutool-core/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.2.5-SNAPSHOT
+ 5.2.5
hutool-core
diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java b/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java
index 0f116f6a2..3cb0ee020 100644
--- a/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java
+++ b/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java
@@ -486,7 +486,7 @@ public class CollUtil {
*/
@SafeVarargs
public static LinkedHashSet newLinkedHashSet(T... ts) {
- return (LinkedHashSet) newHashSet(true, ts);
+ return (LinkedHashSet) set(true, ts);
}
/**
diff --git a/hutool-cron/pom.xml b/hutool-cron/pom.xml
index 4a9afa1f5..0639fe711 100644
--- a/hutool-cron/pom.xml
+++ b/hutool-cron/pom.xml
@@ -7,7 +7,7 @@
cn.hutool
hutool-parent
- 5.2.5-SNAPSHOT
+ 5.2.5
hutool-cron
diff --git a/hutool-crypto/pom.xml b/hutool-crypto/pom.xml
index 8986ece74..9005a6b8b 100644
--- a/hutool-crypto/pom.xml
+++ b/hutool-crypto/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.2.5-SNAPSHOT
+ 5.2.5
hutool-crypto
diff --git a/hutool-db/pom.xml b/hutool-db/pom.xml
index 84ab625ab..3acfd3042 100644
--- a/hutool-db/pom.xml
+++ b/hutool-db/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.2.5-SNAPSHOT
+ 5.2.5
hutool-db
diff --git a/hutool-dfa/pom.xml b/hutool-dfa/pom.xml
index a714f97f0..59db5d9af 100644
--- a/hutool-dfa/pom.xml
+++ b/hutool-dfa/pom.xml
@@ -7,7 +7,7 @@
cn.hutool
hutool-parent
- 5.2.5-SNAPSHOT
+ 5.2.5
hutool-dfa
diff --git a/hutool-extra/pom.xml b/hutool-extra/pom.xml
index f43628c29..af811b3e5 100644
--- a/hutool-extra/pom.xml
+++ b/hutool-extra/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.2.5-SNAPSHOT
+ 5.2.5
hutool-extra
diff --git a/hutool-http/pom.xml b/hutool-http/pom.xml
index 7ea30fb2b..c5f1ab944 100644
--- a/hutool-http/pom.xml
+++ b/hutool-http/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.2.5-SNAPSHOT
+ 5.2.5
hutool-http
diff --git a/hutool-json/pom.xml b/hutool-json/pom.xml
index f5837ea56..caf67181d 100644
--- a/hutool-json/pom.xml
+++ b/hutool-json/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.2.5-SNAPSHOT
+ 5.2.5
hutool-json
diff --git a/hutool-log/pom.xml b/hutool-log/pom.xml
index e550aae74..391bff51e 100644
--- a/hutool-log/pom.xml
+++ b/hutool-log/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.2.5-SNAPSHOT
+ 5.2.5
hutool-log
diff --git a/hutool-poi/pom.xml b/hutool-poi/pom.xml
index de9ae72c0..c540b906a 100644
--- a/hutool-poi/pom.xml
+++ b/hutool-poi/pom.xml
@@ -8,7 +8,7 @@
cn.hutool
hutool-parent
- 5.2.5-SNAPSHOT
+ 5.2.5
hutool-poi
diff --git a/hutool-script/pom.xml b/hutool-script/pom.xml
index f3424433c..feb304160 100644
--- a/hutool-script/pom.xml
+++ b/hutool-script/pom.xml
@@ -8,7 +8,7 @@
cn.hutool
hutool-parent
- 5.2.5-SNAPSHOT
+ 5.2.5
hutool-script
diff --git a/hutool-setting/pom.xml b/hutool-setting/pom.xml
index dff1168d2..871e1578e 100644
--- a/hutool-setting/pom.xml
+++ b/hutool-setting/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.2.5-SNAPSHOT
+ 5.2.5
hutool-setting
diff --git a/hutool-socket/pom.xml b/hutool-socket/pom.xml
index b1be9e927..07bb0deda 100644
--- a/hutool-socket/pom.xml
+++ b/hutool-socket/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.2.5-SNAPSHOT
+ 5.2.5
hutool-socket
diff --git a/hutool-system/pom.xml b/hutool-system/pom.xml
index 20d5ff1fd..9ca9d35ad 100644
--- a/hutool-system/pom.xml
+++ b/hutool-system/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.2.5-SNAPSHOT
+ 5.2.5
hutool-system
diff --git a/pom.xml b/pom.xml
index 020ceffb0..e2047009f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -8,7 +8,7 @@
cn.hutool
hutool-parent
- 5.2.5-SNAPSHOT
+ 5.2.5
hutool
提供丰富的Java工具方法
https://github.com/looly/hutool
From 130fa344c4a6f333b7ba496eca4498a477a40f15 Mon Sep 17 00:00:00 2001
From: Looly
Date: Fri, 27 Mar 2020 00:31:35 +0800
Subject: [PATCH 003/157] prepare 5.2.6
---
CHANGELOG.md | 7 +++++++
README.md | 10 +++++-----
bin/version.txt | 2 +-
docs/js/version.js | 2 +-
hutool-all/pom.xml | 2 +-
hutool-aop/pom.xml | 2 +-
hutool-bloomFilter/pom.xml | 2 +-
hutool-bom/pom.xml | 2 +-
hutool-cache/pom.xml | 2 +-
hutool-captcha/pom.xml | 2 +-
hutool-core/pom.xml | 2 +-
hutool-cron/pom.xml | 2 +-
hutool-crypto/pom.xml | 2 +-
hutool-db/pom.xml | 2 +-
hutool-dfa/pom.xml | 2 +-
hutool-extra/pom.xml | 2 +-
hutool-http/pom.xml | 2 +-
hutool-json/pom.xml | 2 +-
hutool-log/pom.xml | 2 +-
hutool-poi/pom.xml | 2 +-
hutool-script/pom.xml | 2 +-
hutool-setting/pom.xml | 2 +-
hutool-socket/pom.xml | 2 +-
hutool-system/pom.xml | 2 +-
pom.xml | 2 +-
25 files changed, 35 insertions(+), 28 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 25ce1489d..5d246a0e9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,13 @@
-------------------------------------------------------------------------------------------------------------
+## 5.2.6 (2020-03-26)
+
+### 新特性
+### Bug修复
+
+-------------------------------------------------------------------------------------------------------------
+
## 5.2.5 (2020-03-26)
### 新特性
diff --git a/README.md b/README.md
index 5fd7294b6..bf9a22421 100644
--- a/README.md
+++ b/README.md
@@ -40,7 +40,7 @@
-- 主页:https://hutool.cn/ | https://www.hutool.club/ --
- -- QQ群③:555368316 --
+ -- QQ群③:555368316 --
-- QQ群④:718802356 --
@@ -116,21 +116,21 @@ Hutool的存在就是为了减少代码搜索成本,避免网络上参差不
cn.hutool
hutool-all
- 5.2.5
+ 5.2.6
```
### Gradle
```
-compile 'cn.hutool:hutool-all:5.2.5'
+compile 'cn.hutool:hutool-all:5.2.6'
```
### 非Maven项目
点击以下任一链接,下载`hutool-all-X.X.X.jar`即可:
-- [Maven中央库1](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.2.5/)
-- [Maven中央库2](http://repo2.maven.org/maven2/cn/hutool/hutool-all/5.2.5/)
+- [Maven中央库1](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.2.6/)
+- [Maven中央库2](http://repo2.maven.org/maven2/cn/hutool/hutool-all/5.2.6/)
> 注意
> Hutool 5.x支持JDK8+,对Android平台没有测试,不能保证所有工具类获工具方法可用。
diff --git a/bin/version.txt b/bin/version.txt
index 462faf748..a944d7e61 100755
--- a/bin/version.txt
+++ b/bin/version.txt
@@ -1 +1 @@
-5.2.5
+5.2.6
diff --git a/docs/js/version.js b/docs/js/version.js
index 3c62295c9..b5a3cc686 100644
--- a/docs/js/version.js
+++ b/docs/js/version.js
@@ -1 +1 @@
-var version = '5.2.5'
\ No newline at end of file
+var version = '5.2.6'
\ No newline at end of file
diff --git a/hutool-all/pom.xml b/hutool-all/pom.xml
index db751c6ec..0d5f10848 100644
--- a/hutool-all/pom.xml
+++ b/hutool-all/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.2.5
+ 5.2.6-SNAPSHOT
hutool-all
diff --git a/hutool-aop/pom.xml b/hutool-aop/pom.xml
index 3c1b19771..3c011fb9a 100644
--- a/hutool-aop/pom.xml
+++ b/hutool-aop/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.2.5
+ 5.2.6-SNAPSHOT
hutool-aop
diff --git a/hutool-bloomFilter/pom.xml b/hutool-bloomFilter/pom.xml
index a0d3b5c32..e7bf57f83 100644
--- a/hutool-bloomFilter/pom.xml
+++ b/hutool-bloomFilter/pom.xml
@@ -7,7 +7,7 @@
cn.hutool
hutool-parent
- 5.2.5
+ 5.2.6-SNAPSHOT
hutool-bloomFilter
diff --git a/hutool-bom/pom.xml b/hutool-bom/pom.xml
index 8665e9a56..403ddad61 100644
--- a/hutool-bom/pom.xml
+++ b/hutool-bom/pom.xml
@@ -7,7 +7,7 @@
cn.hutool
hutool-parent
- 5.2.5
+ 5.2.6-SNAPSHOT
hutool-bom
diff --git a/hutool-cache/pom.xml b/hutool-cache/pom.xml
index b062128a5..008e8704e 100644
--- a/hutool-cache/pom.xml
+++ b/hutool-cache/pom.xml
@@ -7,7 +7,7 @@
cn.hutool
hutool-parent
- 5.2.5
+ 5.2.6-SNAPSHOT
hutool-cache
diff --git a/hutool-captcha/pom.xml b/hutool-captcha/pom.xml
index 3aec64a4b..0f9c30525 100644
--- a/hutool-captcha/pom.xml
+++ b/hutool-captcha/pom.xml
@@ -7,7 +7,7 @@
cn.hutool
hutool-parent
- 5.2.5
+ 5.2.6-SNAPSHOT
hutool-captcha
diff --git a/hutool-core/pom.xml b/hutool-core/pom.xml
index 4bbdc77ef..94bd039cc 100644
--- a/hutool-core/pom.xml
+++ b/hutool-core/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.2.5
+ 5.2.6-SNAPSHOT
hutool-core
diff --git a/hutool-cron/pom.xml b/hutool-cron/pom.xml
index 0639fe711..d7e2134a8 100644
--- a/hutool-cron/pom.xml
+++ b/hutool-cron/pom.xml
@@ -7,7 +7,7 @@
cn.hutool
hutool-parent
- 5.2.5
+ 5.2.6-SNAPSHOT
hutool-cron
diff --git a/hutool-crypto/pom.xml b/hutool-crypto/pom.xml
index 9005a6b8b..ccdd83b22 100644
--- a/hutool-crypto/pom.xml
+++ b/hutool-crypto/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.2.5
+ 5.2.6-SNAPSHOT
hutool-crypto
diff --git a/hutool-db/pom.xml b/hutool-db/pom.xml
index 3acfd3042..fa32455c3 100644
--- a/hutool-db/pom.xml
+++ b/hutool-db/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.2.5
+ 5.2.6-SNAPSHOT
hutool-db
diff --git a/hutool-dfa/pom.xml b/hutool-dfa/pom.xml
index 59db5d9af..82e7f9473 100644
--- a/hutool-dfa/pom.xml
+++ b/hutool-dfa/pom.xml
@@ -7,7 +7,7 @@
cn.hutool
hutool-parent
- 5.2.5
+ 5.2.6-SNAPSHOT
hutool-dfa
diff --git a/hutool-extra/pom.xml b/hutool-extra/pom.xml
index af811b3e5..8298dc798 100644
--- a/hutool-extra/pom.xml
+++ b/hutool-extra/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.2.5
+ 5.2.6-SNAPSHOT
hutool-extra
diff --git a/hutool-http/pom.xml b/hutool-http/pom.xml
index c5f1ab944..0086696a9 100644
--- a/hutool-http/pom.xml
+++ b/hutool-http/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.2.5
+ 5.2.6-SNAPSHOT
hutool-http
diff --git a/hutool-json/pom.xml b/hutool-json/pom.xml
index caf67181d..af66a23a4 100644
--- a/hutool-json/pom.xml
+++ b/hutool-json/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.2.5
+ 5.2.6-SNAPSHOT
hutool-json
diff --git a/hutool-log/pom.xml b/hutool-log/pom.xml
index 391bff51e..dc713a7b5 100644
--- a/hutool-log/pom.xml
+++ b/hutool-log/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.2.5
+ 5.2.6-SNAPSHOT
hutool-log
diff --git a/hutool-poi/pom.xml b/hutool-poi/pom.xml
index c540b906a..379315af5 100644
--- a/hutool-poi/pom.xml
+++ b/hutool-poi/pom.xml
@@ -8,7 +8,7 @@
cn.hutool
hutool-parent
- 5.2.5
+ 5.2.6-SNAPSHOT
hutool-poi
diff --git a/hutool-script/pom.xml b/hutool-script/pom.xml
index feb304160..9833e6f62 100644
--- a/hutool-script/pom.xml
+++ b/hutool-script/pom.xml
@@ -8,7 +8,7 @@
cn.hutool
hutool-parent
- 5.2.5
+ 5.2.6-SNAPSHOT
hutool-script
diff --git a/hutool-setting/pom.xml b/hutool-setting/pom.xml
index 871e1578e..eb777bc49 100644
--- a/hutool-setting/pom.xml
+++ b/hutool-setting/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.2.5
+ 5.2.6-SNAPSHOT
hutool-setting
diff --git a/hutool-socket/pom.xml b/hutool-socket/pom.xml
index 07bb0deda..011ef7557 100644
--- a/hutool-socket/pom.xml
+++ b/hutool-socket/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.2.5
+ 5.2.6-SNAPSHOT
hutool-socket
diff --git a/hutool-system/pom.xml b/hutool-system/pom.xml
index 9ca9d35ad..487c2c2d5 100644
--- a/hutool-system/pom.xml
+++ b/hutool-system/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.2.5
+ 5.2.6-SNAPSHOT
hutool-system
diff --git a/pom.xml b/pom.xml
index e2047009f..e443672b0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -8,7 +8,7 @@
cn.hutool
hutool-parent
- 5.2.5
+ 5.2.6-SNAPSHOT
hutool
提供丰富的Java工具方法
https://github.com/looly/hutool
From 11191b3cfee9ded6a81906fb25e1a936ad5b4bdb Mon Sep 17 00:00:00 2001
From: Looly
Date: Fri, 27 Mar 2020 09:34:34 +0800
Subject: [PATCH 004/157] fix S
---
CHANGELOG.md | 1 +
.../src/main/java/cn/hutool/extra/spring/SpringUtil.java | 4 +---
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5d246a0e9..5256e7d5b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@
### 新特性
### Bug修复
+* 【extra 】 修复SpringUtil使用devtools重启报错问题
-------------------------------------------------------------------------------------------------------------
diff --git a/hutool-extra/src/main/java/cn/hutool/extra/spring/SpringUtil.java b/hutool-extra/src/main/java/cn/hutool/extra/spring/SpringUtil.java
index f066c6f96..39f706d7a 100644
--- a/hutool-extra/src/main/java/cn/hutool/extra/spring/SpringUtil.java
+++ b/hutool-extra/src/main/java/cn/hutool/extra/spring/SpringUtil.java
@@ -22,9 +22,7 @@ public class SpringUtil implements ApplicationContextAware {
@SuppressWarnings("NullableProblems")
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
- if (SpringUtil.applicationContext == null) {
- SpringUtil.applicationContext = applicationContext;
- }
+ SpringUtil.applicationContext = applicationContext;
}
/**
From c97c76d49d6e47e84786ec028de05084dc6854ef Mon Sep 17 00:00:00 2001
From: Looly
Date: Sun, 29 Mar 2020 09:28:11 +0800
Subject: [PATCH 005/157] add execByShell
---
CHANGELOG-v4.md | 1461 -----------------
CHANGELOG.md | 2 +
.../java/cn/hutool/extra/ssh/JschUtil.java | 55 +-
3 files changed, 54 insertions(+), 1464 deletions(-)
delete mode 100644 CHANGELOG-v4.md
diff --git a/CHANGELOG-v4.md b/CHANGELOG-v4.md
deleted file mode 100644
index 34186edf5..000000000
--- a/CHANGELOG-v4.md
+++ /dev/null
@@ -1,1461 +0,0 @@
-
-# Changelog
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.6.9
-
-### 新特性
-* 【all】 修复注释中的错别字(issue#I12XE6@Gitee)
-* 【core】 CsvWriter支持其它类型的参数(issue#I12XE3@Gitee)
-* 【core】 ClassScanner支持自定义ClassLoader
-* 【core】 修改错别字(pr#568@Github)
-* 【core】 增加DateUtil.parseCST方法(issue#570@Github)
-* 【core】 增加defaultIfEmpty方法
-* 【crypto】 修改bigIntToFixexLengthBytes为bigIntToFixedLengthBytes(pr#575@Github)
-* 【core】 RandomUtil增加randomStringWithoutStr(pr#76@Gitee)
-
-### Bug修复
-* 【all】 修复阶乘计算错误bug(issue#I12XE4@Gitee)
-* 【http】 修复disableCookie无效问题(issue#572@Github)
-* 【http】 修复HttpResponse.getCookies导致的问题(issue#572@Github)
-* 【cron】 修复年无效匹配错误问题(pr#578@Github)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.6.8
-
-### 新特性
-* 【core】 ArrayUtil.isEmpty可变长参数改为数组(issue#555@Github)
-* 【core】 新增Convert.toMap方法(issue#I12ISI@Gitee)
-* 【aop 】 增加返回值获取支持,优化逻辑和接口(pr#561@Github)
-* 【aop 】 改进HtmlUtil.removeHtmlAttr(issue#556@Github)
-* 【crypto】 增加SM3和SM4类
-
-### Bug修复
-* 【extra】 修复Mail中sslEnable无效问题(pr#74@Gitee)
-* 【extra】 修复CsvParser中最后一行双引号没有去除的问题(pr#73@Gitee)
-* 【crypto】 修复SM2算法在自定义密钥时无效问题(issue#I12P5I@Gitee)
-* 【core】 修复StopWatch.prettyPrint条件问题(issue#I12RAC@Gitee)
-* 【core】 修复StrBuilder.del无法删除最后一个字符的问题(issue#I12R14@Gitee)
-* 【poi】 修复sax方式读取复用行导致的问题(issue#I12O0U@Gitee)
-* 【core】 修复ClassUtil循环调用问题
-* 【core】 修复MapConvert转换Bean为Map类型没有转换成功问题
-
--------------------------------------------------------------------------------------------------------------
-
-
-## 4.6.7
-
-### 新特性
-* 【core】 ImgUtil.rotate支持负数(issue#543@Github)
-* 【http】 body方法传null跳过而非报错(issue#I12AP2@Gitee)
-* 【core】 TimeInterval增加intervalPretty方法(issue#I12A6T@Gitee)
-* 【core】 改进ArrayUtil.toString,提高性能
-* 【system】 增加SystemPropsKeys(issue#550@Github)
-* 【core】 FileUtil.normalize在win下支持samba路径(issue#549@Github)
-* 【core】 修复Validator注释错误(pr#70@Gitee)
-* 【cron】 添加获取任务表的方法(issue#I12E5H@Gitee)
-* 【http】 SoapClient增加reset方法用于此对象的复用(issue#I12CCC@Gitee)
-* 【db】 StatementUtil增加setParam方法
-* 【db】 Entity.fieldList改为有序实现
-* 【crypto】 AES、DES增加对ZeroPadding的支持(issue#551@Github)
-* 【db】 优化批量插入代码,减少类型判断导致的性能问题(issue#I12B4Z@Gitee)
-* 【db】 优化SQL日志格式和日志显示
-
-### Bug修复
-* 【core】 修复DateUtil.offset导致的时区错误问题(issue#I1294O@Gitee)
-* 【core】 修复RuntimeUtil.exec重载导致的问题(issue#544@Github)
-* 【db】 修复StatementUtil.getGeneratedKeys返回主键数量不足问题
-* 【db】 修复锁的问题(issue#546@Github)
-* 【db】 修复CombinationAnnotationElement问题(issue#547@Github)
-* 【core】 修复Validator.isGeneral问题
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.6.6
-
-### 新特性
-* 【core】 MapUtil增加newConcurrentHashMap(pr#538@Github)
-* 【core】 增加StopWatch(issue#539@Github)
-* 【core】 增加ZipUtil.listFiles(issue#541@Github)
-
-### Bug修复
-* 【core】 修复DateUtil.endOfYear计算错误问题(issuepr#540@Github)
-* 【core】 修复FileUtil.listFileNames在jar中匹配问题,增加(issuepr#541@Github)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.6.5
-
-### 新特性
-* 【core】 CollUtil增加filterNew等方法(原filter变更为filterNew,新增filter)
-* 【crypto】 Sign增加setParameter方法
-* 【extra】 Sftp得put方法增加进度支持(issue#518@Github)
-* 【core】 ArrayUtil增加distinct方法
-* 【http】 去除log模块依赖,Cookie中去除日志提示,body方法传入JSON对象废弃,未来移除json模块依赖
-* 【extra】 添加MyNLP支持(issue#519@Github)
-* 【json】 添加自定义序列化反序列化支持(issue#I1052A@Gitee)
-* 【dfa】 优化特殊字符构建,优化查找,改为使用StrBuilder
-* 【core】 ZipUtil增加FileFilter参数的重载,支持文件过滤(issue#I11RTP@Gitee)
-* 【http】 HttpRequest增加setChunkedStreamingMode方法(issue#525@Github)
-* 【setting】 SettingLoader支持自定义分隔符
-* 【http】 Content-Type添加默认值(issue#I11YHI@Gitee)
-* 【socket】 增加Closeable接口(issue#532@Github)
-* 【core】 CollUtil增加min和max方法
-
-### Bug修复
-* 【core】 修复NetUtil.getUsableLocalPort问题(pr#69@Gitee)
-* 【core】 修复MathUtil.arrangementSelect重复元素导致无结果问题(issue#529@Gitee)
-* 【core】 修复RandomUtil.randomEleSet越界问题(issue#535@Gitee)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.6.4
-
-### 新特性
-* 【http】 自动关闭HttpURLConnection的头安全检查(issue#512@Github)
-* 【setting】 Setting变量替换支持从系统参数中取值(issue#I11BV1@Gitee)
-* 【core】 改进NumberUtil.isNumber方法(pr#68@Gitee)
-* 【system】 增加Oshi工具封装
-
-### Bug修复
-* 【db】 解决ThreadLocalConnection多数据源被移除问题(pr#66@Gitee)
-* 【core】 解决ArrayUtil.emptyCount计数错误问题(issue#509@Github)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.6.3
-
-### 新特性
-* 【core】 改进CollUtil.zip逻辑,减少内存复制(issue#I10T01@Gitee)
-* 【extra】 邮件增加图片支持(pr#495@Github)
-* 【core】 MapUtil、CollUtil增加emptyIfNull(issue#502@Github)
-* 【core】 增加emptyIfNull等(issue#503@Github)
-* 【setting】 Props增加toBean方法(issue#499@Github)
-* 【poi】 CellUtil增加getMergedRegionValue方法,ExcelWriter增加getDisposition方法
-* 【http】 HttpBase增加headerMap方法
-* 【core】 FileUtil.loopFile增加重载,支持定义深度
-
-### Bug修复
-* 【http】 修复HttpRquest中body方法长度计算问题(issue#I10UPG@Gitee)
-* 【system】 修复获取本地IP问题(pr#65@Gitee)
-* 【poi】 修复设置单元格样式无效问题
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.6.2
-
-### 新特性
-* 【core】 Tuple增加支持equals和hashcode(issue#469@Github)
-* 【http】 Accept修改默认权重,json优先(issue#472@Github)
-* 【http】 增加HttpGlobalConfig(issue#I10DHC@Gitee)
-* 【core】 CollUtil.getFieldValues避免空指针(issue#I10FK9@Gitee)
-* 【http】 改进HtmlUtil.unescape改为EscapeUtil.unescapeHtml4实现(issue#I10AUY@Gitee)
-* 【core】 TextSimilarity改进判断(issue#456@Github)
-* 【poi】 ExcelWriter支持下拉列表(issue#476@Github)
-* 【core】 强化ExceptionUtil(issue#459@Github)
-* 【core】 增强日期工具类(pr#455@Github)
-* 【setting】 构造Setting增加默认字符编码
-* 【extra】 ServletUtil增加getHeaderMap方法
-* 【poi】 CellUtil改进数字支持,解决空指针问题(pr#489@Github)
-* 【core】 增加DEFAULT_BUFFER_SIZE
-
-### Bug修复
-* 【cache】 修复missCount规则(issue#465@Github)
-* 【core】 修复父目录拷贝到子目录导致的递归问题
-* 【crypto】 修复RSA中分段加密计算导致的异常(issue#481@Github)
-* 【json】 修复TypeReference传入Type类型参数导致的异常(issue#488@Github)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.6.0
-
-### 新特性
-* 【all】 增加hutool-bom模块,用于可排除的依赖引入
-* 【core】 ResourceUtil增加readBytes方法
-* 【captcha】 更换为逻辑字体
-* 【extra】 Mail增加reply(issue#445@Github)
-* 【core】 去掉重复方法(issue#IZQYR@Gitee)
-* 【db】 改进结果集转Bean的下划线和驼峰兼容性(issue#IZOPL@Gitee)
-* 【system】 增加JavaInfo对新版本java的支持(pr#454@Github)
-* 【extra】 增加可选标志位,是否返回当前目录(issue#446@Github)
-
-### Bug修复
-* 【core】 修复ImgUtil.slice宽高取反问题(issue#438@Github)
-* 【crypto】 修复MD516位摘要长度错误问题(issue#IZNPE@Gitee)
-* 【core】 修复ImgUtil.hexToColor调用参数问题(issue#449@Github)
-* 【http】 修复可能存在的Http请求结束未关闭连接的情况(issue#449@Github)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.5.18
-
-### 新特性
-* 【poi】 增加ExcelUtil.getWriterWithSheet方法(感谢@【长沙】NULL)
-* 【core】 EnumUtil和ObjectUtil增加方法(pr#57@Gitee)
-* 【core】 EnumUtil增加fromString重载支持默认值(issue#IZFXJ@Gitee)
-* 【core】 DateUtil.parse增加Locale对象重载(issue#437@Github)
-
-### Bug修复
-* 【core】 修复无效的日志打印(issue#IZFW9@Gitee)
-* 【core】 修复Validator.isBirthday注释(issue#IZFMG@Gitee)
-* 【core】 修复TextSimilarity 的bug(issue#435@Github)
-* 【core】 修复Tailer预读取行bug(issue#IZHAT@Gitee)
-* 【core】 修复使用slf4j-simple不打印日志问题
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.5.17
-
-### 新特性
-* 【http】 SoapClient增加超时设置(issue#IYQHK@Gitee)
-* 【captcha】 修正验证码位置,增加可选文字透明度(issue#421@Github)
-* 【poi】 ExcelWriter.setRowHeight增加空指针检查(issue#IYN63@Gitee)
-* 【core】 ImgUtil增加copyImage可选背景色(issue#IYX3E@Gitee)
-* 【core】 CollUtil.sub方法在空列表时返回空数组而非null(issue#430@Github)
-* 【core】 改进本地IP地址获取方法(issue#428@Github)
-* 【core】 WatchMonitor增加ClosedWatchServiceException异常处理(issue#427@Github)
-
-### Bug修复
-* 【crypto】 修复DigestUtil.md5方法的注释(issue#IYQHG@Gitee)
-* 【core】 修复MapUtil.newHashMap初始容量问题(issue#IYKJJ@Gitee)
-* 【core】 修复HttpUtil.encodeParam多出=问题(issue#IZ3PI@Gitee)
-* 【core】 修复Img.scale变形问题(issue#431@Gitee)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.5.16
-
-### 新特性
-* 【cache】 缓存增加get重载(pr#404@Github)
-* 【poi】 增加WordUtil
-* 【core】 改进fnvHash避免负数(issue#IYDK6@Gitee)
-* 【core】 改进BeanCoper逻辑(pr#45@Gitee)
-* 【all】 实现必要序列化接口
-* 【db】 Entity增加可选忽略大小写(issue#IYGVW@Gitee)
-* 【core】 MapUtil增加renameKey方法(感谢@【帝都】宁静)
-
-### Bug修复
-* 【poi】 修复sax中读取Excel普通单元格设置日期格式识别问题(issue#IYD0L@Gitee)
-* 【http】 修复setParam非String值失效问题(issue#IYF9Y@Gitee)
-* 【core】 修复FileUtil.cleanEmpty第二层直接删除文件夹的问题(感谢@【上海】风景)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.5.15
-
-### 新特性
-
-### Bug修复
-* 【extra】 修复JschUtil.exec不执行命名的问题(issue#405@Github)
-* 【http】 修复CookieManager全局设定导致的可能存在的冲突,增加自定义的GlobalCookieManager
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.5.14
-
-### 新特性
-* 【poi】 增加TableUtil
-* 【http】 HttpRequest增加setCookieManager方法
-* 【http】 改进url错误时的报错信息(感谢@【北京】thumb)
-
-### Bug修复
-* 【core】 修复ZipUtil.zlib压缩识别问题(感谢@【上海】 沙漏)
-* 【log】 调整log模块层次结构,兼容slf4j的API(issue#IY8DX@Gitee)
-* 【core】 Convert.toXXX带默认值换成convertQuietly实现,避免异常(issue#403@Gitee)
-* 【log】 解决行号错误问题
-* 【log】 修复decimalFormatMoney中整数丢失问题(issue#IY9OV@Gitee)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.5.13
-
-### 新特性
-* 【crypto】 提供HmacSM3支持(issue#396@Github)
-* 【setting】 SettingLoader添加同步锁(issue#396@Github)
-
-### Bug修复
-* 【log】 修复log模块模板拼接时没有判断等级关闭与否的问题
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.5.12
-
-### 新特性
-* 【json】 解析JSON字符串去除两边空白符(同时解决字符串中bom问题(issue#381@Github)
-* 【poi】 Sax解析增加在异常后关闭文件的逻辑(issue#IXBOU@Gitee)
-* 【core】 MapUtil增加get重载(TypeReference)(issue#IXL81@Gitee)
-* 【crypto】 RC4增加encryptHex和encryptBase64方法(issue#387@Github)
-* 【core】 DateUtil.parse增加格式(issue#385@Github)
-* 【core】 增加CollUtil.containsAny(感谢【北京】宁静)
-* 【core】 增加CollUtil.keySet和values(issue#IXYQJ@Gitee)
-
-### Bug修复
-* 【poi】 解决三目运算符导致类型转换问题(issue#385@Github)
-* 【core】 解决NumberUtil.decimalFormatMoney格式错误问题(issue#391@Github)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.5.11
-
-### 新特性
-* 【core】 DateUtil.parse方法识别时间增强(issue#IWMM6@Gitee)
-* 【extra】 Mail中Files附件可选为空(issue#365@Github)
-* 【extra】 EmojiUtil增加containsEmoji方法(pr#373@Github)
-* 【core】 Convert.toDBC()增加空校验(issue#369@Github)
-
-### Bug修复
-* 【core】 修复NumberUtil.decimalFormatMoney只有整数的bug(issue#IWKVL@Gitee)
-* 【bloomFilter】 修复BitMapBloomFilter构造数bug(issue#IWMIN@Gitee)
-* 【extra】 MailUtil.send方法传入自定义Setting失效问题(感谢@【上海】康)
-* 【core】 修复NetUtil.localIpv4s方法名,改为localIps(issue#IWS2C@Gitee)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.5.10
-
-### 新特性
-* 【extra】 修改MailUtil中的逻辑,默认为非单例邮件客户端(issue#IWFRQ@Gitee)
-
-### Bug修复
-* 【http】 修复HttpUtil.toParams方法某些符号未转义问题(issue#356@Github)
-* 【captcha】 修复验证码被遮挡问题(issue#IWERW@Gitee)
-* 【poi】 修复readBySax重复问题(issue#IVKLQ@Gitee)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.5.9
-
-### 新特性
-* 【core】 修改Singleton单例策略,IdUtil增加getSnowflake(issue#IWA0G@Gitee)
-* 【core】 增加RandomUtil.randomBoolean(issue#351@Github)
-* 【core】 增加Base62实现,Base62类
-
-### Bug修复
-* 【json】 修复JSON中含有日期导致的时间戳包含双引号问题
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.5.8
-
-### 新特性
-* 【cron】 CronPatternUtil增加nextDateAfter方法(issue#IVYNL@Github)
-* 【core】 增加RandomUtil.randomDate方法(issue#IW49T@Github)
-* 【db】 Table增加comment字段,调整元信息逻辑(issue#IW49S@Gitee)
-* 【core】 增加ConcurrencyTester(pr#41@Gitee)
-* 【core】 ZipUtil增加对流的解压支持(issue#IW798@Gitee)
-
-### Bug修复
-* 【core】 修复Enjoy模板创建多个引擎报错问题(issue#344@Github)
-* 【crypto】 修复Linux下RSA/ECB/PKCS1Padding算法无效问题
-* 【core】 修复ImgUtil.scale方法操作png图片透明失效问题(issue#341@Github)
-* 【core】 修复JSON自定义日期格式无引号问题(issue#IW4F6@Gitee)
-* 【core】 修复Android下CallerUtil.getCallerCaller空指针问题(issue#IW68U@Gitee)
-* 【cache】 修复Cache中超时太大导致Long越界问题(issue#347@Github)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.5.7
-
-### 新特性
-* 【core】 新增StrClipboardListener(issue#325@Github)
-* 【core】 新增DesktopUtil(issue#326@Github)
-* 【core】 CollUtil.getFieldValues增加可选是否忽略null值(issue#IVGEE@Gitee)
-* 【http】 新增SoapUtil,SoapClient支持返回SOAPMessage
-* 【core】 RobotUtil增加鼠标相关操作
-* 【core】 增加DateModifier,DateUtil增加truncate和ceiling方法(issue#IVL9A@Gitee)
-* 【core】 PageUtil增加getStart(issue#IVN0C@Gitee)
-* 【core】 CopyOptions增加ignoreXXX方法(感谢@【南昌】...)
-* 【core】 ObjectUtil增加isEmpty方法(感谢@【成都】AliK)
-
-### Bug修复
-* 【core】 修复PatternPool中的URL_HTTP不支持端口的问题(issue#IVF1V@Gitee)
-* 【extra】 修复JschUtil.exec多次connect的问题(issue#339@Github)
-* 【http】 修复SoapUtil.toString乱码问题(pr#337@Github)
-* 【http】 解决Cookie不规范导致的请求响应失败问题(issue#336@Github)
-* 【setting】 GroupedMap增加读写锁解决并发问题(issue#336@Github)
-* 【json】 修复JSONArray中add方法导致覆盖问题(感谢@【江门】小草哥)
-* 【core】 修复Convert对泛型支持不完善的问题(issue#IVMD5@Gitee)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.5.6
-
-### 新特性
-* 【http】 SoapClient增加setParams,增加构造使用默认的namespaceURI方法
-* 【core】 FileUtil增加cleanEmpty方法(issue#319@Github)
-* 【core】 增加ClipboardMonitor(issue#320@Github)
-* 【http】 SoapClient增加部分方法
-* 【http】 HttpRequest增加setConnectionTimeout和setReadTimeout(issue#322@Github)
-* 【core】 Console增printPrograss
-* 【core】 DateBetween增加null校验(issue#IVC23@Gitee)
-* 【core】 增加CollUtil.getFieldValues重载(issue#IV96S@Gitee)
-* 【db】 SqlExecutor和Db增加executeBatch重载,支持批量SQL(issue#324@Github)
-
-### Bug修复
-* 【bloomFilter】修复负数导致的问题(issue#IV6X6@Gitee)
-* 【setting】 修复Props监听问题
-* 【json】 修复TypeUtil中空指针导致的注入失败问题(issue#IVCLW@Gitee)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.5.5
-
-### 新特性
-
-### Bug修复
-* 【core】 Assert中NullPointerException改为IllegalArgumentException(issue#IV41L@Gitee)
-* 【core】 修复创建新sheet时比较器未清空导致的顺序问题(issue#318@Github)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.5.4
-
-### 新特性
-* 【core】 NetUtil增加getUsableLocalPort方法,并迁移至cn.hutool.core.net包
-* 【core】 FileUtil增加isSub方法(pr#39@Gitee)
-* 【core】 增加VoidFunc
-* 【extra】 mail适配mail.setting和config/mail.setting双配置文件(感谢@【江门】小草哥)
-* 【corn】 cron适配cron.setting和config/cron.setting双配置文件(感谢@【江门】小草哥)
-* 【poi】 ExcelWriter增加autoSizeColumnAll方法,ExcelBase增加getColumnCount、getRowCount方法(感谢@@【长沙】M)
-* 【http】 添加SoapClient,删除SoapRequest
-
-### Bug修复
-* 【db】 修复Session中事务问题(issue#IUQMN@Gitee)
-* 【db】 修复Db中关闭逻辑错误导致的事务问题(感谢@【宁波】mojie126)
-* 【http】 修复form方法使用Resource可能导致的空指针问题
-* 【crypto】 修复SM2Engine逻辑错误(感谢bcgit/bc-java)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.5.3
-
-### 新特性
-* 【core】 Simhash添加读写锁(issue#IUF9O@Gitee)
-* 【core】 Img增加round方法,圆角给定图片
-* 【extra】 二维码中的图片做圆角处理
-* 【core】 CsvData实现Iterable接口
-* 【extra】 Ftp增加重连方法(pr#38@Gitee)
-* 【extra】 Velocity升级至2.x,不再兼容1.7
-
-### Bug修复
-* 【core】 修复ReflectUtil新建Map对象错误问题(issue#IUF9O@Gitee)
-* 【core】 修复ImgUtil字体为null导致的空指针问题(issue#IUF3X@Gitee)
-* 【extra】 修复Ftp中文件上传mkdirs方法创建多余文件夹的问题(issue#ITAYV@Gitee)
-* 【extra】 修复Ftp中文件上传mkdirs方法创建多余文件夹的问题(issue#ITAYV@Gitee)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.5.2
-
-### 新特性
-* 【crypto】 增加读取pem格式私钥文件和公钥证书的方法,位于BCUtil(issue#ISJ5M@Gitee)
-* 【core】 增加StrUtil.byteLength(issue#284@Github)
-* 【core】 增加GlobalBouncyCastleProvider,单例使用BouncyCastleProvider
-* 【crypto】 增强对BC库的兼容性,明确RSA为RSA/ECB/PKCS1Padding
-* 【core】 snowflake生成器添加id反推生成时间等信息的方法(pr#293@Github)
-* 【poi】 CellUtil.getCellValue增加null验证
-* 【core】 增加文件内容跟随器Tailer
-* 【crypto】 增加RC4算法
-* 【core】 增加FixedLinkedHashMap
-* 【extra】 增加ChannelType,JschUtil增加createSession、createChannel、openChannel等方法
-* 【core】 WatchUtil增加createModify
-* 【core】 新增ImgUtil,废弃ImageUtil
-
-### Bug修复
-* 【core】 修复ExceptionUtil(pr#35@Gitee)
-* 【core】 修复RandomUtil注释标注问题(pr#288@Github)
-* 【core】 修复TimedCache中onRemove失效问题(issue#ITD0O@Gitee)
-* 【core】 修复DateConverter日期负数问题(issue#ITWK4@Gitee)
-* 【json】 修复toBean时父类定义泛型字段导致的注入问题(issue#ITGGN@Gitee)
-* 【cahce】 修复读锁导致的LRU异常(issue#303@Gtihub)
-* 【captcha】 修复在某些未知情况下获取字体高度导致的问题
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.5.1
-
-### 新特性
-* 【socket】 socket模块加入到all中
-* 【core】 增加Jdk8DateConverter用于支持jdk8中的时间(issue#IS32N@Gitee)
-* 【core】 StrUtil.subPreGbk优化代码规范(pull#277@Github)
-* 【crypto】 MD5支持16位值生成
-* 【crypto】 Digester支持自定义盐所在位置
-* 【captcha】 增加算数计算类验证码(issue#282@Github)
-
-### Bug修复
-* 【json】 修复JSON中toString导致的中文引号被转义问题(感谢@【内蒙】程序员)
-* 【core】 修复15位身份证生日校验问题(issue#ISBUO@Gitee)
-* 【extra】 修复部分模板引擎classpath路径获取失败问题
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.5.0
-
-### 新特性
-* 【socket】 增加Socket模块
-* 【core】 Validator增加isIpV4方法(issue#IRQ6W@Gitee)
-* 【crypto】 增加SM2Engine,支持C1C2C3和C1C3C2两种模式
-* 【core】 StrUtil.splitTrim支持其它空白符(issue#IRVPC@Gitee)
-* 【http】 请求支持DELETE附带参数模式(issue#IRW9E@Gitee)
-* 【bloomFilter】调整BitMap注释
-
-### Bug修复
-* 【crypto】 修复KeyUtil中使用BC库导致的其它密钥生成异常
-* 【core】 修正DateUtil.formatHttpDate方法
-* 【extra】 修复FTP.ls无法遍历文件问题(issue#IRTA3@Gitee)
-* 【extra】 修复QrCodeUtil中ratio参数失效问题,调整默认纠错为M(感谢@【上海】皮皮今)
-* 【core】 修复FileTypeUtil对jpg文件识别问题(issue#275@Github)
-* 【cache】 修复cache使用读锁导致的删除节点并发问题(issue#IRZTL@Gitee)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.4.5
-
-### 新特性
-* 【core】 增加StrFormater代码逻辑可读性(pr#269@Github)
-* 【core】 Validator中使用泛型
-* 【core】 NumberUtil增加toBytes和toInt方法
-* 【core】 XmlUtil增加format方法,支持缩进
-* 【http】 SoapRequest增加executeBody方法(issue#IRN6I@Gitee)
-* 【core】 调整XmlUtil.toStr方法对编码的逻辑
-
-### Bug修复
-* 【core】 修复AnnotationUtil.getAnnotationValue获取对象错误问题(issue#271@Github)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.4.4
-
-### 新特性
-* 【crypto】 增加EC公钥压缩/解压缩(pr#264@Github)
-* 【db】 Entity支持IS NOT NULL形式,调整逻辑,强化Condition的toString(issue#267@Github)
-
-### Bug修复
-* 【core】 修复Profile中路径参数失效问题(issue#265@Github)
-* 【core】 修复MapConvert中值类型转换错误的问题(issue#268@Github)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.4.3
-
-### 新特性
-* 【crypto】 MD5以及Digester增加加盐支持(issue#256@Github)
-* 【crypto】 整理KeyUtil,减少冗余代码
-* 【core】 增加Zodiac类,DateUtil增加getZodiac、getChineseZodiac用于获取星座和生肖(issue#260@Github)
-
-### Bug修复
-* 【core】 修复ExceptionUtil.stacktraceToString中limit参数无效问题(issue#IR7UE@Gitee)
-* 【core】 修复StrUtil.repeatByLength中数组越界问题(issue#IRB2C@Gitee)
-* 【core】 修复FileUtil.remove移动后删除失败问题(issue#IRF8R@Gitee)
-* 【extra】 修复Ftp中delDir逻辑导致的问题(issue#IRCQ8@Gitee)
-* 【core】 修复XmlUtil.mapToXml中map值为空导致的空指针问题。(issue#IRD7X@Gitee)
-* 【poi】 修复ExcelWriter中setOnlyAlias没有排除值的问题。(issue#IRF9L@Gitee)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.4.2
-
-### 新特性
-* 【core】 JSON中添加getStrEscaped方法,并修改原getStr逻辑,不再自动转义(issue#IR7SW@Gitee)
-* 【core】 CLassLoaderUtil增加getJarClassLoader和loadClass重载方法(issue#IR94T@Gitee)
-* 【crypto】 SM2密钥生成曲线修改为使用sm2p256v1(pr#249@Github)
-* 【json】 JSONUtil增加空判断(issue#253@Github)
-* 【core】 改进HexUtil.isHexNumber(issue#254@Github)
-* 【http】 HttpRequest增加getConnection方法(issue#251@Github)
-
-### Bug修复
-* 【core】 修复URL转义问题(issue#IR6QP@Gitee)
-* 【core】 修复WeightRandom权重为0的对象问题(issue#252@Github)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.4.1
-
-### 新特性
-* 【core】 增加Rot(回转N位简易替换密码)、凯撒密码和莫尔斯电码
-* 【crypto】 增加Vigenere密码
-* 【db】 增加达梦7的驱动识别
-* 【extra】 TemplateEngine适配更广泛的参数类型
-* 【core】 HexUtil增加toHex方法,增加CRC8和CRC16(issue#IQWNB@Gitee)
-* 【http】 添加text/xml ContentType(pr#31@Gitee)
-* 【core】 Img、ImageUtil增加Resource和Path参数支持
-* 【extra】 ServletUtil.getClientIP增加注释,提示IP伪造风险
-* 【poi】 增加Word07Writer
-* 【crypto】 增加KeyUtil,SecureUtil中的密钥生成迁移至此工具类中
-* 【core】 增加URLEncoder(自行实现解决空格转义问题),HttpUtil废弃encode和decode方法
-
-### Bug修复
-* 【poi】 解决ExcelWriter中setSheet报错问题(issue#235@Github)
-* 【crypto】 解决SecureUtil.readCertificate密码无效问题(issue#240@Github)
-* 【json】 修复JSONUtil.toList针对对象中的类无法实例化导致的null问题(issue#239@Github)
-* 【db】 修复MongoDS在Single模式下检查配置文件导致的问题(issue#IR2BF@Github)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.4.0
-
-### 新特性
-* 【core】 增加MurmurHash(Murmur3算法实现),HashUtil增加murmur32、murmur64、murmur128方法
-* 【core】 增加Simhash(用于海量文本去重)
-* 【extra】 增加分词封装,封装了ansj、HanLP、IKAnalyzer、Jcseg、Jieba、MMSeg、Lucene-analysis、Word的实现,统一了接口
-* 【core】 去除NumberUtil.parseInt和parseLong的8进制支持(issue#234@Github)
-* 【extra】 Template部分修改命名减少歧义(Engine->TemplateEngine,EngineFactory->TemplateFactory)
-* 【poi】 ExcelWriter中Map支持alias(issue#IQISU@Gitee)
-
-### Bug修复
-
-## 4.3.3
-
-### 新特性
-* 【poi】 ExcelWriter增加write重载,可选强制加标题(感谢@【北京】大熊)
-* 【core】 ExceptionUtil增加isFromOrSuppressedThrowable(pr#29@Gitee)
-* 【core】 ExceptionUtil增加convertFromOrSuppressedThrowable(pr#30@Gitee)
-* 【crypto】 非对称和SM2构造传入的私钥和公钥支持Hex和Base64自动识别
-
-### Bug修复
-* 【core】 修复padAfter和padPre结果错误问题(issue#IQANO@Gitee)
-* 【crypto】 修复SM2签名验证异常(issue#IQAY0@Gitee)
-* 【extra】 修复Freemarker字符串模板无效问题(issue#231@Github)
-* 【core】 修复StrUtil.strip问题(issue#232@Github)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.3.2
-
-### 新特性
-* 【core】 StrUtil增加equalsAny和equalsAnyIgnoreCase方法(issue#IPUQK@Gitee)
-* 【http】 StrUtil增加equalsAny和equalsAnyIgnoreCase方法(issue#223@Github)
-* 【http】 StrUtil增加padPre、padAfter、center方法(issue#IPWR0@Gitee)
-* 【core】 ImageUtil增加compress方法(issue#IPYIF@Gitee)
-* 【core】 ReflectUtil增加getMethodByName、getMethodByNameIgnoreCase(issue#IQ2BO@Gitee)
-* 【crypto】 增加SmUtil国密算法工具类(issue#225@Github)
-* 【crypto】 增加SM2非对称加密(issue#225@Github)
-* 【db】 增加AbstractDSFactory,减少冗余代码
-* 【json】 JSONUtil.toBean增加可选是否忽略错误(issue@227@Gtihub)
-
-### Bug修复
-* 【core】 修复FileUtil.lastIndexOfSeparator空指针问题(issue#IPXPK@Gitee)
-* 【core】 修复ArrayUtil.newArray泛型问题
-* 【core】 修复CsvWriter循环调用问题(issue#IQ8T6@Gitee)
-* 【poi】 修复ExcelReader读取Map空头导致的问题(issue#IQ6F2@Gitee)
-* 【db】 修复Driver识别导致的SQL Server方言异常(issue#IQ687@Gitee)
-* 【core】 修复Number.isInteger和isLong判断问题(issue#229@Github)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.3.1
-
-### 新特性
-* 【core】 新增DateUtil.dateNew方法(issue#217@Github)
-* 【extra】 JschUtil.exec增加重载,可选错误输出(issue#IPNAB@Gitee)
-* 【core】 增加NoLock(issue#218@Github)
-* 【core】 QrCode.decode改进
-* 【core】 合并无必要的构造方法
-* 【setting】 Setting.getMap方法在分组不存在时返回空Map而非null(issue#IPU2X@Gitee)
-
-### Bug修复
-* 【db】 解决数据源识别错误问题(issue#IPNI7@Gitee)
-* 【core】 修复DateField.of缺失字段问题(issue#IPP51@Gitee)
-* 【core】 JSONObject中忽略空值失效问题(issue#221@Github)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.3.0
-
-### 新特性
-* 【core】 增加TypeReference类(issue#IPAML@Gitee)
-* 【json】 支持TypeReference类转换,并对toBean逻辑做了大量变动(issue#IPAML@Gitee)
-* 【core】 ArrayUtil.get和CollUtil.get返回null而非空指针(issue#IPKZO@Gitee)
-
-### Bug修复
-* 【extra】 修复VelocityEngine中模板中文乱码问题(issue#216@Github)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.2.2
-
-### 新特性
-* 【json】 JSONObject调整构造方法,支持对象转为JSON可选是否有序(issue#IP1Q2@Gitee)
-* 【core】 BeanUtil增加hasGetter和hasSetter方法
-* 【core】 StrUtil增加isUperCase和isLowerCase方法,增加removeAll和removeAllLineBreaks(issue#IP7PT@Gitee)
-* 【db】 增加PostgreSQL的单元测试
-* 【core】 ArrayUtil增加sub方法泛型支持
-* 【core】 从Apache-commons-lang3移植Builder(issue#IPALY@Gitee)
-* 【core】 增加Func1接口,ReUtil和StrUtil增加Func1参数的replace方法(pr#27@Gitee)
-* 【db】 Table增加getColumn方法,Column补充注释(issue#209@Github)
-
-### Bug修复
-* 【cron】 修复L代表的最后一天无效问题(issue#IP5PB@Gitee)
-* 【core】 修复验证15位身份证月的判断问题(issue#IP70D@Gitee)
-* 【poi】 修复多次调用write方法写出多个标题问题(issue#212@Github)
-* 【extra】 修复模板写出文件空白问题(issue#208@Github)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.2.1
-
-### 新特性
-* 【extra】 增加基于emoji-java的EmojiUtil
-* 【http】 增加User-agent解析
-* 【crypto】 引入bouncycastle从而对国密SM2、SM3、SM4支持
-* 【poi】 新增ExcelFileUtil,改进错误提示
-
-### Bug修复
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.1.22
-
-### 新特性
-* 【core】 BeanUtil.copyProperties方法支持目标为Map(issue#IOQHZ@Gitee)
-* 【poi】 ExcelWriter增加方法setOnlyAlias,用于特定字段剔除(issue#IOOVK@Gitee)
-* 【captcha】 增加setBackground方法(issue#200@Github)
-* 【core】 NetUtil增加idnToASCII方法(issue#201@Github)
-* 【log】 增加JBoss-Logging支持(issue#IOVS1@Gitee)
-* 【http】 增加URL标准化,从而支持非http开头的URL字符串
-
-### Bug修复
-* 【core】 修复Validator.isBirthday
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.1.21
-
-### 新特性
-* 【core】 RuntimeUtil增加getErrorResult方法(issue#199@Github)
-* 【core】 ReflectUtil增加hasField方法(感谢@【杭州】J辉)
-* 【core】 BeanUtil增加toBean方法(感谢@【杭州】J辉)
-* 【db】 增加对HSQLDB支持,改进Driver自定识别
-
-### Bug修复
-* 【core】 修复EnumUtil.getFieldNames定义name属性重复问题(感谢@【杭州】J辉)
-* 【json】 修复List多层嵌套toBean转换失败问题
-* 【core】 修复ObjectUtil.toString问题(issue#IONLA@Gitee)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.1.20
-
-### 新特性
-* 【http】 增强SoapRequest的兼容性(感谢@【南京】陽光)
-* 【core】 改进ZipUtil错误提示
-* 【core】 DateUtil.parse方法读取时间时,年月日按照当天计算。(issue#INYCF@Gitee)
-* 【core】 DateUtil.parse改进支持UTC时间格式。
-* 【db】 MongoDS支持客户端验证(issue#IO2DS@Gitee)
-* 【core】 改进字符串转集合和数组(支持逗号分隔形式)(pr#26@Gitee)
-* 【core】 改进DateConverter(issue#IOCWR@Gitee)
-* 【core】 改进NumberUtil中转数字,支持字母结尾(issue#IOCWR@Gitee)
-* 【poi】 ExcelUtil增加indexToColName和colNameToIndex方法(issue#IO8ZH@Gitee)
-* 【core】 Convert.toList修改为泛型(issue#IOJZV@Gitee)
-* 【core】 BeanDesc中属性修改为使用LinkedHashMap存储
-* 【core】 ArrayUtil.get和CollUtil.get对于越界返回null而非抛出异常(issue#IOFKL@Gitee)
-* 【core】 EnumUtil增加likeValueOf方法(issue#IOFKL@Gitee)
-* 【core】 删除CollUtil.sortPageAll2方法,增加ColllUtil.page方法
-
-### Bug修复
-* 【core】 修正CollUtil.sortPageAll逻辑(pr#186@Github)
-* 【core】 修复ClassLoaderUtil.loadClass不能加载内部类问题(issue#IO4GF@Gitee)
-* 【core】 修复CustomKeyLinkedMap继承问题(issue#IO5Y2@Gitee)
-* 【core】 修复NumberUtil.isPrimes没有参数校验导致的问题(issue#IO57Q@Gitee)
-* 【extra】 修复QrConfig 引入包错误问题(pr#194@Github)
-* 【extra】 修复Sftp创建目录问题(issue#INZUP@Gitee)
-* 【core】 修复CollUtil.sortPageAll方法
-* 【core】 修复ImageUtil图片旋转出现黑边问题(pr#189@Github)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.1.19
-
-### 新特性
-* 【extra】 Ftp增加setMode方法(issue#INPMZ@Gitee)
-* 【core】 IdUtil增加fastUUID和fastSimpleUUID方法(issue#INU37@Gitee)
-* 【core】 DateUtil增加formatChineseDate方法(issue#INT6I@Gitee)
-* 【core】 ClassUtil中部分方法迁移至ReflectUtil
-* 【json】 新增JSONConfig,统一JSON配置,并添加可选的自定义输出日期格式支持
-
-### Bug修复
-* 【core】 修复ImageUtil文件流未关闭问题(感谢@【西安】追寻)
-* 【core】 修复ZipUtil中gzip和zlib方法未调用finish导致的问题(issue#INSXF@Gitee)
-* 【core】 修复ZipUtil中文件目录同名无法压缩的问题(issue#INQ1K@Gitee)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.1.18
-
-### 新特性
-* 【http】 改进字符串匹配正则(issue#INHPD@Gitee)
-* 【core】 增加gzip和UnGzip针对流的方法(issue#INKMP@Gitee)
-* 【http】 增加ThreadLocalCookieStore
-
-### Bug修复
-* 【core】 修复BeanUtil.copyProperties参数多余问题
-* 【cron】 修复表达式匹配错误问题(issue#INLEE@Gitee)
-* 【core】 修复ReflectUtil获取空参数方法导致的问题(issue#INN5W@Gitee)
-* 【json】 修复JSONArray.toList方法导致的问题(issue#INO3F@Gitee)
-* 【core】 修复NumberUtil.parseLong中0转换问题方法导致的问题(issue#INO3F@Gitee)
-* 【core】 修复CompareUtil循环引用问题(issue#180@Github)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.1.17
-
-### 新特性
-
-### Bug修复
-* 【core】 修复JDK7之后比较器中违反自反性导致的问题
-* 【cron】 修改部分逻辑
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.1.16
-
-### 新特性
-* 【core】 Convert.增加boolean类型转数字(issue#INCKM@Gitee)
-* 【core】 新增BooleanUtil
-
-### Bug修复
-* 【core】 修复JDK11下Caller被弃用导致的问题(issue#174@Github)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.1.15
-
-### 新特性
-* 【core】 Convert.toInt增加容错,NumberUtil增加toNumber方法(issue#IN2LP@Gitee)
-* 【core】 ImageUtil增加cut切圆形方法(issue#IN3JJ@Gitee)
-* 【core】 Img增加setPositionBaseCentre可选坐标计算基于中心(issue#IN3JM@Gitee)
-* 【core】 ImageUtil增加逻辑判断颜色模式,避免失色问题(issue#IN3JK@Gitee)
-* 【cron】 改进规则支持20/2这类形式
-* 【extra】 ServletUtil.write增加重载方法支持文件(issue#IN9O0@Gitee)
-
-### Bug修复
-* 【core】 修复DateUtil.yearAndQuarter计算错误的问题(issue#IN38V@Gitee)
-* 【core】 修复ClassUtil.isPublic判断问题(issue#IN38V@Gitee)
-* 【extra】 修复JschUtil中Session关闭未移除出池导致的问题(issue#171@Github)
-* 【core】 修复NumberUtil.isInteger中0判断问题(issue#IN9BS@Gitee)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.1.14
-
-### 新特性
-* 【core】 StrUtil增加hide方法
-* 【core】 PatternPool增加URL_HTTP,原URL规则变更
-* 【extra】 统一FTP和SFTP接口规范
-* 【extra】 QrCodeUtil支持二维码中贴Logo图片
-* 【core】 校准ImageUtil.pressText文字位置
-* 【core】 ImageUtil增加getColor等方法
-* 【core】 增加RobotUtil提供截屏等封装,增加ScreenUtil用于获取屏幕属性
-* 【extra】 QrCodeUtil增加条形码等其它类型支持(issue#IN1CR@Gitee)
-* 【core】 增加DateUtil.parseUTC方法(issue#IN1IO@Gitee)
-* 【core】 增加DateUtil.isWeekend方法
-* 【all】 加入Travis-CI验证项目构建
-
-### Bug修复
-* 【core】 修复ImageUtil.convert转换png变色问题(issue#IMWUO@Gitee)
-* 【core】 修复FileUtil.newerThan中null判断的问题(issue#165@Github)
-* 【extra】 修复Ftp中mkdir方法引起的数组越界问题
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.1.13
-
-### 新特性
-* 【core】 增加RejectPolicy线程池线程拒绝策略枚举
-* 【core】 DateUtil增加isSame方法
-* 【core】 FileUtil.getAbsolutePath方法在获取不到ClassPath情况下返回原路径
-* 【core】 打印SQL日志覆盖每一个方法
-* 【core】 Convert.toXXX转数字的时候默认去除两边空白符
-* 【poi】 增加BigExcelWriter,支持Excel大数据导出(issue#IK47S@Gitee)
-* 【core】 ExceptionUtil增加isCausedBy和getCausedBy方法
-* 【poi】 EnumUtil增加toString和fromString
-* 【poi】 新增IdUtil工具类
-
-### Bug修复
-* 【core】 修复RuntimeUtil.getResultLines未关闭Process问题(pr#164@Github)
-* 【core】 修复ClassPathResource在jar运行模式下的空指针问题
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.1.12
-
-### 新特性
-* 【core】 ExcelReader.read方法返回的Map默认有序
-
-### Bug修复
-* 【core】 修复ZipUtil以及FileUtil中slip漏洞(issue#162@Github)
-* 【core】 修复ZipUtil路径问题(issue#IMUEK@Gitee)
-* 【core】 修复FileUtil.getParent方法获取父路径不严格导致空指针问题
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.1.11
-
-### 新特性
-* 【core】 Convert增加toList方法
-* 【core】 StrUtil增加containsAny针对char的重载
-* 【core】 FileUtil.mainName修正处理逻辑
-* 【core】 CharUtil增加isFileSeparator方法
-* 【core】 增加UUID类,提升Simple模式下性能
-* 【poi】 ExcelUtil增加setStyleSet方法,修改write逻辑,对于单列数据输出,而非忽略(感谢@【宁波】mojie126)
-* 【core】 新增WebAppResource类
-* 【extra】 新增Thymeleaf模板支持
-* 【setting】 去除Setting日志
-
-### Bug修复
-* 【script】 修复FullSupportScriptEngine构造中ext和mimeType方式获取引擎丢失问题
-* 【cron】 修复定时任务执行阻塞问题
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.1.10
-
-### 新特性
-* 【extra】 Template增加Jfinal的Enjoy模板支持
-* 【core】 Assert增加checkBetween方法,Validator增加isBetween和validatorBetween
-* 【core】 增加CollUtil.getLast方法(感谢@【帝都】宁静)
-* 【core】 修改Assert.notNull注释(issue#IMI3Z@Gitee)
-* 【core】 BeanUtil增加isEmpty和hasNullField方法(pr#157@Github)
-* 【log】 ConsoleLog增加setLevel方法(issue#IMLZ3@Gitee)
-* 【captcha】 解决验证码超出背景的问题(issue#IHWHE@Gitee)
-
-### Bug修复
-* 【core】 修复BOMInputStream构造的问题(pr#22@Gitee)
-* 【json】 修复toBean中如果字段中为字符串而JSON中为JSONObject对象注入失败问题(issue#IMGBJ@Gitee)
-* 【setting】 修复keySet总返回空问题(issue#IMHD7@Gitee)
-* 【extra】 修复starttls和SSL连接混淆问题(issue#IMLMD@Gitee)
-* 【setting】 修复getStr无法获取默认值问题(issue#IMLMI@Gitee)
-* 【core】 修复BeanUtil.mapToBean设置别名失效问题
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.1.9
-
-### 新特性
-* 【core】 MapUtil增加toObjectArray方法
-* 【core】 URLUtil.normalize增加反斜杠处理(issue#IM8BI@Gitee)
-* 【core】 增加ClassUtil.getShortClassName(issue#IM8XM@Gitee)
-* 【core】 增加ThreadFactoryBuilder和ExecutorBuilder
-* 【cron】 定时任务改为线程池实现
-* 【core】 Assert增加checkIndex方法
-* 【core】 parseBoolean增加on、off关键字支持可选字符串
-* 【core】 URLUtil.formatUrl方法兼容更多情况(issue#IMAEA@Gitee)
-* 【core】 改进NumberUtil.isInteger和isLong判断(issue#IMDGB@Gitee)
-* 【http】 HttpResponse增加isOk方法(issue#155@Github)
-* 【http】 改进HttpUtil.downloadXXX方法,返回非2XX抛出异常(issue#IMCTT@Gitee)
-* 【http】 HttpRequest增加setUrlHandler方法(issue#IMD1X@Gitee)
-* 【http】 HttpRequest增加getCookieManager和closeCookie方法(issue#IMDND@Gitee)
-
-### Bug修复
-* 【core】 修复IdcardUtil中isValidCard10空指针问题(issue#IMB7R@Gitee)
-* 【core】 修复SoapRequest空指针问题(issue#IMBUN@Gitee)
-* 【http】 修复文件上传没有关闭File的问题(issue#IMDUY@Gitee)
-* 【json】 修复toBean中有Map参数导致的值丢失问题(issue#IMDEM@Gitee)
-* 【bloomFilter】修复hash值负数问题(issue#154@Github)
-* 【core】 修复Convert中Map强转导致的问题
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.1.8
-
-### 新特性
-* 【http】 HttpRequest增加getUrl、getMethod等方法
-* 【core】 Validator增加isWord和ValidateWord(感谢@【帝都】宁静)
-* 【core】 增加CollUtil.filter针对List的重载(issue#IM1NI@Gitee)
-* 【core】 增加ImageUtil.toBase64
-* 【http】 增加SoapRequest
-* 【poi】 ExcelWriter增加renameSheet方法(issue#150@Github)
-* 【core】 ZipUtil增加unzipFileBytes方法(issue#IM5KO@Gitee)
-* 【aop】 加入Cglib实现的切面支持(issue#IM4Y2@Gitee)
-* 【extra】 加入FTP客户端支持,基于commons-net封装
-
-### Bug修复
-* 【http】 修复编码自动识别的bug(issue#IM33O@Gitee)
-* 【db】 修复Session中ds引起的空指针问题(感谢@【武汉】jellard)
-* 【core】 修复ReflectUtil.newInstance二次调用资源问题(issue#IM51X@Gitee)
-* 【core】 修复ClassScaner包名前缀引起的问题(issue#IM5OJ@Gitee)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.1.7
-
-### 新特性
-* 【db】 SqlRunner被弃用
-
-### Bug修复
-* 【db】 修复Oracle分页问题(issue#ILZDA@Gitee)
-* 【db】 Dialect使用单例
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.1.6
-
-### 新特性
-* 【core】 OptNullBasicTypeGetter增加getDate方法(issue#ILUQM@Gitee)
-* 【core】 RuntimeUtil增加可选环境变量参数(issue#ILV2I@Gitee)
-* 【core】 修改Caller结构
-
-### Bug修复
-* 【db】 修复Oracle分页多一条问题(issue#ILUQM@Gitee)
-* 【poi】 修复ExcelWriter换行问题(issue#ILXLI@Gitee)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.1.5
-
-### 新特性
-* 【poi】 ExcelWriter支持通过别名方式设置Bean写出的顺序(感谢@【武汉】zzz)
-* 【db】 SQL日志打印扩展到所有SQL(感谢@【河北】理想主义)
-* 【core】 增加FileUtil.copyFilesFromDir方法(issue#ILRLG@Gitee)
-* 【core】 EscapeUtil.unescapeHtml4和EscapeUtil.escapeHtml4(issue#112@Github)
-* 【http】 增加CustomProtocolsSSLFactory和AndroidSupportSSLFactory(pr#142@Github)
-* 【setting】 添加SettingUtil(感谢@【杭州】t-io)
-* 【bloomFilter】添加BloomFilterUtil
-* 【core】 添加Img类
-
-### Bug修复
-* 【http】 修复body方法判断Content-Type失效问题(感谢@【上海】皮皮今)
-* 【core】 修复FileUtil.copy方法在目标不存在的情况下报错问题
-* 【core】 修复ClassScaner在Spring boot fat jar下扫描失败的问题(issue#IKDJW@Gitee)
-* 【json】 修复JSONObject构造names列表为空导致的构造空对象(issue#143@Github )
-* 【core】 修复ImageUtil.pressText图片有黑边的问题(issue#141@Github)
-
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.1.4
-
-### 新特性
-* 【all】 补充package-info
-* 【db】 增加方法SqlExecutor.callQuery(issue#ILJ0N@Gitee)
-* 【core】 ExceptionUtil增加部分方法
-* 【system】 SystemUtil增加部分方法
-* 【core】 新增NamedThreadLocal(issue#ILJ0Z@Gitee)
-* 【core】 ZipUtil新增Zlib压缩解压
-* 【core】 NumberUtil增加parseInt和parseLong,支持10进制、8进制和16进制自动识别
-* 【db】 Table继承自LinkedHashMap保证字段读出有序(感谢@【帝都】宁静)
-* 【json】 JSONObject子类自动判断是否有序(感谢@【帝都】宁静)
-* 【poi】 抽象ExcelBase,提取共用方法
-
-### Bug修复
-* 【http】 修复HttpRequest.setFollowRedirects无效问题(issue#ILIKG@Gitee)
-* 【core】 修复CharUtil.isEmoji问题
-* 【http】 修复HttpResponse.writeBody同步模式下写出失败问题
-* 【http】 修复Cookie机制导致的部分Cookie信息不能在请求时附带的问题
-* 【json】 修复JSONArray.toArray转换为原始类型导致的异常问题
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.1.3
-
-### 新特性
-* 【all】 优化db的DsFactory、log的LogFactory、extra的TemplateUtil逻辑,减少异常栈嵌套
-* 【core】 Validator增加isMac、validateMac方法(感谢@【上海】阳仔)
-
-### Bug修复
-* 【core】 修复ArrayUtil.join前后fix失效问题(@【河北】理想主义)
-* 【core】 修复DateRange最后一个元素逻辑问题(issue#ILE38@Gitee)
-* 【cron】 修复调用CronUtil.stop()方法无法正常结束作业进程的问题(issue#ILFCZ@Gitee)
-* 【db】 修复page方法在Oracle中丢失参数问题(issue#ILGXP@Gitee)
-* 【extra】 修复QrCodeUtil.decode对复杂二维码解码失败问题(感谢@【成都】小朋友)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.1.2
-
-### 新特性
-* 【core】 MapUtil增加getDate方法(感谢@【帝都】宁静)
-* 【json】 putByPath方法增加容错性,支持下标越界识别为追加(issue#IKNM6@Gitee)
-* 【core】 增加FileUtil.getParent方法(pr#18@Gitee)
-* 【core】 ImageUtil.pressText增加抗锯齿(pr#19@Gitee)
-* 【core】 BeanUtil.getPropertyDescriptors去除class属性(issue#IKVKR@Gitee)
-* 【json】 putByPath方法针对空的规则变更(issue#IKX2H@Gitee)
-* 【captcha】 增加CodeGenerator,可自定义验证码文字生成策略(issue#IL3YH@Gitee)
-* 【core】 增加CollUtil.list方法,更灵活的创建ArrayList和LinkedList
-* 【core】 DateTime增加时区支持(issue#131@Github)
-* 【extra】 QrCodeUtil二维码生成支持设置边距、颜色等自定义项(issue#135@Github)
-
-### Bug修复
-* 【core】 修复JSONUtil.formatJsonStr引号换行问题(issue#IKMMK@Gitee)
-* 【core】 修复URLUtil.getDecodedPath可能导致的空指针问题(issue#IKLRD@Gitee)
-* 【core】 修复PinyinUtil.getAllFirstLetter非汉字显示问题(issue#IKM0P@Gitee)
-* 【json】 修复当Bean为私有类时无法实例化导致的JSON转换问题(感谢@【上海】风景)
-* 【json】 修复Bean中有Object字段时toBean产生的问题(感谢@【上海】风景)
-* 【core】 修复XmlUtil关闭XXE避免XXE攻击
-* 【poi】 修复Excel03SaxReader读取小数的问题(感谢@【深圳】rm -rf /)
-* 【core】 修复CollUtil.findOne空参数导致的空指针问题(issue#133@Github)
-* 【core】 修复JSONArray.addAll问题(pr#137@Github)
-* 【core】 修复UnicodeUtil单独空格无法转换问题
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.1.1
-
-### 新特性
-* 【poi】 ExcelWriter写出bean使用LinkedHashMap
-* 【core】 UnicodeUtil新增:1、\u大小写不区分,2、\u后跟非16进制按照非Unicode符对待,直接输出(issue#IKJGU@Gitee)
-* 【crypto】 增加Bcrypt实现(参照:jBCrypt)
-* 【core】 XXXIterator修改为XXXIter,同时实现Iterator和Iterable接口
-* 【core】 Dict使用LinkedHashMap,Entity也是
-
-### Bug修复
-* 【setting】 修复store方法无换行问题
-* 【core】 修复UnicodeUtil.toString方法不正确Unicode死循环问题(issue#IKJGU@Gitee)
-* 【http】 修复HttpsURLConnectionOLDImpl导致的转换异常(issue#IKKGF@Gitee)
-* 【crypto】 修复RSA分段加密解密的bug(感谢@【深圳】Demo)
-* 【poi】 修复ExcelWriter写出文件无法覆盖问题(感谢@【宁波】mojie126)
-* 【poi】 修复sax方式读取空行空指针问题(issue#124@Github)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.1.0
-
-### 新特性
-* 【extra】 模板工具改为模板门面,抽象各模板引擎
-* 【core】 修改Season为quarter(pr#114@Github)
-* 【core】 CollUtil增加removeAny方法
-* 【core】 StrUtil增加emptyToDefault和blankToDefault(issue#115@Github)
-* 【core】 优化排列组合算法(感谢@【青岛】LQ)
-* 【core】 NumberUtil增加roundHalfEven(感谢@【青岛】LQ)
-* 【http】 HttpRequest.form支持多文件上传(相同key)(issue#IJYWM@Gitee)
-* 【db】 新增SqlLog,独立SQL日志打印配置
-* 【poi】 ExcelReader新增readAsText方法,ExcelWriter新增setHeaderOrFooter方法(设置页眉页脚)
-* 【crypto】 删除DSA类(DSA算法用在Sign中),修改规则,RSA分段方式变为全局(issue#IKGKG@Gitee)
-* 【core】 DateUtil添加range和rangeToList方法,增加DateRange类(issue#119@Github)
-* 【core】 StrUtil增加concat方法,可选是否null转""(感谢@【帝都】宁静)
-
-### Bug修复
-* 【core】 修复StrUtil.replace方法第一个字符无法替换问题(issue#IJZR0@Gitee)
-* 【core】 修复Season计算问题(pr#114@Github)
-* 【core】 修复PinyinUtil获取拼音特殊字符转数字问题(issue#IJNWH@Gitee)
-* 【core】 修复FileUtil.isAbsolutePath方法正则问题(issue#IJZUB@Gitee)
-* 【extra】 修复ServletUtil.getMultipart方法的问题
-* 【http】 修复patch方法无效问题(issue#IK2Z8@Gitee)
-* 【core】 修复DateUtil.parseTimeToday格式问题(issue#IK25B@Gitee)
-* 【poi】 修复设置字体日期和小数无效问题(issue#IK488@Gitee)
-* 【core】 修复NumberUtil.partValue的bug(pr#15@Gitee)
-* 【poi】 调整了readBySax方式读取导致的部分问题
-* 【core】 修复CsvRow的get方法越界问题(issue#IK9CX@Gitee)
-* 【core】 修复UnicodeUtil丢失末尾字符串的问题(issue#IKI6T@Gitee)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.0.13
-
-### 新特性
-* 【json】 JSONArray添加jsonIter方法可以实现foreach语法遍历JSONObject(issue#IJPIJ@Gitee)
-* 【core】 强化FileTypeUtil中对PDF文件格式的识别兼容性(issue#IJO1K@Gitee)
-* 【core】 修改BetweenFormater枚举规则,修复不足1天显示空问题
-* 【http】 由于JDK9移除了javax.activation导致的问题,修复移除相关包依赖(issue#109@Github)
-* 【core】 改进Resource,增加getName方法,增加构造支持name
-* 【core】 RandomUtil增加randomStringUpper方法(issue#IJVLS@Gitee)
-
-### Bug修复
-* 【core】 修复XmlUtil.toStr方法注释丢失问题(issue#IJPUA@Gitee)
-* 【core】 修复ImageUtil.scale和createFont方法的bug(issue#IJOKE@Gitee)
-* 【core】 修复StrUtil.format方法Map参数中值为null导致的空指针问题(issue#IJO31@Gitee)
-* 【core】 修复ReUtil.getAllGroups丢失最后一个分组问题(issue#IJRJM@Gitee)
-* 【json】 修复Bean中为Map导致的泛型类型不匹配问题(issue#IJRJM@Gitee)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.0.12
-
-### 新特性
-* 【core】 ClassScaner支持jar的嵌套
-
-### Bug修复
-* 【setting】 修复Setting中size的bug
-* 【cron】 修复Setting修改导致的定时任务读取错误问题(issue#IJMVN@Gitee)
-* 【setting】 修复Props中autoLoad无效问题(issue#IJMOE@Gitee)
-* 【cron】 修复表达式中年匹配位置的问题(issue#106@Gtihub)
-* 【log】 修复log.info(null)空指针问题(issue#IJNRW@Gitee)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.0.11
-
-### 新特性
-* 【core】 Week.toChinese()添加可选参数,选择星期的前缀(比如是“星期”还是“周”)
-* 【core】 PinyinUtil增加方法,汉字转拼音(pr#11@Gitee)
-* 【core】 Convert增加toList方法
-* 【core】 CollUtil增加toList方法(感谢@【帝都】宁静)
-* 【poi】 新增FormulaCellValue对象用于写出公式支持(感谢@【宁波】mojie126)
-
-### Bug修复
-* 【core】 修复NumberChineseFormater.format()方法无“元”字的问题(issue#IJ6MR@Gitee)
-* 【core】 修复FileUtil.loopFile遍历根目录时空指针错误问题
-* 【poi】 修复ExcelReader遇到ERROR单元格时报错问题(感谢@夏夜神话)
-* 【http】 修复HttpUtil.post传入json字符串导致的问题(issue#99@Github)
-* 【json】 修复Unicode不可见字符转义导致的中文双引号等符号显示问题(issue#IJFBD@Gitee)
-* 【core】 修复ReferenceUtil中SoftReference错误问题(pr#105@Github)
-* 【db】 删除ActiveRsHandler(歧义),修复showSql属性报错问题(issue#IJII8@Gitee)
-* 【setting】 大改Setting逻辑,使用GroupedMap代替分组拼接方式,解决了无分组情况下会包含分组的问题
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.0.10
-
-### 新特性
-* 【poi】 ExcelWriter.merge方法加入重载,可选是否加入默认标题样式
-* 【poi】 ExcelSaxReader改进按照流读取工作簿的构造,使之对于mark不支持的流也可解析
-* 【cron】 添加updatePattern方法,可更新Task执行时间规则(感谢@【上海】嘿)
-* 【cache】 添加get方法支持可选的是否更新lastAccess时间(issue#IISC4@Gitee)
-* 【core】 StrUtil增加isNullOrUndefined、isEmptyOrUndefined、isBlankOrUndefined方法(issue#IIR44@Gitee)
-* 【core】 isBlankChar方法迁移到CharUtil中
-* 【db】 增加NamedSql
-* 【poi】 对于POI未引入或版本错误提供更加明确的提示
-* 【core】 增加UUIDConverter,支持UUID对象的自动转换
-* 【core】 IterUtil增加fieldValueList、fieldValueAsMap、join重载方法(issue#IIU4F@Gitee)
-* 【core】 IoUtil增加checksum、toBuffered方法,StrUtil增加maxLength方法(参考osgl-tool)
-* 【poi】 ExcelReader支持自定义sheet
-
-### Bug修复
-* 【poi】 修复ExcelWriter合并单元格后样式失效问题
-* 【http】 修复HttpUtil.download方法遇到特殊Disposition时处理异常问题(感谢@【深圳】Bomb)
-* 【core】 修复StrUtil.toUnderlineCase方法中下划线转下划线导致的问题
-* 【core】 修复RandomUtil.randomEles方法计数错误问题(issue#98@Github)
-* 【core】 修复NumberChineseFormater负数小数结果错误问题(pr#10@Gitee)
-* 【captcha】修复验证码无法序列化的问题(issue#IJ2MI@Gitee)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.0.9
-
-### 新特性
-* 【core】 SecureUtil增加signParamsSha1方法(感谢@【帝都】宁静)
-* 【core】 XmlUtil增加mapToXml和xmlToMap(感谢@【杭州】小宙子)
-* 【captcha】修改逻辑:在创建验证码对象时生成一个验证码(感谢@【重庆】liuuuu)
-* 【core】 CopiedIterator使用LinkedList替代ArrayList(issue#III8K@Gitee)
-* 【poi】 ExcelWriter增加getOrCreateCell、createStyleForCell方法,便于自定义特殊单元格
-* 【core】 增加AnnotationUtil类
-* 【core】 IoUtil增加toMarkSupportStream方法
-* 【poi】 ExcelReader改进按照流读取工作簿的构造,使之对于mark不支持的流也可解析
-* 【core】 新增BytesResource和InputStreamResource
-* 【core】 RandomUtil新增randomBigDecimal(感谢@【帝都】宁静)
-* 【db】 Column对象添加comment字段
-* 【core】 Base64增加encode方法,参数为Inputstream和File,新增decodeToFile、decodeToStream(issue#IILZS@Gitee)
-* 【core】 扩充XmlUtil部分方法
-
-### Bug修复
-* 【core】修复StrUtil.replace问题(感谢@【上海】piaohao)
-* 【mail】解决在javax.mail大于1.5版本时,附件名过长在国内邮箱导致的显示错误问题(添加splitlongparameters参数)
-* 【core】修复ZipUtil.zip压缩目录时加入盘符问题(感谢@【深圳】Vmo )
-* 【core】修复PropertyComparator失效问题(感谢@【长沙】哼哼 )
-* 【cron】修复20/2此类表达式无效问题(感谢@【广州】杨小过 )
-* 【core】修复XmlUtil.toStr编码设置无效问题
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.0.8
-
-### 新特性
-* 【core】新增PinyinComparator、CollUtil新增sortByPinyin(感谢@【帝都】宁静)
-* 【json】JSONUtil增加xmlToJson方法
-* 【poi】 ExcelWriter增加setColumnWidth和setRowHeight方法
-* 【core】FileUtil.clean增加字符串重载(感谢@【帝都】宁静)
-* 【core】ArrayUtil增加insert方法(感谢@【帝都】宁静)
-* 【core】RandomUtil.randomDouble增加可选保留小数重载(感谢@【帝都】宁静)
-* 【core】增加RandomUtil.randomDay随机天(感谢@【帝都】宁静)
-* 【poi】 ExcelWriter增加setOrCreateSheet方法,从而支持多sheet生成
-
-### Bug修复
-* 【json】修复JSONArray中addAll加入两次的bug(感谢@【天津】〓下页)
-* 【core】修复BeanDesc中对static属性未忽略的问题(感谢@【深圳】枫林晓寒)
-* 【http】解决无法移除默认头信息的问题
-* 【core】修复Base64在decode时针对urlSafe乱码问题(issue#89@Github)
-* 【core】修复ReUtil.extractMulti(感谢@【杭州】徐承恩)
-* 【core】修复DESede类中算法错误问题(issue#93@Github)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.0.7
-
-### 新特性
-* 【core】新加math包,并添加MathUtil工具类(排列组合迁入此)
-* 【core】StrUtil增加move方法,字符串位移(感谢@【帝都】宁静)
-* 【core】ArrayUtil的max和min采用可变参数(T[]除外)(感谢@【帝都】宁静)
-* 【core】NumberUtil增加max和min方法,与ArrayUtil一致(感谢@【帝都】宁静)
-* 【poi】 去除InternalExcelUtil,根据功能新增WorkbookUtil、RowUtil、CellUtil、ExcelPicUtil
-* 【core】新增PinyinUtil(感谢@【帝都】宁静)
-* 【core】StrUtil增加wrapAll、wrapAllIfMissing(感谢@【帝都】宁静)
-* 【core】Singleton增加put方法
-* 【core】Convert增加convertByClassName方法
-* 【json】JSONUtil增加toList快捷方法
-
-### Bug修复
-* 【core】修复排列组合结果错误问题(感谢@【帝都】宁静)
-* 【poi】 修复StrUtil.unWrap传入null导致的越界问题(issue#II1VU@Gitee)
-* 【core】修复ImageUtil.sliceByRowsAndCols方法计算错误(感谢@【唐山】小虫)
-* 【core】修复StrUtil.replace问题(感谢@【霾都】QQ小冰)
-* 【core】修复FileTypeUtil对jpg的识别范围(issue#91@Github)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.0.6
-
-### 新特性
-* 【poi】 ExcelReader增加getWriter、getOrCreateCell方法
-* 【core】NetUtil增加isInRange方法(感谢@【成都】小邓)
-* 【core】新增BeanPath(仅支持部分JSONPath语法)
-* 【core】CollUtil新增reverse、reverseNew方法
-* 【core】集合中新增排列(Arrangement)和组合(Combination)类(感谢@【北京】宁静)
-* 【core】StrUtil新增splitToLong和splitToInt方法
-* 【core】MapUtil增加getXXX方法
-* 【core】扩充Dict构造
-* 【core】CollUtil新增sortByProperty方法
-* 【json】toBean支持下划线转驼峰
-* 【core】FileUtil新增更多方法,包括路径拼接
-* 【core】新增LineIterator、NullOutputStream两个类
-
-### Bug修复
-* 【core】修复IdcardUtil中身份证15转18位年的问题(Issue#IHT1Q@Gitee)
-* 【http】忽略Premature EOF错误(感谢@【南京】peckey)
-* 【core】修复ArrayConvert中集合转原始类型数组导致的异常
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.0.5
-
-### 新特性
-* 【json】 toBean方法支持Map.class参数,消除歧义
-* 【core】FileWriter和FileUtil增加writeMap方法
-* 【core】新增CsvWriter和CsvUtil
-* 【poi】 改进ExcelWriter.flush未指定文件时的报错信息
-* 【db】 在配置文件不存在时优化错误提示
-* 【core】BeanUtil.beanToMap方法支持自定义key
-* 【core】增加ModifierUtil,修饰符工具类
-* 【http】下载文件时文件名首先从头信息中获取
-* 【poi】 ExcelReader增加getCell方法
-* 【db】 Oracle驱动变更
-* 【extra】扩充Sftp方法(感谢@【广西】Succy)
-* 【core】ImageUtil增加binary方法,生成二值化图片(感谢@【天津】〓下页)
-
-### Bug修复
-* 【poi】 修复ExcelReader获取Workbook为空的问题
-* 【core】修复ImageUtil.scale的问题(感谢@【北京】千古不见一人闲)
-* 【json】 修复JSON转字符串时值中双引号转义问题(感谢@【深圳】jae)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.0.4
-
-### 新特性
-* 【http】 HttpUtil.downloadFile增加超时重载(感谢@【深圳】富)
-* 【setting】Setting增加构造重载(pr#8@Gitee)
-* 【core】 IterUtil增加fieldValueMap方法(感谢@【苏州】陈华 万缕数据@【北京】宁静)
-
-### Bug修复
-* 【log】 修复StaticLog.warn打印级别错误问题(issue#IHMF9@Gitee)
-* 【core】修复MapUtil.newHashMap中isOrder(感谢@【珠海】hzhhui)
-* 【core】修复DateTime.season获取的问题(感谢@西湖断桥)
-* 【cron】修复在秒匹配关闭时无法匹配的问题(感谢@【北京】宁静)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.0.3
-
-### 新特性
-* 【core】新增LocalPortGenerater,本地端口生成器
-* 【extra】新增Sftp类,用于SFTP支持
-* 【core】StrUtil增加replace(支持参数从某个位置开始)和replaceIgnoreCase方法(感谢@【贵阳】shadow )
-* 【core】Number.equals方法迁移到CharUtil(NumberUtil中依旧保留)
-* 【extra】mail增加抄送和密送支持(感谢【成都】出错)
-* 【poi】ExcelReader别名在返回List时也被支持(第一行)
-* 【poi】ExcelReader增加getSheets和getSheetNames方法(感谢@【帝都】宁静)
-* 【poi】ExcelReader增加readCellValue和readRow方法(感谢@【苏州】马克)
-* 【db】全局数据源工厂独立,使用懒加载方式,消除歧义
-* 【log】全局日志工厂独立,懒加载方式,消除歧义
-* 【extra】MailUtil增加快捷方法支持抄送和密送参数
-
-### Bug修复
-* 【core】修复获取子路径bug(issue#IHI5K@Gitee)
-* 【poi】修复ExcelReader在读取文件后未关闭导致文件被占用问题(感谢@【昆明】-@_@)
-* 【log】解决Tinylog实现显示类名和行行错误问题
-* 【extra】修复Mail构造在MailAccount传入null时读取错误的问题
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.0.2
-
-### 新特性
-* 【core】优化BeanDesc,适配更多Getter和Setter方法
-* 【extra】增加基于zxing的二维码生成和解码(zxing可选依赖)
-* 【core】增加VersionComparator用于版本比较,同时添加StrUtil.compareVersion
-* 【core】Convert支持Map、Bean之间的转换、enum,新增BeanConverter和CastBeanConverter
-* 【extra】ServletUtil中增加获取body和上传文件支持
-* 【json】在json与bean互相转换时支持enum和字符串转换(感谢@【帝都】宁静)
-* 【core】增加OptArrayTypeGetter接口
-* 【http】HttpUtil增加decodeParamMap方法,返回单值map(感谢@【帝都】宁静)
-* 【poi】ExcelWriter增加writeCellValue方法
-* 【cron】去除CronUtil以及Scheduler中的isMatchYear方法(年的匹配通过表达式自动判断)
-* 【extra】邮件Mail对象增加setUseGlobalSession方法,用于自定义是否使用单例会话
-
-### Bug修复
-* 【setting】修复clear方法未清空group的问题,store方法未换行问题,set方法分组丢失问题(感谢@【广西】Succy)
-* 【json】修复Map嵌套转JSONObject时判断失误导致的值错误(issue#@Gitee)
-* 【core】修复betweenYear注释错误(感谢@【常州】在校学生)
-* 【core】修复Convert.digitToChinese方法中角为0时显示问题(issue#IHHE1@Gitee)
-* 【cron】修复在秒匹配模式下5位表达式执行异常问题,修复cron.setting文件不存在报错问题
-* 【extra】邮件配置中参数值转为String解决可能存在的bug
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.0.1
-
-### 新特性
-* 新增CharUtil
-* 新增ASCIIStrCache,对ASCII字符做String对应表,提升字符转字符串性能
-* 去除JschUtil中的同步修饰,改为锁
-* 新增MapUtil.sort
-* SymmetricCrypto支持加密后转为Base64和从Base64解密
-* AsymmetricCrypto支持Hex和Base64加密解密
-* 新增SecureUtil.signParams方法用于参数签名(感谢@【帝都】宁静)
-* 新增Loader和LazyLoader,抽象懒加载
-* 新增CsvReader,CSV读取
-* HttpRequest支持可选get请求下的url参数编码
-* ExcelReader增加read重载方法,ExcelUtil增加isEmpty(Sheet)方法(pr#5@Gitee)
-* db模块针对IS NULL优化
-
-### Bug修复
-* 修复db模块中数据库为下划线而Bean为驼峰导致的注入失败问题(感谢@【广西】Succy)
-* 修复findLike的bug(感谢@cici)
-* 修复ArrayUtil.join循环引用bug
-* FileTypeUtil针对pdf格式做修改(issue#IHDNH@Gitee)
-* 修复Http模块中get方法拼接参数问题
-* 修复db模块in方式查询错误问题
-* 修复CollUtil.disjunction计算差集修复一个集合为空的情况(感谢@【天津】〓下页)
-* 修复Db模块中Number参数丢失问题(感谢@【山东】小灰灰)
-
--------------------------------------------------------------------------------------------------------------
-
-## 4.0.0
-
-### 新特性
-* 变更包名为cn.hutool.xxx
-* 新增ObjecIdt类,用于实现MongoDB的ID生成策略
-* 验证码单独成为一个模块hutool-captcha
-* 新增NamedThreadFactory
-* 新增BufferUtil
-* POI新增StyleUtil,StyleSet新增方法可设置背景、边框等样式
-* JDBC参数针对BigInteger处理
-* db模块支持显示和格式化显示SQL
-* 调整日志优先级:ConsoleLog优先于JDKLog,Log4j2优先于Log4j
-* db模块的SqlRunner中可自定义Wrapper
-* ExcelReader增加read重载方法(pr#4@Gitee)
-* Convert.convert增加Class的重载,解决返回值歧义(感谢@t-io)
-* Http中使用byte[]存储body,减少转换
-* ExcelReader增加getWorkbook、getSheet方法
-* 新增StrBuilder
-* 新增JschUtil
-* 新增UnicodeUtil
-* db模块的BeanListHandler和BeanHandler支持Map、Collection、Array等类型
-* NumberUtil加减乘支持多个值,解决float和double混合运算导致的坑
-
-### Bug修复
-* 修复ExcelReader空行导致空指针问题(pr#4@Gitee)
-* 修复BeanUtil.getProperty不能获取父类属性的问题
-* 修复BeanDesc类中boolean类型字段名为isXXX的情况无法注入问题
-* 解决类扫描后加载类中引用依赖导致的报错(感谢@【帝都】宁静)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5256e7d5b..3c2aa0da2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,8 @@
## 5.2.6 (2020-03-26)
### 新特性
+* 【extra 】 JschUtil增加execByShell方法(issue#I1CYES@Gitee)
+
### Bug修复
* 【extra 】 修复SpringUtil使用devtools重启报错问题
diff --git a/hutool-extra/src/main/java/cn/hutool/extra/ssh/JschUtil.java b/hutool-extra/src/main/java/cn/hutool/extra/ssh/JschUtil.java
index 55608f890..2a9baaba2 100644
--- a/hutool-extra/src/main/java/cn/hutool/extra/ssh/JschUtil.java
+++ b/hutool-extra/src/main/java/cn/hutool/extra/ssh/JschUtil.java
@@ -6,7 +6,13 @@ import cn.hutool.core.lang.Assert;
import cn.hutool.core.net.LocalPortGenerater;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
-import com.jcraft.jsch.*;
+import com.jcraft.jsch.Channel;
+import com.jcraft.jsch.ChannelExec;
+import com.jcraft.jsch.ChannelSftp;
+import com.jcraft.jsch.ChannelShell;
+import com.jcraft.jsch.JSch;
+import com.jcraft.jsch.JSchException;
+import com.jcraft.jsch.Session;
import java.io.IOException;
import java.io.InputStream;
@@ -172,7 +178,7 @@ public class JschUtil {
sshUser = "root";
}
- if(null == jsch){
+ if (null == jsch) {
jsch = new JSch();
}
@@ -343,7 +349,10 @@ public class JschUtil {
}
/**
- * 执行Shell命令
+ * 执行Shell命令(使用EXEC方式)
+ *
+ * 此方法单次发送一个命令到服务端,不读取环境变量,执行结束后自动关闭channel,不会产生阻塞。
+ *
*
* @param session Session会话
* @param cmd 命令
@@ -375,6 +384,46 @@ public class JschUtil {
}
}
+ /**
+ * 执行Shell命令
+ *
+ * 此方法单次发送一个命令到服务端,自动读取环境变量,执行结束后自动关闭channel,不会产生阻塞。
+ * 此方法返回数据中可能
+ *
+ *
+ * @param session Session会话
+ * @param cmd 命令
+ * @param charset 发送和读取内容的编码
+ * @return {@link ChannelExec}
+ * @since 5.2.5
+ */
+ public static String execByShell(Session session, String cmd, Charset charset) {
+ final ChannelShell shell = openShell(session);
+ // 开始连接
+ shell.setPty(true);
+ OutputStream out = null;
+ InputStream in = null;
+ final StringBuilder result = StrUtil.builder();
+ try {
+ out = shell.getOutputStream();
+ in = shell.getInputStream();
+
+ out.write(StrUtil.bytes(cmd, charset));
+ out.flush();
+
+ while (in.available() > 0) {
+ result.append(IoUtil.read(in, charset));
+ }
+ } catch (IOException e) {
+ throw new IORuntimeException(e);
+ } finally {
+ IoUtil.close(out);
+ IoUtil.close(in);
+ close(shell);
+ }
+ return result.toString();
+ }
+
/**
* 关闭SSH连接会话
*
From bcd773b85a5962ab1e5e05e6f469daac64164e65 Mon Sep 17 00:00:00 2001
From: Looly
Date: Sun, 29 Mar 2020 10:07:59 +0800
Subject: [PATCH 006/157] add method
---
.../java/cn/hutool/core/lang/Console.java | 9 +-
.../java/cn/hutool/core/util/StrUtil.java | 1025 ++++++++---------
.../java/cn/hutool/core/util/StrUtilTest.java | 4 +-
3 files changed, 514 insertions(+), 524 deletions(-)
diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/Console.java b/hutool-core/src/main/java/cn/hutool/core/lang/Console.java
index 0f1dfd8b5..a50f4edb2 100644
--- a/hutool-core/src/main/java/cn/hutool/core/lang/Console.java
+++ b/hutool-core/src/main/java/cn/hutool/core/lang/Console.java
@@ -1,13 +1,12 @@
package cn.hutool.core.lang;
-import static java.lang.System.out;
-
-import java.util.Scanner;
-
import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.StrUtil;
+import java.util.Scanner;
+
import static java.lang.System.err;
+import static java.lang.System.out;
/**
* 命令行(控制台)工具方法类
@@ -189,7 +188,7 @@ public class Console {
* @since 5.2.5
*/
public static String where() {
- StackTraceElement stackTraceElement = new Throwable().getStackTrace()[1];
+ final StackTraceElement stackTraceElement = new Throwable().getStackTrace()[1];
final String className = stackTraceElement.getClassName();
final String methodName = stackTraceElement.getMethodName();
final String fileName = stackTraceElement.getFileName();
diff --git a/hutool-core/src/main/java/cn/hutool/core/util/StrUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/StrUtil.java
index dff3124b4..afe1ca6cf 100644
--- a/hutool-core/src/main/java/cn/hutool/core/util/StrUtil.java
+++ b/hutool-core/src/main/java/cn/hutool/core/util/StrUtil.java
@@ -1,14 +1,5 @@
package cn.hutool.core.util;
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
-import java.text.MessageFormat;
-import java.util.*;
-import java.util.Map.Entry;
-import java.util.regex.Pattern;
-
import cn.hutool.core.comparator.VersionComparator;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Assert;
@@ -19,11 +10,24 @@ import cn.hutool.core.text.StrFormatter;
import cn.hutool.core.text.StrSpliter;
import cn.hutool.core.text.TextSimilarity;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.regex.Pattern;
+
/**
* 字符串工具类
- *
- * @author xiaoleilu
*
+ * @author xiaoleilu
*/
public class StrUtil {
@@ -74,12 +78,13 @@ public class StrUtil {
public static final String EMPTY_JSON = "{}";
// ------------------------------------------------------------------------ Blank
+
/**
* 字符串是否为空白 空白的定义如下:
* 1、为null
* 2、为不可见字符(如空格)
* 3、""
- *
+ *
* @param str 被检测的字符串
* @return 是否为空
*/
@@ -105,7 +110,7 @@ public class StrUtil {
* 1、为null
* 2、为不可见字符(如空格)
* 3、""
- *
+ *
* @param obj 对象
* @return 如果为字符串是否为空串
* @since 3.3.0
@@ -124,7 +129,7 @@ public class StrUtil {
* 1、不为null
* 2、不为不可见字符(如空格)
* 3、不为""
- *
+ *
* @param str 被检测的字符串
* @return 是否为非空
*/
@@ -134,7 +139,7 @@ public class StrUtil {
/**
* 是否包含空字符串
- *
+ *
* @param strs 字符串列表
* @return 是否包含空字符串
*/
@@ -153,7 +158,7 @@ public class StrUtil {
/**
* 给定所有字符串是否为空白
- *
+ *
* @param strs 字符串
* @return 所有字符串是否为空白
*/
@@ -171,11 +176,12 @@ public class StrUtil {
}
// ------------------------------------------------------------------------ Empty
+
/**
* 字符串是否为空,空的定义如下:
* 1、为null
* 2、为""
- *
+ *
* @param str 被检测的字符串
* @return 是否为空
*/
@@ -187,7 +193,7 @@ public class StrUtil {
* 如果对象是字符串是否为空串空的定义如下:
* 1、为null
* 2、为""
- *
+ *
* @param obj 对象
* @return 如果为字符串是否为空串
* @since 3.3.0
@@ -205,21 +211,21 @@ public class StrUtil {
* 字符串是否为非空白 空白的定义如下:
* 1、不为null
* 2、不为""
- *
+ *
* @param str 被检测的字符串
* @return 是否为非空
*/
public static boolean isNotEmpty(CharSequence str) {
return false == isEmpty(str);
}
-
+
/**
* 当给定字符串为null时,转换为Empty
- *
+ *
* @param str 被检查的字符串
* @return 原字符串或者空串
- * @since 4.6.3
* @see #nullToEmpty(CharSequence)
+ * @since 4.6.3
*/
public static String emptyIfNull(CharSequence str) {
return nullToEmpty(str);
@@ -227,7 +233,7 @@ public class StrUtil {
/**
* 当给定字符串为null时,转换为Empty
- *
+ *
* @param str 被转换的字符串
* @return 转换后的字符串
*/
@@ -237,17 +243,16 @@ public class StrUtil {
/**
* 如果字符串是null,则返回指定默认字符串,否则返回字符串本身。
- *
+ *
*
* nullToDefault(null, "default") = "default"
* nullToDefault("", "default") = ""
* nullToDefault(" ", "default") = " "
* nullToDefault("bat", "default") = "bat"
*
- *
- * @param str 要转换的字符串
+ *
+ * @param str 要转换的字符串
* @param defaultStr 默认字符串
- *
* @return 字符串本身或指定的默认字符串
*/
public static String nullToDefault(CharSequence str, String defaultStr) {
@@ -256,17 +261,16 @@ public class StrUtil {
/**
* 如果字符串是null或者"",则返回指定默认字符串,否则返回字符串本身。
- *
+ *
*
* emptyToDefault(null, "default") = "default"
* emptyToDefault("", "default") = "default"
* emptyToDefault(" ", "default") = " "
* emptyToDefault("bat", "default") = "bat"
*
- *
- * @param str 要转换的字符串
+ *
+ * @param str 要转换的字符串
* @param defaultStr 默认字符串
- *
* @return 字符串本身或指定的默认字符串
* @since 4.1.0
*/
@@ -276,17 +280,16 @@ public class StrUtil {
/**
* 如果字符串是null或者""或者空白,则返回指定默认字符串,否则返回字符串本身。
- *
+ *
*
* emptyToDefault(null, "default") = "default"
* emptyToDefault("", "default") = "default"
* emptyToDefault(" ", "default") = "default"
* emptyToDefault("bat", "default") = "bat"
*
- *
- * @param str 要转换的字符串
+ *
+ * @param str 要转换的字符串
* @param defaultStr 默认字符串
- *
* @return 字符串本身或指定的默认字符串
* @since 4.1.0
*/
@@ -296,7 +299,7 @@ public class StrUtil {
/**
* 当给定字符串为空字符串时,转换为null
- *
+ *
* @param str 被转换的字符串
* @return 转换后的字符串
*/
@@ -306,7 +309,7 @@ public class StrUtil {
/**
* 是否包含空字符串
- *
+ *
* @param strs 字符串列表
* @return 是否包含空字符串
*/
@@ -325,7 +328,7 @@ public class StrUtil {
/**
* 是否全部为空字符串
- *
+ *
* @param strs 字符串列表
* @return 是否全部为空字符串
*/
@@ -344,7 +347,7 @@ public class StrUtil {
/**
* 检查字符串是否为null、“null”、“undefined”
- *
+ *
* @param str 被检查的字符串
* @return 是否为null、“null”、“undefined”
* @since 4.0.10
@@ -358,7 +361,7 @@ public class StrUtil {
/**
* 检查字符串是否为null、“”、“null”、“undefined”
- *
+ *
* @param str 被检查的字符串
* @return 是否为null、“”、“null”、“undefined”
* @since 4.0.10
@@ -372,7 +375,7 @@ public class StrUtil {
/**
* 检查字符串是否为null、空白串、“null”、“undefined”
- *
+ *
* @param str 被检查的字符串
* @return 是否为null、空白串、“null”、“undefined”
* @since 4.0.10
@@ -386,7 +389,7 @@ public class StrUtil {
/**
* 是否为“null”、“undefined”,不做空指针检查
- *
+ *
* @param str 字符串
* @return 是否为“null”、“undefined”
*/
@@ -396,12 +399,13 @@ public class StrUtil {
}
// ------------------------------------------------------------------------ Trim
+
/**
* 除去字符串头尾部的空白,如果字符串是null,依然返回null。
- *
+ *
*
* 注意,和String.trim不同,此方法使用NumberUtil.isBlankChar 来判定空白, 因而可以除去英文字符集之外的其它空白,如中文空格。
- *
+ *
*
* trim(null) = null
* trim("") = ""
@@ -409,9 +413,8 @@ public class StrUtil {
* trim("abc") = "abc"
* trim(" abc ") = "abc"
*
- *
+ *
* @param str 要处理的字符串
- *
* @return 除去头尾空白的字符串,如果原字串为null,则返回null
*/
public static String trim(CharSequence str) {
@@ -420,7 +423,7 @@ public class StrUtil {
/**
* 给定字符串数组全部做去首尾空格
- *
+ *
* @param strs 字符串数组
*/
public static void trim(String[] strs) {
@@ -477,10 +480,10 @@ public class StrUtil {
/**
* 除去字符串头部的空白,如果字符串是null,则返回null。
- *
+ *
*
* 注意,和String.trim不同,此方法使用CharUtil.isBlankChar 来判定空白, 因而可以除去英文字符集之外的其它空白,如中文空格。
- *
+ *
*
* trimStart(null) = null
* trimStart("") = ""
@@ -489,9 +492,8 @@ public class StrUtil {
* trimStart("abc ") = "abc "
* trimStart(" abc ") = "abc "
*
- *
+ *
* @param str 要处理的字符串
- *
* @return 除去空白的字符串,如果原字串为null或结果字符串为"",则返回 null
*/
public static String trimStart(CharSequence str) {
@@ -500,10 +502,10 @@ public class StrUtil {
/**
* 除去字符串尾部的空白,如果字符串是null,则返回null。
- *
+ *
*
* 注意,和String.trim不同,此方法使用CharUtil.isBlankChar 来判定空白, 因而可以除去英文字符集之外的其它空白,如中文空格。
- *
+ *
*
* trimEnd(null) = null
* trimEnd("") = ""
@@ -512,9 +514,8 @@ public class StrUtil {
* trimEnd("abc ") = "abc"
* trimEnd(" abc ") = " abc"
*
- *
+ *
* @param str 要处理的字符串
- *
* @return 除去空白的字符串,如果原字串为null或结果字符串为"",则返回 null
*/
public static String trimEnd(CharSequence str) {
@@ -523,10 +524,9 @@ public class StrUtil {
/**
* 除去字符串头尾部的空白符,如果字符串是null,依然返回null。
- *
- * @param str 要处理的字符串
+ *
+ * @param str 要处理的字符串
* @param mode -1表示trimStart,0表示trim全部, 1表示trimEnd
- *
* @return 除去指定字符后的的字符串,如果原字串为null,则返回null
*/
public static String trim(CharSequence str, int mode) {
@@ -561,9 +561,9 @@ public class StrUtil {
/**
* 字符串是否以给定字符开始
- *
+ *
* @param str 字符串
- * @param c 字符
+ * @param c 字符
* @return 是否开始
*/
public static boolean startWith(CharSequence str, char c) {
@@ -573,9 +573,9 @@ public class StrUtil {
/**
* 是否以指定字符串开头
* 如果给定的字符串和开头字符串都为null则返回true,否则任意一个值为null返回false
- *
- * @param str 被监测字符串
- * @param prefix 开头字符串
+ *
+ * @param str 被监测字符串
+ * @param prefix 开头字符串
* @param isIgnoreCase 是否忽略大小写
* @return 是否以指定字符串开头
*/
@@ -593,8 +593,8 @@ public class StrUtil {
/**
* 是否以指定字符串开头
- *
- * @param str 被监测字符串
+ *
+ * @param str 被监测字符串
* @param prefix 开头字符串
* @return 是否以指定字符串开头
*/
@@ -604,8 +604,8 @@ public class StrUtil {
/**
* 是否以指定字符串开头,忽略大小写
- *
- * @param str 被监测字符串
+ *
+ * @param str 被监测字符串
* @param prefix 开头字符串
* @return 是否以指定字符串开头
*/
@@ -616,8 +616,8 @@ public class StrUtil {
/**
* 给定字符串是否以任何一个字符串开始
* 给定字符串和数组为空都返回false
- *
- * @param str 给定字符串
+ *
+ * @param str 给定字符串
* @param prefixes 需要检测的开始字符串
* @return 给定字符串是否以任何一个字符串开始
* @since 3.0.6
@@ -637,9 +637,9 @@ public class StrUtil {
/**
* 字符串是否以给定字符结尾
- *
+ *
* @param str 字符串
- * @param c 字符
+ * @param c 字符
* @return 是否结尾
*/
public static boolean endWith(CharSequence str, char c) {
@@ -649,9 +649,9 @@ public class StrUtil {
/**
* 是否以指定字符串结尾
* 如果给定的字符串和开头字符串都为null则返回true,否则任意一个值为null返回false
- *
- * @param str 被监测字符串
- * @param suffix 结尾字符串
+ *
+ * @param str 被监测字符串
+ * @param suffix 结尾字符串
* @param isIgnoreCase 是否忽略大小写
* @return 是否以指定字符串结尾
*/
@@ -669,8 +669,8 @@ public class StrUtil {
/**
* 是否以指定字符串结尾
- *
- * @param str 被监测字符串
+ *
+ * @param str 被监测字符串
* @param suffix 结尾字符串
* @return 是否以指定字符串结尾
*/
@@ -680,8 +680,8 @@ public class StrUtil {
/**
* 是否以指定字符串结尾,忽略大小写
- *
- * @param str 被监测字符串
+ *
+ * @param str 被监测字符串
* @param suffix 结尾字符串
* @return 是否以指定字符串结尾
*/
@@ -692,8 +692,8 @@ public class StrUtil {
/**
* 给定字符串是否以任何一个字符串结尾
* 给定字符串和数组为空都返回false
- *
- * @param str 给定字符串
+ *
+ * @param str 给定字符串
* @param suffixes 需要检测的结尾字符串
* @return 给定字符串是否以任何一个字符串结尾
* @since 3.0.6
@@ -713,8 +713,8 @@ public class StrUtil {
/**
* 指定字符是否在字符串中出现过
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param searchChar 被查找的字符
* @return 是否包含
* @since 3.1.2
@@ -726,13 +726,13 @@ public class StrUtil {
/**
* 指定字符串是否在字符串中出现过
*
- * @param str 字符串
+ * @param str 字符串
* @param searchStr 被查找的字符串
* @return 是否包含
* @since 5.1.1
*/
public static boolean contains(CharSequence str, CharSequence searchStr) {
- if(null == str || null == searchStr){
+ if (null == str || null == searchStr) {
return false;
}
return str.toString().contains(searchStr);
@@ -740,8 +740,8 @@ public class StrUtil {
/**
* 查找指定字符串是否包含指定字符串列表中的任意一个字符串
- *
- * @param str 指定字符串
+ *
+ * @param str 指定字符串
* @param testStrs 需要检查的字符串数组
* @return 是否包含任意一个字符串
* @since 3.2.0
@@ -752,8 +752,8 @@ public class StrUtil {
/**
* 查找指定字符串是否包含指定字符列表中的任意一个字符
- *
- * @param str 指定字符串
+ *
+ * @param str 指定字符串
* @param testChars 需要检查的字符数组
* @return 是否包含任意一个字符
* @since 4.1.11
@@ -772,8 +772,8 @@ public class StrUtil {
/**
* 检查指定字符串中是否只包含给定的字符
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param testChars 检查的字符
* @return 字符串含有非检查的字符,返回false
* @since 4.4.1
@@ -793,7 +793,7 @@ public class StrUtil {
/**
* 给定字符串是否包含空白符(空白符包括空格、制表符、全角空格和不间断空格)
* 如果给定字符串为null或者"",则返回false
- *
+ *
* @param str 字符串
* @return 是否包含空白符
* @since 4.0.8
@@ -817,8 +817,8 @@ public class StrUtil {
/**
* 查找指定字符串是否包含指定字符串列表中的任意一个字符串,如果包含返回找到的第一个字符串
- *
- * @param str 指定字符串
+ *
+ * @param str 指定字符串
* @param testStrs 需要检查的字符串数组
* @return 被包含的第一个字符串
* @since 3.2.0
@@ -837,8 +837,8 @@ public class StrUtil {
/**
* 是否包含特定字符,忽略大小写,如果给定两个参数都为null,返回true
- *
- * @param str 被检测字符串
+ *
+ * @param str 被检测字符串
* @param testStr 被测试是否包含的字符串
* @return 是否包含
*/
@@ -853,8 +853,8 @@ public class StrUtil {
/**
* 查找指定字符串是否包含指定字符串列表中的任意一个字符串
* 忽略大小写
- *
- * @param str 指定字符串
+ *
+ * @param str 指定字符串
* @param testStrs 需要检查的字符串数组
* @return 是否包含任意一个字符串
* @since 3.2.0
@@ -866,8 +866,8 @@ public class StrUtil {
/**
* 查找指定字符串是否包含指定字符串列表中的任意一个字符串,如果包含返回找到的第一个字符串
* 忽略大小写
- *
- * @param str 指定字符串
+ *
+ * @param str 指定字符串
* @param testStrs 需要检查的字符串数组
* @return 被包含的第一个字符串
* @since 3.2.0
@@ -887,13 +887,13 @@ public class StrUtil {
/**
* 获得set或get或is方法对应的标准属性名
* 例如:setName 返回 name
- *
+ *
*
* getName =》name
* setName =》name
* isName =》name
*
- *
+ *
* @param getOrSetMethodName Get或Set方法名
* @return 如果是set或get方法名,返回field, 否则null
*/
@@ -901,7 +901,7 @@ public class StrUtil {
final String getOrSetMethodNameStr = getOrSetMethodName.toString();
if (getOrSetMethodNameStr.startsWith("get") || getOrSetMethodNameStr.startsWith("set")) {
return removePreAndLowerFirst(getOrSetMethodName, 3);
- } else if(getOrSetMethodNameStr.startsWith("is")) {
+ } else if (getOrSetMethodNameStr.startsWith("is")) {
return removePreAndLowerFirst(getOrSetMethodName, 2);
}
return null;
@@ -910,7 +910,7 @@ public class StrUtil {
/**
* 生成set方法名
* 例如:name 返回 setName
- *
+ *
* @param fieldName 属性名
* @return setXxx
*/
@@ -920,7 +920,7 @@ public class StrUtil {
/**
* 生成get方法名
- *
+ *
* @param fieldName 属性名
* @return getXxx
*/
@@ -931,8 +931,8 @@ public class StrUtil {
/**
* 移除字符串中所有给定字符串
* 例:removeAll("aa-bb-cc-dd", "-") =》 aabbccdd
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param strToRemove 被移除的字符串
* @return 移除后的字符串
*/
@@ -945,8 +945,8 @@ public class StrUtil {
/**
* 去除字符串中指定的多个字符,如有多个则全部去除
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param chars 字符列表
* @return 去除后的字符
* @since 4.2.2
@@ -972,12 +972,12 @@ public class StrUtil {
/**
* 去除所有换行符,包括:
- *
+ *
*
* 1. \r
* 1. \n
*
- *
+ *
* @param str 字符串
* @return 处理后的字符串
* @since 4.2.2
@@ -989,8 +989,8 @@ public class StrUtil {
/**
* 去掉首部指定长度的字符串并将剩余字符串首字母小写
* 例如:str=setName, preLength=3 =》 return name
- *
- * @param str 被处理的字符串
+ *
+ * @param str 被处理的字符串
* @param preLength 去掉的长度
* @return 处理后的字符串,不符合规范返回null
*/
@@ -1012,8 +1012,8 @@ public class StrUtil {
/**
* 去掉首部指定长度的字符串并将剩余字符串首字母小写
* 例如:str=setName, prefix=set =》 return name
- *
- * @param str 被处理的字符串
+ *
+ * @param str 被处理的字符串
* @param prefix 前缀
* @return 处理后的字符串,不符合规范返回null
*/
@@ -1023,8 +1023,8 @@ public class StrUtil {
/**
* 原字符串首字母大写并在其首部添加指定字符串 例如:str=name, preString=get =》 return getName
- *
- * @param str 被处理的字符串
+ *
+ * @param str 被处理的字符串
* @param preString 添加的首部
* @return 处理后的字符串
*/
@@ -1038,7 +1038,7 @@ public class StrUtil {
/**
* 大写首字母
* 例如:str = name, return Name
- *
+ *
* @param str 字符串
* @return 字符串
*/
@@ -1058,7 +1058,7 @@ public class StrUtil {
/**
* 小写首字母
* 例如:str = Name, return name
- *
+ *
* @param str 字符串
* @return 字符串
*/
@@ -1077,8 +1077,8 @@ public class StrUtil {
/**
* 去掉指定前缀
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param prefix 前缀
* @return 切掉后的字符串,若前缀不是 preffix, 返回原字符串
*/
@@ -1096,8 +1096,8 @@ public class StrUtil {
/**
* 忽略大小写去掉指定前缀
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param prefix 前缀
* @return 切掉后的字符串,若前缀不是 prefix, 返回原字符串
*/
@@ -1115,8 +1115,8 @@ public class StrUtil {
/**
* 去掉指定后缀
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param suffix 后缀
* @return 切掉后的字符串,若后缀不是 suffix, 返回原字符串
*/
@@ -1134,8 +1134,8 @@ public class StrUtil {
/**
* 去掉指定后缀,并小写首字母
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param suffix 后缀
* @return 切掉后的字符串,若后缀不是 suffix, 返回原字符串
*/
@@ -1145,8 +1145,8 @@ public class StrUtil {
/**
* 忽略大小写去掉指定后缀
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param suffix 后缀
* @return 切掉后的字符串,若后缀不是 suffix, 返回原字符串
*/
@@ -1164,8 +1164,8 @@ public class StrUtil {
/**
* 去除两边的指定字符串
- *
- * @param str 被处理的字符串
+ *
+ * @param str 被处理的字符串
* @param prefixOrSuffix 前缀或后缀
* @return 处理后的字符串
* @since 3.1.2
@@ -1180,8 +1180,8 @@ public class StrUtil {
/**
* 去除两边的指定字符串
- *
- * @param str 被处理的字符串
+ *
+ * @param str 被处理的字符串
* @param prefix 前缀
* @param suffix 后缀
* @return 处理后的字符串
@@ -1208,8 +1208,8 @@ public class StrUtil {
/**
* 去除两边的指定字符串,忽略大小写
- *
- * @param str 被处理的字符串
+ *
+ * @param str 被处理的字符串
* @param prefixOrSuffix 前缀或后缀
* @return 处理后的字符串
* @since 3.1.2
@@ -1220,8 +1220,8 @@ public class StrUtil {
/**
* 去除两边的指定字符串,忽略大小写
- *
- * @param str 被处理的字符串
+ *
+ * @param str 被处理的字符串
* @param prefix 前缀
* @param suffix 后缀
* @return 处理后的字符串
@@ -1246,8 +1246,8 @@ public class StrUtil {
/**
* 如果给定字符串不是以prefix开头的,在开头补充 prefix
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param prefix 前缀
* @return 补充后的字符串
*/
@@ -1266,8 +1266,8 @@ public class StrUtil {
/**
* 如果给定字符串不是以suffix结尾的,在尾部补充 suffix
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param suffix 后缀
* @return 补充后的字符串
*/
@@ -1286,7 +1286,7 @@ public class StrUtil {
/**
* 清理空白字符
- *
+ *
* @param str 被清理的字符串
* @return 清理后的字符串
*/
@@ -1308,10 +1308,11 @@ public class StrUtil {
}
// ------------------------------------------------------------------------------ Split
+
/**
* 切分字符串
- *
- * @param str 被切分的字符串
+ *
+ * @param str 被切分的字符串
* @param separator 分隔符字符
* @return 切分后的数组
*/
@@ -1321,8 +1322,8 @@ public class StrUtil {
/**
* 切分字符串为long数组
- *
- * @param str 被切分的字符串
+ *
+ * @param str 被切分的字符串
* @param separator 分隔符
* @return 切分后long数组
* @since 4.0.6
@@ -1333,8 +1334,8 @@ public class StrUtil {
/**
* 切分字符串为long数组
- *
- * @param str 被切分的字符串
+ *
+ * @param str 被切分的字符串
* @param separator 分隔符字符串
* @return 切分后long数组
* @since 4.0.6
@@ -1345,8 +1346,8 @@ public class StrUtil {
/**
* 切分字符串为int数组
- *
- * @param str 被切分的字符串
+ *
+ * @param str 被切分的字符串
* @param separator 分隔符
* @return 切分后long数组
* @since 4.0.6
@@ -1357,8 +1358,8 @@ public class StrUtil {
/**
* 切分字符串为int数组
- *
- * @param str 被切分的字符串
+ *
+ * @param str 被切分的字符串
* @param separator 分隔符字符串
* @return 切分后long数组
* @since 4.0.6
@@ -1371,8 +1372,8 @@ public class StrUtil {
* 切分字符串
* a#b#c =》 [a,b,c]
* a##b#c =》 [a,"",b,c]
- *
- * @param str 被切分的字符串
+ *
+ * @param str 被切分的字符串
* @param separator 分隔符字符
* @return 切分后的集合
*/
@@ -1382,25 +1383,25 @@ public class StrUtil {
/**
* 切分字符串
- *
- * @param str 被切分的字符串
+ *
+ * @param str 被切分的字符串
* @param separator 分隔符字符
- * @param limit 限制分片数
+ * @param limit 限制分片数
* @return 切分后的数组
*/
public static String[] splitToArray(CharSequence str, char separator, int limit) {
if (null == str) {
- return new String[] {};
+ return new String[]{};
}
return StrSpliter.splitToArray(str.toString(), separator, limit, false, false);
}
/**
* 切分字符串,不去除切分后每个元素两边的空白符,不去除空白项
- *
- * @param str 被切分的字符串
+ *
+ * @param str 被切分的字符串
* @param separator 分隔符字符
- * @param limit 限制分片数,-1不限制
+ * @param limit 限制分片数,-1不限制
* @return 切分后的集合
*/
public static List split(CharSequence str, char separator, int limit) {
@@ -1409,8 +1410,8 @@ public class StrUtil {
/**
* 切分字符串,去除切分后每个元素两边的空白符,去除空白项
- *
- * @param str 被切分的字符串
+ *
+ * @param str 被切分的字符串
* @param separator 分隔符字符
* @return 切分后的集合
* @since 3.1.2
@@ -1421,8 +1422,8 @@ public class StrUtil {
/**
* 切分字符串,去除切分后每个元素两边的空白符,去除空白项
- *
- * @param str 被切分的字符串
+ *
+ * @param str 被切分的字符串
* @param separator 分隔符字符
* @return 切分后的集合
* @since 3.2.0
@@ -1433,10 +1434,10 @@ public class StrUtil {
/**
* 切分字符串,去除切分后每个元素两边的空白符,去除空白项
- *
- * @param str 被切分的字符串
+ *
+ * @param str 被切分的字符串
* @param separator 分隔符字符
- * @param limit 限制分片数,-1不限制
+ * @param limit 限制分片数,-1不限制
* @return 切分后的集合
* @since 3.1.0
*/
@@ -1446,10 +1447,10 @@ public class StrUtil {
/**
* 切分字符串,去除切分后每个元素两边的空白符,去除空白项
- *
- * @param str 被切分的字符串
+ *
+ * @param str 被切分的字符串
* @param separator 分隔符字符
- * @param limit 限制分片数,-1不限制
+ * @param limit 限制分片数,-1不限制
* @return 切分后的集合
* @since 3.2.0
*/
@@ -1459,10 +1460,10 @@ public class StrUtil {
/**
* 切分字符串,不限制分片数量
- *
- * @param str 被切分的字符串
- * @param separator 分隔符字符
- * @param isTrim 是否去除切分字符串后每个元素两边的空格
+ *
+ * @param str 被切分的字符串
+ * @param separator 分隔符字符
+ * @param isTrim 是否去除切分字符串后每个元素两边的空格
* @param ignoreEmpty 是否忽略空串
* @return 切分后的集合
* @since 3.0.8
@@ -1473,11 +1474,11 @@ public class StrUtil {
/**
* 切分字符串
- *
- * @param str 被切分的字符串
- * @param separator 分隔符字符
- * @param limit 限制分片数,-1不限制
- * @param isTrim 是否去除切分字符串后每个元素两边的空格
+ *
+ * @param str 被切分的字符串
+ * @param separator 分隔符字符
+ * @param limit 限制分片数,-1不限制
+ * @param isTrim 是否去除切分字符串后每个元素两边的空格
* @param ignoreEmpty 是否忽略空串
* @return 切分后的集合
* @since 3.0.8
@@ -1491,11 +1492,11 @@ public class StrUtil {
/**
* 切分字符串
- *
- * @param str 被切分的字符串
- * @param separator 分隔符字符
- * @param limit 限制分片数,-1不限制
- * @param isTrim 是否去除切分字符串后每个元素两边的空格
+ *
+ * @param str 被切分的字符串
+ * @param separator 分隔符字符
+ * @param limit 限制分片数,-1不限制
+ * @param isTrim 是否去除切分字符串后每个元素两边的空格
* @param ignoreEmpty 是否忽略空串
* @return 切分后的集合
* @since 3.2.0
@@ -1510,14 +1511,14 @@ public class StrUtil {
/**
* 切分字符串
- *
- * @param str 被切分的字符串
+ *
+ * @param str 被切分的字符串
* @param separator 分隔符
* @return 字符串
*/
public static String[] split(CharSequence str, CharSequence separator) {
if (str == null) {
- return new String[] {};
+ return new String[]{};
}
final String separatorStr = (null == separator) ? null : separator.toString();
@@ -1526,7 +1527,7 @@ public class StrUtil {
/**
* 根据给定长度,将给定字符串截取为多个部分
- *
+ *
* @param str 字符串
* @param len 每一个小节的长度
* @return 截取后的字符串数组
@@ -1534,7 +1535,7 @@ public class StrUtil {
*/
public static String[] split(CharSequence str, int len) {
if (null == str) {
- return new String[] {};
+ return new String[]{};
}
return StrSpliter.splitByLength(str.toString(), len);
}
@@ -1547,10 +1548,10 @@ public class StrUtil {
* 如果经过修正的index中from大于to,则互换from和to example:
* abcdefgh 2 3 =》 c
* abcdefgh 2 -3 =》 cde
- *
- * @param str String
+ *
+ * @param str String
* @param fromIndex 开始的index(包括)
- * @param toIndex 结束的index(不包括)
+ * @param toIndex 结束的index(不包括)
* @return 字串
*/
public static String sub(CharSequence str, int fromIndex, int toIndex) {
@@ -1593,9 +1594,9 @@ public class StrUtil {
/**
* 通过CodePoint截取字符串,可以截断Emoji
*
- * @param str String
+ * @param str String
* @param fromIndex 开始的index(包括)
- * @param toIndex 结束的index(不包括)
+ * @param toIndex 结束的index(不包括)
* @return 字串
*/
public static String subByCodePoint(CharSequence str, int fromIndex, int toIndex) {
@@ -1620,8 +1621,8 @@ public class StrUtil {
/**
* 截取部分字符串,这里一个汉字的长度认为是2
*
- * @param str 字符串
- * @param len 切割的位置
+ * @param str 字符串
+ * @param len 切割的位置
* @param suffix 切割后加上后缀
* @return 切割后的字符串
* @since 3.1.1
@@ -1651,7 +1652,7 @@ public class StrUtil {
/**
* 限制字符串长度,如果超过指定长度,截取指定长度并在末尾加"..."
- *
+ *
* @param string 字符串
* @param length 最大长度
* @return 切割后的剩余的前半部分字符串+"..."
@@ -1670,8 +1671,8 @@ public class StrUtil {
/**
* 切割指定位置之前部分的字符串
- *
- * @param string 字符串
+ *
+ * @param string 字符串
* @param toIndex 切割到的位置(不包括)
* @return 切割后的剩余的前半部分字符串
*/
@@ -1681,8 +1682,8 @@ public class StrUtil {
/**
* 切割指定位置之后部分的字符串
- *
- * @param string 字符串
+ *
+ * @param string 字符串
* @param fromIndex 切割开始的位置(包括)
* @return 切割后后剩余的后半部分字符串
*/
@@ -1695,7 +1696,7 @@ public class StrUtil {
/**
* 切割指定长度的后部分的字符串
- *
+ *
*
* StrUtil.subSufByLength("abcde", 3) = "cde"
* StrUtil.subSufByLength("abcde", 0) = ""
@@ -1705,7 +1706,7 @@ public class StrUtil {
* StrUtil.subSufByLength("abcde", 10) = "abcde"
* StrUtil.subSufByLength(null, 3) = null
*
- *
+ *
* @param string 字符串
* @param length 切割长度
* @return 切割后后剩余的后半部分字符串
@@ -1724,10 +1725,10 @@ public class StrUtil {
/**
* 截取字符串,从指定位置开始,截取指定长度的字符串
* author weibaohui
- *
- * @param input 原始字符串
+ *
+ * @param input 原始字符串
* @param fromIndex 开始的index,包括
- * @param length 要截取的长度
+ * @param length 要截取的长度
* @return 截取后的字符串
*/
public static String subWithLength(String input, int fromIndex, int length) {
@@ -1738,7 +1739,7 @@ public class StrUtil {
* 截取分隔字符串之前的字符串,不包括分隔字符串
* 如果给定的字符串为空串(null或"")或者分隔字符串为null,返回原字符串
* 如果分隔字符串为空串"",则返回空串,如果分隔字符串未找到,返回原字符串,举例如下:
- *
+ *
*
* StrUtil.subBefore(null, *) = null
* StrUtil.subBefore("", *) = ""
@@ -1749,9 +1750,9 @@ public class StrUtil {
* StrUtil.subBefore("abc", "") = ""
* StrUtil.subBefore("abc", null) = "abc"
*
- *
- * @param string 被查找的字符串
- * @param separator 分隔字符串(不包括)
+ *
+ * @param string 被查找的字符串
+ * @param separator 分隔字符串(不包括)
* @param isLastSeparator 是否查找最后一个分隔字符串(多次出现分隔字符串时选取最后一个),true为选取最后一个
* @return 切割后的字符串
* @since 3.1.1
@@ -1780,7 +1781,7 @@ public class StrUtil {
* 截取分隔字符串之前的字符串,不包括分隔字符串
* 如果给定的字符串为空串(null或"")或者分隔字符串为null,返回原字符串
* 如果分隔字符串未找到,返回原字符串,举例如下:
- *
+ *
*
* StrUtil.subBefore(null, *) = null
* StrUtil.subBefore("", *) = ""
@@ -1789,9 +1790,9 @@ public class StrUtil {
* StrUtil.subBefore("abc", 'c') = "ab"
* StrUtil.subBefore("abc", 'd') = "abc"
*
- *
- * @param string 被查找的字符串
- * @param separator 分隔字符串(不包括)
+ *
+ * @param string 被查找的字符串
+ * @param separator 分隔字符串(不包括)
* @param isLastSeparator 是否查找最后一个分隔字符串(多次出现分隔字符串时选取最后一个),true为选取最后一个
* @return 切割后的字符串
* @since 4.1.15
@@ -1828,8 +1829,8 @@ public class StrUtil {
* StrUtil.subAfter("abc", "") = "abc"
*
*
- * @param string 被查找的字符串
- * @param separator 分隔字符串(不包括)
+ * @param string 被查找的字符串
+ * @param separator 分隔字符串(不包括)
* @param isLastSeparator 是否查找最后一个分隔字符串(多次出现分隔字符串时选取最后一个),true为选取最后一个
* @return 切割后的字符串
* @since 3.1.1
@@ -1864,8 +1865,8 @@ public class StrUtil {
* StrUtil.subAfter("abc", 'd') = ""
*
*
- * @param string 被查找的字符串
- * @param separator 分隔字符串(不包括)
+ * @param string 被查找的字符串
+ * @param separator 分隔字符串(不包括)
* @param isLastSeparator 是否查找最后一个分隔字符串(多次出现分隔字符串时选取最后一个),true为选取最后一个
* @return 切割后的字符串
* @since 4.1.15
@@ -1884,9 +1885,9 @@ public class StrUtil {
/**
* 截取指定字符串中间部分,不包括标识字符串
- *
+ *
* 栗子:
- *
+ *
*
* StrUtil.subBetween("wx[b]yz", "[", "]") = "b"
* StrUtil.subBetween(null, *, *) = null
@@ -1899,10 +1900,10 @@ public class StrUtil {
* StrUtil.subBetween("yabcz", "y", "z") = "abc"
* StrUtil.subBetween("yabczyabcz", "y", "z") = "abc"
*
- *
- * @param str 被切割的字符串
+ *
+ * @param str 被切割的字符串
* @param before 截取开始的字符串标识
- * @param after 截取到的字符串标识
+ * @param after 截取到的字符串标识
* @return 截取后的字符串
* @since 3.1.1
*/
@@ -1927,9 +1928,9 @@ public class StrUtil {
/**
* 截取指定字符串中间部分,不包括标识字符串
- *
+ *
* 栗子:
- *
+ *
*
* StrUtil.subBetween(null, *) = null
* StrUtil.subBetween("", "") = ""
@@ -1938,8 +1939,8 @@ public class StrUtil {
* StrUtil.subBetween("tagabctag", "") = ""
* StrUtil.subBetween("tagabctag", "tag") = "abc"
*
- *
- * @param str 被切割的字符串
+ *
+ * @param str 被切割的字符串
* @param beforeAndAfter 截取开始和结束的字符串标识
* @return 截取后的字符串
* @since 3.1.1
@@ -1950,7 +1951,7 @@ public class StrUtil {
/**
* 截取指定字符串多段中间部分,不包括标识字符串
- *
+ *
* 栗子:
*
*
@@ -1967,46 +1968,44 @@ public class StrUtil {
* StrUtil.subBetweenAll("[yabc[zy]abcz]", "[", "]"); = ["zy"] 重叠时只截取内部,
*
*
- * @param str 被切割的字符串
- * @param regexBefore 截取开始的字符串标识
- * @param regexAfter 截取到的字符串标识
+ * @param str 被切割的字符串
+ * @param prefix 截取开始的字符串标识
+ * @param suffix 截取到的字符串标识
* @return 截取后的字符串
* @author dahuoyzs
* @since 5.2.5
*/
- public static String[] subBetweenAll(CharSequence str, CharSequence regexBefore, CharSequence regexAfter) {
- if (str == null || regexBefore == null || regexAfter == null || str.length() < 1 || regexBefore.length() < 1 || regexAfter.length() < 1) {
+ public static String[] subBetweenAll(CharSequence str, CharSequence prefix, CharSequence suffix) {
+ if(hasEmpty(str, prefix, suffix)) {
return new String[0];
}
- final String before = regexBefore.toString().replace("\\", "");
- final String after = regexAfter.toString().replace("\\", "");
- final Integer beforeNumber = StrUtil.count(str, before);
- final Integer afterNumber = StrUtil.count(str, after);
- if (beforeNumber<1||afterNumber<1){
+ final int prefixCount = count(str, prefix);
+ final int suffixCount = count(str, suffix);
+ if (prefixCount < 1 || suffixCount < 1) {
return new String[0];
}
LinkedList betweenList = new LinkedList<>();
- if (beforeNumber.compareTo(afterNumber) > 0) {
- String[] fragments = str.toString().split(regexAfter.toString());
+ if (prefixCount > suffixCount) {
+ String[] fragments = split(str, suffix);
for (int i = 0; i < fragments.length - 1; i++) {
String fragment = fragments[i];
- if (fragment.contains(before)) {
- int beforeIndex = StrUtil.lastIndexOf(fragment, before, 0, false);
+ if (fragment.contains(prefix)) {
+ int beforeIndex = StrUtil.lastIndexOf(fragment, prefix, 0, false);
String between = fragment.substring(beforeIndex);
- if (between.length()>0)
+ if (between.length() > 0)
betweenList.add(between);
}
}
} else {
- String[] fragments = str.toString().split(regexBefore.toString());
+ String[] fragments = split(str, prefix);
for (int i = 1; i < fragments.length; i++) {
String fragment = fragments[i];
- if (fragment.contains(after)) {
- int afterIndex = StrUtil.indexOf(fragment, after, 0, false);
+ if (fragment.contains(suffix)) {
+ int afterIndex = StrUtil.indexOf(fragment, suffix, 0, false);
String between = fragment.substring(0, afterIndex);
- if (between.length()>0)
+ if (between.length() > 0)
betweenList.add(between);
}
}
@@ -2017,8 +2016,8 @@ public class StrUtil {
/**
* 给定字符串是否被字符包围
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param prefix 前缀
* @param suffix 后缀
* @return 是否包围,空串不包围
@@ -2037,8 +2036,8 @@ public class StrUtil {
/**
* 给定字符串是否被字符包围
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param prefix 前缀
* @param suffix 后缀
* @return 是否包围,空串不包围
@@ -2056,8 +2055,8 @@ public class StrUtil {
/**
* 重复某个字符
- *
- * @param c 被重复的字符
+ *
+ * @param c 被重复的字符
* @param count 重复的数目,如果小于等于0则返回""
* @return 重复字符字符串
*/
@@ -2075,8 +2074,8 @@ public class StrUtil {
/**
* 重复某个字符串
- *
- * @param str 被重复的字符
+ *
+ * @param str 被重复的字符
* @param count 重复的数目
* @return 重复字符字符串
*/
@@ -2111,8 +2110,8 @@ public class StrUtil {
/**
* 重复某个字符串到指定长度
- *
- * @param str 被重复的字符
+ *
+ * @param str 被重复的字符
* @param padLen 指定长度
* @return 重复字符字符串
* @since 4.3.2
@@ -2141,15 +2140,15 @@ public class StrUtil {
/**
* 重复某个字符串并通过分界符连接
- *
+ *
*
* StrUtil.repeatAndJoin("?", 5, ",") = "?,?,?,?,?"
* StrUtil.repeatAndJoin("?", 0, ",") = ""
* StrUtil.repeatAndJoin("?", 5, null) = "?????"
*
- *
- * @param str 被重复的字符串
- * @param count 数量
+ *
+ * @param str 被重复的字符串
+ * @param count 数量
* @param conjunction 分界符
* @return 连接后的字符串
* @since 4.0.1
@@ -2173,7 +2172,7 @@ public class StrUtil {
/**
* 比较两个字符串(大小写敏感)。
- *
+ *
*
* equals(null, null) = true
* equals(null, "abc") = false
@@ -2181,10 +2180,9 @@ public class StrUtil {
* equals("abc", "abc") = true
* equals("abc", "ABC") = false
*
- *
+ *
* @param str1 要比较的字符串1
* @param str2 要比较的字符串2
- *
* @return 如果两个字符串相同,或者都是null,则返回true
*/
public static boolean equals(CharSequence str1, CharSequence str2) {
@@ -2193,7 +2191,7 @@ public class StrUtil {
/**
* 比较两个字符串(大小写不敏感)。
- *
+ *
*
* equalsIgnoreCase(null, null) = true
* equalsIgnoreCase(null, "abc") = false
@@ -2201,10 +2199,9 @@ public class StrUtil {
* equalsIgnoreCase("abc", "abc") = true
* equalsIgnoreCase("abc", "ABC") = true
*
- *
+ *
* @param str1 要比较的字符串1
* @param str2 要比较的字符串2
- *
* @return 如果两个字符串相同,或者都是null,则返回true
*/
public static boolean equalsIgnoreCase(CharSequence str1, CharSequence str2) {
@@ -2213,9 +2210,9 @@ public class StrUtil {
/**
* 比较两个字符串是否相等。
- *
- * @param str1 要比较的字符串1
- * @param str2 要比较的字符串2
+ *
+ * @param str1 要比较的字符串1
+ * @param str2 要比较的字符串2
* @param ignoreCase 是否忽略大小写
* @return 如果两个字符串相同,或者都是null,则返回true
* @since 3.2.0
@@ -2240,7 +2237,7 @@ public class StrUtil {
/**
* 给定字符串是否与提供的中任一字符串相同(忽略大小写),相同则返回{@code true},没有相同的返回{@code false}
* 如果参与比对的字符串列表为空,返回{@code false}
- *
+ *
* @param str1 给定需要检查的字符串
* @param strs 需要参与比对的字符串列表
* @return 是否相同
@@ -2253,7 +2250,7 @@ public class StrUtil {
/**
* 给定字符串是否与提供的中任一字符串相同,相同则返回{@code true},没有相同的返回{@code false}
* 如果参与比对的字符串列表为空,返回{@code false}
- *
+ *
* @param str1 给定需要检查的字符串
* @param strs 需要参与比对的字符串列表
* @return 是否相同
@@ -2266,10 +2263,10 @@ public class StrUtil {
/**
* 给定字符串是否与提供的中任一字符串相同,相同则返回{@code true},没有相同的返回{@code false}
* 如果参与比对的字符串列表为空,返回{@code false}
- *
- * @param str1 给定需要检查的字符串
+ *
+ * @param str1 给定需要检查的字符串
* @param ignoreCase 是否忽略大小写
- * @param strs 需要参与比对的字符串列表
+ * @param strs 需要参与比对的字符串列表
* @return 是否相同
* @since 4.3.2
*/
@@ -2294,9 +2291,9 @@ public class StrUtil {
* 通常使用:format("this is {} for {}", "a", "b") =》 this is a for b
* 转义{}: format("this is \\{} for {}", "a", "b") =》 this is \{} for a
* 转义\: format("this is \\\\{} for {}", "a", "b") =》 this is \a for b
- *
+ *
* @param template 文本模板,被替换的部分用 {} 表示
- * @param params 参数值
+ * @param params 参数值
* @return 格式化后的文本
*/
public static String format(CharSequence template, Object... params) {
@@ -2313,8 +2310,8 @@ public class StrUtil {
* 有序的格式化文本,使用{number}做为占位符
* 例:
* 通常使用:format("this is {0} for {1}", "a", "b") =》 this is a for b
- *
- * @param pattern 文本格式
+ *
+ * @param pattern 文本格式
* @param arguments 参数
* @return 格式化后的文本
*/
@@ -2325,9 +2322,9 @@ public class StrUtil {
/**
* 格式化文本,使用 {varName} 占位
* map = {a: "aValue", b: "bValue"} format("{a} and {b}", map) ---=》 aValue and bValue
- *
+ *
* @param template 文本模板,被替换的部分用 {key} 表示
- * @param map 参数值对
+ * @param map 参数值对
* @return 格式化后的文本
*/
public static String format(CharSequence template, Map, ?> map) {
@@ -2351,7 +2348,7 @@ public class StrUtil {
/**
* 编码字符串,编码为UTF-8
- *
+ *
* @param str 字符串
* @return 编码后的字节码
*/
@@ -2362,7 +2359,7 @@ public class StrUtil {
/**
* 编码字符串
* 使用系统默认编码
- *
+ *
* @param str 字符串
* @return 编码后的字节码
*/
@@ -2372,8 +2369,8 @@ public class StrUtil {
/**
* 编码字符串
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param charset 字符集,如果此字段为空,则解码的结果取决于平台
* @return 编码后的字节码
*/
@@ -2383,8 +2380,8 @@ public class StrUtil {
/**
* 编码字符串
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param charset 字符集,如果此字段为空,则解码的结果取决于平台
* @return 编码后的字节码
*/
@@ -2402,7 +2399,7 @@ public class StrUtil {
/**
* 将对象转为字符串
* 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
- *
+ *
* @param obj 对象
* @return 字符串
*/
@@ -2413,8 +2410,8 @@ public class StrUtil {
/**
* 将对象转为字符串
* 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
- *
- * @param obj 对象
+ *
+ * @param obj 对象
* @param charsetName 字符集
* @return 字符串
*/
@@ -2425,8 +2422,8 @@ public class StrUtil {
/**
* 将对象转为字符串
* 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
- *
- * @param obj 对象
+ *
+ * @param obj 对象
* @param charset 字符集
* @return 字符串
*/
@@ -2452,8 +2449,8 @@ public class StrUtil {
/**
* 将byte数组转为字符串
- *
- * @param bytes byte数组
+ *
+ * @param bytes byte数组
* @param charset 字符集
* @return 字符串
*/
@@ -2463,8 +2460,8 @@ public class StrUtil {
/**
* 解码字节码
- *
- * @param data 字符串
+ *
+ * @param data 字符串
* @param charset 字符集,如果此字段为空,则解码的结果取决于平台
* @return 解码后的字符串
*/
@@ -2481,8 +2478,8 @@ public class StrUtil {
/**
* 将Byte数组转为字符串
- *
- * @param bytes byte数组
+ *
+ * @param bytes byte数组
* @param charset 字符集
* @return 字符串
*/
@@ -2492,8 +2489,8 @@ public class StrUtil {
/**
* 解码字节码
- *
- * @param data 字符串
+ *
+ * @param data 字符串
* @param charset 字符集,如果此字段为空,则解码的结果取决于平台
* @return 解码后的字符串
*/
@@ -2514,8 +2511,8 @@ public class StrUtil {
/**
* 将编码的byteBuffer数据转换为字符串
- *
- * @param data 数据
+ *
+ * @param data 数据
* @param charset 字符集,如果为空使用当前系统字符集
* @return 字符串
*/
@@ -2529,8 +2526,8 @@ public class StrUtil {
/**
* 将编码的byteBuffer数据转换为字符串
- *
- * @param data 数据
+ *
+ * @param data 数据
* @param charset 字符集,如果为空使用当前系统字符集
* @return 字符串
*/
@@ -2543,7 +2540,7 @@ public class StrUtil {
/**
* {@link CharSequence} 转为字符串,null安全
- *
+ *
* @param cs {@link CharSequence}
* @return 字符串
*/
@@ -2553,7 +2550,7 @@ public class StrUtil {
/**
* 调用对象的toString方法,null会返回“null”
- *
+ *
* @param obj 对象
* @return 字符串
* @since 4.1.3
@@ -2564,8 +2561,8 @@ public class StrUtil {
/**
* 字符串转换为byteBuffer
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param charset 编码
* @return byteBuffer
*/
@@ -2575,12 +2572,11 @@ public class StrUtil {
/**
* 以 conjunction 为分隔符将多个对象转换为字符串
- *
- * @see ArrayUtil#join(Object, CharSequence)
- *
+ *
* @param conjunction 分隔符
- * @param objs 数组
+ * @param objs 数组
* @return 连接后的字符串
+ * @see ArrayUtil#join(Object, CharSequence)
*/
public static String join(CharSequence conjunction, Object... objs) {
return ArrayUtil.join(objs, conjunction);
@@ -2589,7 +2585,7 @@ public class StrUtil {
/**
* 将驼峰式命名的字符串转换为下划线方式。如果转换前的驼峰式命名的字符串为空,则返回空字符串。
* 例如:
- *
+ *
*
* HelloWorld=》hello_world
* Hello_World=》hello_world
@@ -2606,7 +2602,7 @@ public class StrUtil {
/**
* 将驼峰式命名的字符串转换为使用符号连接方式。如果转换前的驼峰式命名的字符串为空,则返回空字符串。
*
- * @param str 转换前的驼峰式命名的字符串,也可以为符号连接形式
+ * @param str 转换前的驼峰式命名的字符串,也可以为符号连接形式
* @param symbol 连接符
* @return 转换后符号连接方式命名的字符串
* @since 4.0.10
@@ -2692,8 +2688,8 @@ public class StrUtil {
/**
* 包装指定字符串
* 当前缀和后缀一致时使用此方法
- *
- * @param str 被包装的字符串
+ *
+ * @param str 被包装的字符串
* @param prefixAndSuffix 前缀和后缀
* @return 包装后的字符串
* @since 3.1.0
@@ -2704,8 +2700,8 @@ public class StrUtil {
/**
* 包装指定字符串
- *
- * @param str 被包装的字符串
+ *
+ * @param str 被包装的字符串
* @param prefix 前缀
* @param suffix 后缀
* @return 包装后的字符串
@@ -2716,9 +2712,9 @@ public class StrUtil {
/**
* 包装多个字符串
- *
+ *
* @param prefixAndSuffix 前缀和后缀
- * @param strs 多个字符串
+ * @param strs 多个字符串
* @return 包装的字符串数组
* @since 4.0.7
*/
@@ -2728,10 +2724,10 @@ public class StrUtil {
/**
* 包装多个字符串
- *
+ *
* @param prefix 前缀
* @param suffix 后缀
- * @param strs 多个字符串
+ * @param strs 多个字符串
* @return 包装的字符串数组
* @since 4.0.7
*/
@@ -2745,8 +2741,8 @@ public class StrUtil {
/**
* 包装指定字符串,如果前缀或后缀已经包含对应的字符串,则不再包装
- *
- * @param str 被包装的字符串
+ *
+ * @param str 被包装的字符串
* @param prefix 前缀
* @param suffix 后缀
* @return 包装后的字符串
@@ -2777,9 +2773,9 @@ public class StrUtil {
/**
* 包装多个字符串,如果已经包装,则不再包装
- *
+ *
* @param prefixAndSuffix 前缀和后缀
- * @param strs 多个字符串
+ * @param strs 多个字符串
* @return 包装的字符串数组
* @since 4.0.7
*/
@@ -2789,10 +2785,10 @@ public class StrUtil {
/**
* 包装多个字符串,如果已经包装,则不再包装
- *
+ *
* @param prefix 前缀
* @param suffix 后缀
- * @param strs 多个字符串
+ * @param strs 多个字符串
* @return 包装的字符串数组
* @since 4.0.7
*/
@@ -2806,8 +2802,8 @@ public class StrUtil {
/**
* 去掉字符包装,如果未被包装则返回原字符串
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param prefix 前置字符串
* @param suffix 后置字符串
* @return 去掉包装字符的字符串
@@ -2822,8 +2818,8 @@ public class StrUtil {
/**
* 去掉字符包装,如果未被包装则返回原字符串
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param prefix 前置字符
* @param suffix 后置字符
* @return 去掉包装字符的字符串
@@ -2841,8 +2837,8 @@ public class StrUtil {
/**
* 去掉字符包装,如果未被包装则返回原字符串
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param prefixAndSuffix 前置和后置字符
* @return 去掉包装字符的字符串
* @since 4.0.1
@@ -2853,8 +2849,8 @@ public class StrUtil {
/**
* 指定字符串是否被包装
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param prefix 前缀
* @param suffix 后缀
* @return 是否被包装
@@ -2869,8 +2865,8 @@ public class StrUtil {
/**
* 指定字符串是否被同一字符包装(前后都有这些字符串)
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param wrapper 包装字符串
* @return 是否被包装
*/
@@ -2880,8 +2876,8 @@ public class StrUtil {
/**
* 指定字符串是否被同一字符包装(前后都有这些字符串)
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param wrapper 包装字符
* @return 是否被包装
*/
@@ -2891,8 +2887,8 @@ public class StrUtil {
/**
* 指定字符串是否被包装
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param prefixChar 前缀
* @param suffixChar 后缀
* @return 是否被包装
@@ -2907,16 +2903,16 @@ public class StrUtil {
/**
* 补充字符串以满足最小长度
- *
+ *
*
* StrUtil.padPre(null, *, *);//null
* StrUtil.padPre("1", 3, "ABC");//"AB1"
* StrUtil.padPre("123", 2, "ABC");//"12"
*
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param minLength 最小长度
- * @param padStr 补充的字符
+ * @param padStr 补充的字符
* @return 补充后的字符串
*/
public static String padPre(CharSequence str, int minLength, CharSequence padStr) {
@@ -2935,16 +2931,16 @@ public class StrUtil {
/**
* 补充字符串以满足最小长度
- *
+ *
*
* StrUtil.padPre(null, *, *);//null
* StrUtil.padPre("1", 3, '0');//"001"
* StrUtil.padPre("123", 2, '0');//"12"
*
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param minLength 最小长度
- * @param padChar 补充的字符
+ * @param padChar 补充的字符
* @return 补充后的字符串
*/
public static String padPre(CharSequence str, int minLength, char padChar) {
@@ -2963,16 +2959,16 @@ public class StrUtil {
/**
* 补充字符串以满足最小长度
- *
+ *
*
* StrUtil.padAfter(null, *, *);//null
* StrUtil.padAfter("1", 3, '0');//"100"
* StrUtil.padAfter("123", 2, '0');//"23"
*
- *
- * @param str 字符串,如果为null,按照空串处理
+ *
+ * @param str 字符串,如果为null,按照空串处理
* @param minLength 最小长度
- * @param padChar 补充的字符
+ * @param padChar 补充的字符
* @return 补充后的字符串
*/
public static String padAfter(CharSequence str, int minLength, char padChar) {
@@ -2991,16 +2987,16 @@ public class StrUtil {
/**
* 补充字符串以满足最小长度
- *
+ *
*
* StrUtil.padAfter(null, *, *);//null
* StrUtil.padAfter("1", 3, "ABC");//"1AB"
* StrUtil.padAfter("123", 2, "ABC");//"23"
*
- *
- * @param str 字符串,如果为null,按照空串处理
+ *
+ * @param str 字符串,如果为null,按照空串处理
* @param minLength 最小长度
- * @param padStr 补充的字符
+ * @param padStr 补充的字符
* @return 补充后的字符串
* @since 4.3.2
*/
@@ -3020,7 +3016,7 @@ public class StrUtil {
/**
* 居中字符串,两边补充指定字符串,如果指定长度小于字符串,则返回原字符串
- *
+ *
*
* StrUtil.center(null, *) = null
* StrUtil.center("", 4) = " "
@@ -3030,7 +3026,7 @@ public class StrUtil {
* StrUtil.center("a", 4) = " a "
*
*
- * @param str 字符串
+ * @param str 字符串
* @param size 指定长度
* @return 补充后的字符串
* @since 4.3.2
@@ -3041,7 +3037,7 @@ public class StrUtil {
/**
* 居中字符串,两边补充指定字符串,如果指定长度小于字符串,则返回原字符串
- *
+ *
*
* StrUtil.center(null, *, *) = null
* StrUtil.center("", 4, ' ') = " "
@@ -3053,8 +3049,8 @@ public class StrUtil {
* StrUtil.center("abc", 7, ' ') = " abc "
*
*
- * @param str 字符串
- * @param size 指定长度
+ * @param str 字符串
+ * @param size 指定长度
* @param padChar 两边补充的字符
* @return 补充后的字符串
* @since 4.3.2
@@ -3075,7 +3071,7 @@ public class StrUtil {
/**
* 居中字符串,两边补充指定字符串,如果指定长度小于字符串,则返回原字符串
- *
+ *
*
* StrUtil.center(null, *, *) = null
* StrUtil.center("", 4, " ") = " "
@@ -3088,8 +3084,8 @@ public class StrUtil {
* StrUtil.center("abc", 7, "") = " abc "
*
*
- * @param str 字符串
- * @param size 指定长度
+ * @param str 字符串
+ * @param size 指定长度
* @param padStr 两边补充的字符串
* @return 补充后的字符串
*/
@@ -3112,7 +3108,7 @@ public class StrUtil {
/**
* 创建StringBuilder对象
- *
+ *
* @return StringBuilder对象
*/
public static StringBuilder builder() {
@@ -3121,7 +3117,7 @@ public class StrUtil {
/**
* 创建StrBuilder对象
- *
+ *
* @return StrBuilder对象
* @since 4.0.1
*/
@@ -3131,7 +3127,7 @@ public class StrUtil {
/**
* 创建StringBuilder对象
- *
+ *
* @param capacity 初始大小
* @return StringBuilder对象
*/
@@ -3141,7 +3137,7 @@ public class StrUtil {
/**
* 创建StrBuilder对象
- *
+ *
* @param capacity 初始大小
* @return StrBuilder对象
* @since 4.0.1
@@ -3152,7 +3148,7 @@ public class StrUtil {
/**
* 创建StringBuilder对象
- *
+ *
* @param strs 初始字符串列表
* @return StringBuilder对象
*/
@@ -3166,7 +3162,7 @@ public class StrUtil {
/**
* 创建StrBuilder对象
- *
+ *
* @param strs 初始字符串列表
* @return StrBuilder对象
*/
@@ -3176,7 +3172,7 @@ public class StrUtil {
/**
* 获得StringReader
- *
+ *
* @param str 字符串
* @return StringReader
*/
@@ -3189,7 +3185,7 @@ public class StrUtil {
/**
* 获得StringWriter
- *
+ *
* @return StringWriter
*/
public static StringWriter getWriter() {
@@ -3210,7 +3206,7 @@ public class StrUtil {
* StrUtil.count("abba", "xxx") = 0
*
*
- * @param content 被查找的字符串
+ * @param content 被查找的字符串
* @param strForSearch 需要查找的字符串
* @return 查找到的个数
*/
@@ -3232,8 +3228,8 @@ public class StrUtil {
/**
* 统计指定内容中包含指定字符的数量
- *
- * @param content 内容
+ *
+ * @param content 内容
* @param charForSearch 被统计的字符
* @return 包含数量
*/
@@ -3253,8 +3249,8 @@ public class StrUtil {
/**
* 将字符串切分为N等份
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param partLength 每等份的长度
* @return 切分后的数组
* @since 3.0.6
@@ -3265,7 +3261,7 @@ public class StrUtil {
}
int len = str.length();
if (len < partLength) {
- return new String[] { str.toString() };
+ return new String[]{str.toString()};
}
int part = NumberUtil.count(len, partLength);
final String[] array = new String[part];
@@ -3279,8 +3275,8 @@ public class StrUtil {
/**
* 将给定字符串,变成 "xxx...xxx" 形式的字符串
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param maxLength 最大长度
* @return 截取后的字符串
*/
@@ -3300,7 +3296,7 @@ public class StrUtil {
/**
* 比较两个字符串,用于排序
- *
+ *
*
* StrUtil.compare(null, null, *) = 0
* StrUtil.compare(null , "a", true) < 0
@@ -3313,9 +3309,9 @@ public class StrUtil {
* StrUtil.compare("a", "B", *) > 0
* StrUtil.compare("ab", "abc", *) < 0
*
- *
- * @param str1 字符串1
- * @param str2 字符串2
+ *
+ * @param str1 字符串1
+ * @param str2 字符串2
* @param nullIsLess {@code null} 值是否排在前(null是否小于非空值)
* @return 排序值。负数:str1 < str2,正数:str1 > str2, 0:str1 == str2
*/
@@ -3334,7 +3330,7 @@ public class StrUtil {
/**
* 比较两个字符串,用于排序,大小写不敏感
- *
+ *
*
* StrUtil.compareIgnoreCase(null, null, *) = 0
* StrUtil.compareIgnoreCase(null , "a", true) < 0
@@ -3349,9 +3345,9 @@ public class StrUtil {
* StrUtil.compareIgnoreCase("A", "b", *) < 0
* StrUtil.compareIgnoreCase("ab", "abc", *) < 0
*
- *
- * @param str1 字符串1
- * @param str2 字符串2
+ *
+ * @param str1 字符串1
+ * @param str2 字符串2
* @param nullIsLess {@code null} 值是否排在前(null是否小于非空值)
* @return 排序值。负数:str1 < str2,正数:str1 > str2, 0:str1 == str2
*/
@@ -3371,7 +3367,7 @@ public class StrUtil {
/**
* 比较两个版本
* null版本排在最小:即:
- *
+ *
*
* StrUtil.compareVersion(null, "v1") < 0
* StrUtil.compareVersion("v1", "v1") = 0
@@ -3382,7 +3378,7 @@ public class StrUtil {
* StrUtil.compareVersion("1.13.0", "1.12.1c") > 0
* StrUtil.compareVersion("V0.0.20170102", "V0.0.20170101") > 0
*
- *
+ *
* @param version1 版本1
* @param version2 版本2
* @return 排序值。负数:version1 < version2,正数:version1 > version2, 0:version1 == version2
@@ -3394,8 +3390,8 @@ public class StrUtil {
/**
* 指定范围内查找指定字符
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param searchChar 被查找的字符
* @return 位置
*/
@@ -3405,10 +3401,10 @@ public class StrUtil {
/**
* 指定范围内查找指定字符
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param searchChar 被查找的字符
- * @param start 起始位置,如果小于0,从0开始查找
+ * @param start 起始位置,如果小于0,从0开始查找
* @return 位置
*/
public static int indexOf(final CharSequence str, char searchChar, int start) {
@@ -3421,11 +3417,11 @@ public class StrUtil {
/**
* 指定范围内查找指定字符
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param searchChar 被查找的字符
- * @param start 起始位置,如果小于0,从0开始查找
- * @param end 终止位置,如果超过str.length()则默认查找到字符串末尾
+ * @param start 起始位置,如果小于0,从0开始查找
+ * @param end 终止位置,如果超过str.length()则默认查找到字符串末尾
* @return 位置
*/
public static int indexOf(final CharSequence str, char searchChar, int start, int end) {
@@ -3446,7 +3442,7 @@ public class StrUtil {
/**
* 指定范围内查找字符串,忽略大小写
- *
+ *
*
* StrUtil.indexOfIgnoreCase(null, *, *) = -1
* StrUtil.indexOfIgnoreCase(*, null, *) = -1
@@ -3460,8 +3456,8 @@ public class StrUtil {
* StrUtil.indexOfIgnoreCase("aabaabaa", "", 2) = 2
* StrUtil.indexOfIgnoreCase("abc", "", 9) = -1
*
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param searchStr 需要查找位置的字符串
* @return 位置
* @since 3.2.1
@@ -3472,7 +3468,7 @@ public class StrUtil {
/**
* 指定范围内查找字符串
- *
+ *
*
* StrUtil.indexOfIgnoreCase(null, *, *) = -1
* StrUtil.indexOfIgnoreCase(*, null, *) = -1
@@ -3486,8 +3482,8 @@ public class StrUtil {
* StrUtil.indexOfIgnoreCase("aabaabaa", "", 2) = 2
* StrUtil.indexOfIgnoreCase("abc", "", 9) = -1
*
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param searchStr 需要查找位置的字符串
* @param fromIndex 起始位置
* @return 位置
@@ -3499,10 +3495,10 @@ public class StrUtil {
/**
* 指定范围内查找字符串
- *
- * @param str 字符串
- * @param searchStr 需要查找位置的字符串
- * @param fromIndex 起始位置
+ *
+ * @param str 字符串
+ * @param searchStr 需要查找位置的字符串
+ * @param fromIndex 起始位置
* @param ignoreCase 是否忽略大小写
* @return 位置
* @since 3.2.1
@@ -3538,8 +3534,8 @@ public class StrUtil {
/**
* 指定范围内查找字符串,忽略大小写
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param searchStr 需要查找位置的字符串
* @return 位置
* @since 3.2.1
@@ -3551,8 +3547,8 @@ public class StrUtil {
/**
* 指定范围内查找字符串,忽略大小写
* fromIndex 为搜索起始位置,从后往前计数
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param searchStr 需要查找位置的字符串
* @param fromIndex 起始位置,从后往前计数
* @return 位置
@@ -3565,10 +3561,10 @@ public class StrUtil {
/**
* 指定范围内查找字符串
* fromIndex 为搜索起始位置,从后往前计数
- *
- * @param str 字符串
- * @param searchStr 需要查找位置的字符串
- * @param fromIndex 起始位置,从后往前计数
+ *
+ * @param str 字符串
+ * @param searchStr 需要查找位置的字符串
+ * @param fromIndex 起始位置,从后往前计数
* @param ignoreCase 是否忽略大小写
* @return 位置
* @since 3.2.1
@@ -3605,9 +3601,9 @@ public class StrUtil {
*
* 如果 str=null 或 searchStr=null 或 ordinal≥0 则返回-1
* 此方法来自:Apache-Commons-Lang
- *
+ *
* 例子(*代表任意字符):
- *
+ *
*
* StrUtil.ordinalIndexOf(null, *, *) = -1
* StrUtil.ordinalIndexOf(*, null, *) = -1
@@ -3622,9 +3618,9 @@ public class StrUtil {
* StrUtil.ordinalIndexOf("aabaabaa", "", 2) = 0
*
*
- * @param str 被检查的字符串,可以为null
+ * @param str 被检查的字符串,可以为null
* @param searchStr 被查找的字符串,可以为null
- * @param ordinal 第几次出现的位置
+ * @param ordinal 第几次出现的位置
* @return 查找到的位置
* @since 3.2.3
*/
@@ -3648,14 +3644,14 @@ public class StrUtil {
}
// ------------------------------------------------------------------------------------------------------------------ Append and prepend
+
/**
* 如果给定字符串不是以给定的一个或多个字符串为结尾,则在尾部添加结尾字符串
* 不忽略大小写
*
- * @param str 被检查的字符串
- * @param suffix 需要添加到结尾的字符串
+ * @param str 被检查的字符串
+ * @param suffix 需要添加到结尾的字符串
* @param suffixes 需要额外检查的结尾字符串,如果以这些中的一个为结尾,则不再添加
- *
* @return 如果已经结尾,返回原字符串,否则返回添加结尾的字符串
* @since 3.0.7
*/
@@ -3667,10 +3663,9 @@ public class StrUtil {
* 如果给定字符串不是以给定的一个或多个字符串为结尾,则在尾部添加结尾字符串
* 忽略大小写
*
- * @param str 被检查的字符串
- * @param suffix 需要添加到结尾的字符串
+ * @param str 被检查的字符串
+ * @param suffix 需要添加到结尾的字符串
* @param suffixes 需要额外检查的结尾字符串,如果以这些中的一个为结尾,则不再添加
- *
* @return 如果已经结尾,返回原字符串,否则返回添加结尾的字符串
* @since 3.0.7
*/
@@ -3681,11 +3676,10 @@ public class StrUtil {
/**
* 如果给定字符串不是以给定的一个或多个字符串为结尾,则在尾部添加结尾字符串
*
- * @param str 被检查的字符串
- * @param suffix 需要添加到结尾的字符串
+ * @param str 被检查的字符串
+ * @param suffix 需要添加到结尾的字符串
* @param ignoreCase 检查结尾时是否忽略大小写
- * @param suffixes 需要额外检查的结尾字符串,如果以这些中的一个为结尾,则不再添加
- *
+ * @param suffixes 需要额外检查的结尾字符串,如果以这些中的一个为结尾,则不再添加
* @return 如果已经结尾,返回原字符串,否则返回添加结尾的字符串
* @since 3.0.7
*/
@@ -3707,10 +3701,9 @@ public class StrUtil {
* 如果给定字符串不是以给定的一个或多个字符串为开头,则在首部添加起始字符串
* 不忽略大小写
*
- * @param str 被检查的字符串
- * @param prefix 需要添加到首部的字符串
+ * @param str 被检查的字符串
+ * @param prefix 需要添加到首部的字符串
* @param prefixes 需要额外检查的首部字符串,如果以这些中的一个为起始,则不再添加
- *
* @return 如果已经结尾,返回原字符串,否则返回添加结尾的字符串
* @since 3.0.7
*/
@@ -3722,10 +3715,9 @@ public class StrUtil {
* 如果给定字符串不是以给定的一个或多个字符串为开头,则在首部添加起始字符串
* 忽略大小写
*
- * @param str 被检查的字符串
- * @param prefix 需要添加到首部的字符串
+ * @param str 被检查的字符串
+ * @param prefix 需要添加到首部的字符串
* @param prefixes 需要额外检查的首部字符串,如果以这些中的一个为起始,则不再添加
- *
* @return 如果已经结尾,返回原字符串,否则返回添加结尾的字符串
* @since 3.0.7
*/
@@ -3736,11 +3728,10 @@ public class StrUtil {
/**
* 如果给定字符串不是以给定的一个或多个字符串为开头,则在首部添加起始字符串
*
- * @param str 被检查的字符串
- * @param prefix 需要添加到首部的字符串
+ * @param str 被检查的字符串
+ * @param prefix 需要添加到首部的字符串
* @param ignoreCase 检查结尾时是否忽略大小写
- * @param prefixes 需要额外检查的首部字符串,如果以这些中的一个为起始,则不再添加
- *
+ * @param prefixes 需要额外检查的首部字符串,如果以这些中的一个为起始,则不再添加
* @return 如果已经结尾,返回原字符串,否则返回添加结尾的字符串
* @since 3.0.7
*/
@@ -3761,7 +3752,7 @@ public class StrUtil {
/**
* 反转字符串
* 例如:abcd =》dcba
- *
+ *
* @param str 被反转的字符串
* @return 反转后的字符串
* @since 3.0.9
@@ -3773,10 +3764,10 @@ public class StrUtil {
/**
* 将已有字符串填充为规定长度,如果已有字符串超过这个长度则返回这个字符串
* 字符填充于字符串前
- *
- * @param str 被填充的字符串
+ *
+ * @param str 被填充的字符串
* @param filledChar 填充的字符
- * @param len 填充长度
+ * @param len 填充长度
* @return 填充后的字符串
* @since 3.1.2
*/
@@ -3787,10 +3778,10 @@ public class StrUtil {
/**
* 将已有字符串填充为规定长度,如果已有字符串超过这个长度则返回这个字符串
* 字符填充于字符串后
- *
- * @param str 被填充的字符串
+ *
+ * @param str 被填充的字符串
* @param filledChar 填充的字符
- * @param len 填充长度
+ * @param len 填充长度
* @return 填充后的字符串
* @since 3.1.2
*/
@@ -3800,11 +3791,11 @@ public class StrUtil {
/**
* 将已有字符串填充为规定长度,如果已有字符串超过这个长度则返回这个字符串
- *
- * @param str 被填充的字符串
+ *
+ * @param str 被填充的字符串
* @param filledChar 填充的字符
- * @param len 填充长度
- * @param isPre 是否填充在前
+ * @param len 填充长度
+ * @param isPre 是否填充在前
* @return 填充后的字符串
* @since 3.1.2
*/
@@ -3821,12 +3812,12 @@ public class StrUtil {
/**
* 截取两个字符串的不同部分(长度一致),判断截取的子串是否相同
* 任意一个字符串为null返回false
- *
- * @param str1 第一个字符串
- * @param start1 第一个字符串开始的位置
- * @param str2 第二个字符串
- * @param start2 第二个字符串开始的位置
- * @param length 截取长度
+ *
+ * @param str1 第一个字符串
+ * @param start1 第一个字符串开始的位置
+ * @param str2 第二个字符串
+ * @param start2 第二个字符串开始的位置
+ * @param length 截取长度
* @param ignoreCase 是否忽略大小写
* @return 子串是否相同
* @since 3.2.1
@@ -3841,8 +3832,8 @@ public class StrUtil {
/**
* 字符串的每一个字符是否都与定义的匹配器匹配
- *
- * @param value 字符串
+ *
+ * @param value 字符串
* @param matcher 匹配器
* @return 是否全部匹配
* @since 3.2.3
@@ -3861,9 +3852,9 @@ public class StrUtil {
/**
* 替换字符串中的指定字符串,忽略大小写
- *
- * @param str 字符串
- * @param searchStr 被查找的字符串
+ *
+ * @param str 字符串
+ * @param searchStr 被查找的字符串
* @param replacement 被替换的字符串
* @return 替换后的字符串
* @since 4.0.3
@@ -3874,9 +3865,9 @@ public class StrUtil {
/**
* 替换字符串中的指定字符串
- *
- * @param str 字符串
- * @param searchStr 被查找的字符串
+ *
+ * @param str 字符串
+ * @param searchStr 被查找的字符串
* @param replacement 被替换的字符串
* @return 替换后的字符串
* @since 4.0.3
@@ -3887,11 +3878,11 @@ public class StrUtil {
/**
* 替换字符串中的指定字符串
- *
- * @param str 字符串
- * @param searchStr 被查找的字符串
+ *
+ * @param str 字符串
+ * @param searchStr 被查找的字符串
* @param replacement 被替换的字符串
- * @param ignoreCase 是否忽略大小写
+ * @param ignoreCase 是否忽略大小写
* @return 替换后的字符串
* @since 4.0.3
*/
@@ -3901,12 +3892,12 @@ public class StrUtil {
/**
* 替换字符串中的指定字符串
- *
- * @param str 字符串
- * @param fromIndex 开始位置(包括)
- * @param searchStr 被查找的字符串
+ *
+ * @param str 字符串
+ * @param fromIndex 开始位置(包括)
+ * @param searchStr 被查找的字符串
* @param replacement 被替换的字符串
- * @param ignoreCase 是否忽略大小写
+ * @param ignoreCase 是否忽略大小写
* @return 替换后的字符串
* @since 4.0.3
*/
@@ -3948,10 +3939,10 @@ public class StrUtil {
/**
* 替换指定字符串的指定区间内字符为固定字符
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param startInclude 开始位置(包含)
- * @param endExclude 结束位置(不包含)
+ * @param endExclude 结束位置(不包含)
* @param replacedChar 被替换的字符
* @return 替换后的字符串
* @since 3.2.1
@@ -3985,9 +3976,9 @@ public class StrUtil {
/**
* 替换所有正则匹配的文本,并使用自定义函数决定如何替换
- *
- * @param str 要替换的字符串
- * @param pattern 用于匹配的正则式
+ *
+ * @param str 要替换的字符串
+ * @param pattern 用于匹配的正则式
* @param replaceFun 决定如何替换的函数
* @return 替换后的字符串
* @see ReUtil#replaceAll(CharSequence, Pattern, Func1)
@@ -3999,9 +3990,9 @@ public class StrUtil {
/**
* 替换所有正则匹配的文本,并使用自定义函数决定如何替换
- *
- * @param str 要替换的字符串
- * @param regex 用于匹配的正则式
+ *
+ * @param str 要替换的字符串
+ * @param regex 用于匹配的正则式
* @param replaceFun 决定如何替换的函数
* @return 替换后的字符串
* @see ReUtil#replaceAll(CharSequence, String, Func1)
@@ -4014,9 +4005,9 @@ public class StrUtil {
/**
* 替换指定字符串的指定区间内字符为"*"
*
- * @param str 字符串
+ * @param str 字符串
* @param startInclude 开始位置(包含)
- * @param endExclude 结束位置(不包含)
+ * @param endExclude 结束位置(不包含)
* @return 替换后的字符串
* @since 4.1.14
*/
@@ -4027,9 +4018,9 @@ public class StrUtil {
/**
* 替换字符字符数组中所有的字符为replacedStr
* 提供的chars为所有需要被替换的字符,例如:"\r\n",则"\r"和"\n"都会被替换,哪怕他们单独存在
- *
- * @param str 被检查的字符串
- * @param chars 需要替换的字符列表,用一个字符串表示这个字符列表
+ *
+ * @param str 被检查的字符串
+ * @param chars 需要替换的字符列表,用一个字符串表示这个字符列表
* @param replacedStr 替换成的字符串
* @return 新字符串
* @since 3.2.2
@@ -4043,9 +4034,9 @@ public class StrUtil {
/**
* 替换字符字符数组中所有的字符为replacedStr
- *
- * @param str 被检查的字符串
- * @param chars 需要替换的字符列表
+ *
+ * @param str 被检查的字符串
+ * @param chars 需要替换的字符列表
* @param replacedStr 替换成的字符串
* @return 新字符串
* @since 3.2.2
@@ -4071,7 +4062,7 @@ public class StrUtil {
/**
* 计算两个字符串的相似度
- *
+ *
* @param str1 字符串1
* @param str2 字符串2
* @return 相似度
@@ -4083,9 +4074,9 @@ public class StrUtil {
/**
* 计算连个字符串的相似度百分比
- *
- * @param str1 字符串1
- * @param str2 字符串2
+ *
+ * @param str1 字符串1
+ * @param str2 字符串2
* @param scale 相似度
* @return 相似度百分比
* @since 3.2.3
@@ -4099,10 +4090,10 @@ public class StrUtil {
* 如果字符串为null,返回false
* 如果给定的位置大于字符串长度,返回false
* 如果给定的位置小于0,返回false
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param position 位置
- * @param c 需要对比的字符
+ * @param c 需要对比的字符
* @return 字符串指定位置的字符是否与给定字符相同
* @since 3.3.1
*/
@@ -4116,7 +4107,7 @@ public class StrUtil {
/**
* 给定字符串数组的总长度
* null字符长度定义为0
- *
+ *
* @param strs 字符串数组
* @return 总长度
* @since 4.0.1
@@ -4133,11 +4124,11 @@ public class StrUtil {
* 循环位移指定位置的字符串为指定距离
* 当moveLength大于0向右位移,小于0向左位移,0不位移
* 当moveLength大于字符串长度时采取循环位移策略,即位移到头后从头(尾)位移,例如长度为10,位移13则表示位移3
- *
- * @param str 字符串
+ *
+ * @param str 字符串
* @param startInclude 起始位置(包括)
- * @param endExclude 结束位置(不包括)
- * @param moveLength 移动距离,负数表示左移,正数为右移
+ * @param endExclude 结束位置(不包括)
+ * @param moveLength 移动距离,负数表示左移,正数为右移
* @return 位移后的字符串
* @since 4.0.7
*/
@@ -4171,10 +4162,10 @@ public class StrUtil {
/**
* 生成随机UUID
- *
+ *
* @return UUID字符串
- * @since 4.0.10
* @see IdUtil#randomUUID()
+ * @since 4.0.10
*/
public static String uuid() {
return IdUtil.randomUUID();
@@ -4182,9 +4173,9 @@ public class StrUtil {
/**
* 连接多个字符串为一个
- *
+ *
* @param isNullToEmpty 是否null转为""
- * @param strs 字符串数组
+ * @param strs 字符串数组
* @return 连接后的字符串
* @since 4.1.0
*/
@@ -4198,12 +4189,12 @@ public class StrUtil {
/**
* 给定字符串中的字母是否全部为大写,判断依据如下:
- *
+ *
*
* 1. 大写字母包括A-Z
* 2. 其它非字母的Unicode符都算作大写
*
- *
+ *
* @param str 被检查的字符串
* @return 是否全部为大写
* @since 4.2.2
@@ -4223,12 +4214,12 @@ public class StrUtil {
/**
* 给定字符串中的字母是否全部为小写,判断依据如下:
- *
+ *
*
* 1. 小写字母包括a-z
* 2. 其它非字母的Unicode符都算作小写
*
- *
+ *
* @param str 被检查的字符串
* @return 是否全部为小写
* @since 4.2.2
@@ -4256,11 +4247,11 @@ public class StrUtil {
public static int length(CharSequence cs) {
return cs == null ? 0 : cs.length();
}
-
+
/**
* 给定字符串转为bytes后的byte数(byte长度)
- *
- * @param cs 字符串
+ *
+ * @param cs 字符串
* @param charset 编码
* @return byte长度
* @since 4.5.2
diff --git a/hutool-core/src/test/java/cn/hutool/core/util/StrUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/StrUtilTest.java
index f0fd31419..6e3a41fde 100644
--- a/hutool-core/src/test/java/cn/hutool/core/util/StrUtilTest.java
+++ b/hutool-core/src/test/java/cn/hutool/core/util/StrUtilTest.java
@@ -424,8 +424,8 @@ public class StrUtilTest {
@Test
public void subBetweenAllTest() {
- Assert.assertArrayEquals(new String[]{"yz","abc"},StrUtil.subBetweenAll("saho[yz]fdsadp[abc]a","\\[","\\]"));
- Assert.assertArrayEquals(new String[]{"abc"}, StrUtil.subBetweenAll("saho[yzfdsadp[abc]a]","\\[","\\]"));
+ Assert.assertArrayEquals(new String[]{"yz","abc"},StrUtil.subBetweenAll("saho[yz]fdsadp[abc]a","[","]"));
+ Assert.assertArrayEquals(new String[]{"abc"}, StrUtil.subBetweenAll("saho[yzfdsadp[abc]a]","[","]"));
}
}
From 3eaf4702f52ff2c144abc2b29bb4cd38345fc9ea Mon Sep 17 00:00:00 2001
From: Looly
Date: Sun, 29 Mar 2020 12:29:12 +0800
Subject: [PATCH 007/157] add method
---
CHANGELOG.md | 1 +
.../java/cn/hutool/core/util/StrUtil.java | 41 ++++---------------
.../java/cn/hutool/core/util/StrUtilTest.java | 5 +++
3 files changed, 15 insertions(+), 32 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3c2aa0da2..9651cee1e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@
### 新特性
* 【extra 】 JschUtil增加execByShell方法(issue#I1CYES@Gitee)
+* 【core 】 StrUtil增加subBetweenAll方法,Console增加where和lineNumber方法(issue#812@Github)
### Bug修复
* 【extra 】 修复SpringUtil使用devtools重启报错问题
diff --git a/hutool-core/src/main/java/cn/hutool/core/util/StrUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/StrUtil.java
index afe1ca6cf..f3f36f253 100644
--- a/hutool-core/src/main/java/cn/hutool/core/util/StrUtil.java
+++ b/hutool-core/src/main/java/cn/hutool/core/util/StrUtil.java
@@ -1968,50 +1968,27 @@ public class StrUtil {
* StrUtil.subBetweenAll("[yabc[zy]abcz]", "[", "]"); = ["zy"] 重叠时只截取内部,
*
*
- * @param str 被切割的字符串
+ * @param str 被切割的字符串
* @param prefix 截取开始的字符串标识
- * @param suffix 截取到的字符串标识
+ * @param suffix 截取到的字符串标识
* @return 截取后的字符串
* @author dahuoyzs
* @since 5.2.5
*/
public static String[] subBetweenAll(CharSequence str, CharSequence prefix, CharSequence suffix) {
- if(hasEmpty(str, prefix, suffix)) {
+ if (hasEmpty(str, prefix, suffix)) {
return new String[0];
}
- final int prefixCount = count(str, prefix);
- final int suffixCount = count(str, suffix);
- if (prefixCount < 1 || suffixCount < 1) {
- return new String[0];
- }
-
- LinkedList betweenList = new LinkedList<>();
- if (prefixCount > suffixCount) {
- String[] fragments = split(str, suffix);
- for (int i = 0; i < fragments.length - 1; i++) {
- String fragment = fragments[i];
- if (fragment.contains(prefix)) {
- int beforeIndex = StrUtil.lastIndexOf(fragment, prefix, 0, false);
- String between = fragment.substring(beforeIndex);
- if (between.length() > 0)
- betweenList.add(between);
- }
- }
- } else {
- String[] fragments = split(str, prefix);
- for (int i = 1; i < fragments.length; i++) {
- String fragment = fragments[i];
- if (fragment.contains(suffix)) {
- int afterIndex = StrUtil.indexOf(fragment, suffix, 0, false);
- String between = fragment.substring(0, afterIndex);
- if (between.length() > 0)
- betweenList.add(between);
- }
+ final List result = new LinkedList<>();
+ for (String fragment : split(str, prefix)) {
+ int suffixIndex = fragment.indexOf(suffix.toString());
+ if (suffixIndex > 0) {
+ result.add(fragment.substring(0, suffixIndex));
}
}
- return betweenList.toArray(new String[0]);
+ return result.toArray(new String[0]);
}
/**
diff --git a/hutool-core/src/test/java/cn/hutool/core/util/StrUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/StrUtilTest.java
index 6e3a41fde..770ded054 100644
--- a/hutool-core/src/test/java/cn/hutool/core/util/StrUtilTest.java
+++ b/hutool-core/src/test/java/cn/hutool/core/util/StrUtilTest.java
@@ -426,6 +426,11 @@ public class StrUtilTest {
public void subBetweenAllTest() {
Assert.assertArrayEquals(new String[]{"yz","abc"},StrUtil.subBetweenAll("saho[yz]fdsadp[abc]a","[","]"));
Assert.assertArrayEquals(new String[]{"abc"}, StrUtil.subBetweenAll("saho[yzfdsadp[abc]a]","[","]"));
+ Assert.assertArrayEquals(new String[]{"abc", "abc"}, StrUtil.subBetweenAll("yabczyabcz","y","z"));
+ Assert.assertArrayEquals(new String[0], StrUtil.subBetweenAll(null,"y","z"));
+ Assert.assertArrayEquals(new String[0], StrUtil.subBetweenAll("","y","z"));
+ Assert.assertArrayEquals(new String[0], StrUtil.subBetweenAll("abc",null,"z"));
+ Assert.assertArrayEquals(new String[0], StrUtil.subBetweenAll("abc","y",null));
}
}
From 2783f17472ea8a37747dcd7093e838b5ef6798d7 Mon Sep 17 00:00:00 2001
From: Looly
Date: Mon, 30 Mar 2020 10:38:15 +0800
Subject: [PATCH 008/157] add setFreezePane
---
.../main/java/cn/hutool/json/JSONUtil.java | 22 +++++++++++++++++
.../java/cn/hutool/poi/excel/ExcelWriter.java | 24 +++++++++++++++++++
.../hutool/poi/excel/test/ExcelWriteTest.java | 2 ++
3 files changed, 48 insertions(+)
diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONUtil.java b/hutool-json/src/main/java/cn/hutool/json/JSONUtil.java
index 21d741b83..b7fa8d8e4 100644
--- a/hutool-json/src/main/java/cn/hutool/json/JSONUtil.java
+++ b/hutool-json/src/main/java/cn/hutool/json/JSONUtil.java
@@ -48,6 +48,17 @@ public final class JSONUtil {
return new JSONObject();
}
+ /**
+ * 创建JSONObject
+ *
+ * @param config JSON配置
+ * @return JSONObject
+ * @since 5.2.5
+ */
+ public static JSONObject createObj(JSONConfig config) {
+ return new JSONObject(config);
+ }
+
/**
* 创建 JSONArray
*
@@ -57,6 +68,17 @@ public final class JSONUtil {
return new JSONArray();
}
+ /**
+ * 创建 JSONArray
+ *
+ * @param config JSON配置
+ * @return JSONArray
+ * @since 5.2.5
+ */
+ public static JSONArray createArray(JSONConfig config) {
+ return new JSONArray(config);
+ }
+
/**
* JSON字符串转JSONObject对象
*
diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelWriter.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelWriter.java
index cd7e2ee0b..1f2a27cbb 100644
--- a/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelWriter.java
+++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelWriter.java
@@ -470,6 +470,30 @@ public class ExcelWriter extends ExcelBase {
return this;
}
+ /**
+ * 设置窗口冻结,之前冻结的窗口会被覆盖,如果rowSplit为0表示取消冻结
+ *
+ * @param rowSplit 冻结的行及行数,2表示前两行
+ * @return this
+ * @since 5.2.5
+ */
+ public ExcelWriter setFreezePane(int rowSplit){
+ return setFreezePane(0, rowSplit);
+ }
+
+ /**
+ * 设置窗口冻结,之前冻结的窗口会被覆盖,如果colSplit和rowSplit为0表示取消冻结
+ *
+ * @param colSplit 冻结的列及列数,2表示前两列
+ * @param rowSplit 冻结的行及行数,2表示前两行
+ * @return this
+ * @since 5.2.5
+ */
+ public ExcelWriter setFreezePane(int colSplit, int rowSplit){
+ getSheet().createFreezePane(colSplit, rowSplit);
+ return this;
+ }
+
/**
* 设置列宽(单位为一个字符的宽度,例如传入width为10,表示10个字符的宽度)
*
diff --git a/hutool-poi/src/test/java/cn/hutool/poi/excel/test/ExcelWriteTest.java b/hutool-poi/src/test/java/cn/hutool/poi/excel/test/ExcelWriteTest.java
index 9bca94c59..abc3edb28 100644
--- a/hutool-poi/src/test/java/cn/hutool/poi/excel/test/ExcelWriteTest.java
+++ b/hutool-poi/src/test/java/cn/hutool/poi/excel/test/ExcelWriteTest.java
@@ -90,6 +90,8 @@ public class ExcelWriteTest {
// 一次性写出内容,使用默认样式
writer.write(rows);
writer.autoSizeColumn(0, true);
+ //冻结前两行
+ writer.setFreezePane(0, 2);
// 关闭writer,释放内存
writer.close();
}
From 174d80e865e4452db32df56bd56b171114b9c24c Mon Sep 17 00:00:00 2001
From: Looly
Date: Mon, 30 Mar 2020 19:36:19 +0800
Subject: [PATCH 009/157] add methods
---
CHANGELOG.md | 1 +
.../cn/hutool/core/collection/CollUtil.java | 24 +++++++++
.../cn/hutool/core/collection/ListUtil.java | 25 ++++++++++
.../java/cn/hutool/core/map/TableMap.java | 50 +++++++++++++++++--
.../hutool/core/collection/ListUtilTest.java | 9 ++++
5 files changed, 104 insertions(+), 5 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9651cee1e..73dac269f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,7 @@
### 新特性
* 【extra 】 JschUtil增加execByShell方法(issue#I1CYES@Gitee)
* 【core 】 StrUtil增加subBetweenAll方法,Console增加where和lineNumber方法(issue#812@Github)
+* 【core 】 TableMap增加getKeys和getValues方法
### Bug修复
* 【extra 】 修复SpringUtil使用devtools重启报错问题
diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java b/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java
index 3cb0ee020..186caf969 100644
--- a/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java
+++ b/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java
@@ -1310,6 +1310,30 @@ public class CollUtil {
return count;
}
+ /**
+ * 获取匹配规则定义中匹配到元素的所有位置
+ * 此方法对于某些无序集合的位置信息,以转换为数组后的位置为准。
+ *
+ * @param 元素类型
+ * @param collection 集合
+ * @param matcher 匹配器,为空则全部匹配
+ * @return 位置数组
+ * @since 5.2.5
+ */
+ public static int[] indexOfAll(Collection collection, Matcher matcher){
+ final List indexList = new ArrayList<>();
+ if (null != collection) {
+ int index = 0;
+ for (T t : collection) {
+ if (null == matcher || matcher.match(t)) {
+ indexList.add(index);
+ }
+ index++;
+ }
+ }
+ return Convert.convert(int[].class, indexList);
+ }
+
// ---------------------------------------------------------------------- isEmpty
/**
diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/ListUtil.java b/hutool-core/src/main/java/cn/hutool/core/collection/ListUtil.java
index d45d2c60d..5579dcec9 100644
--- a/hutool-core/src/main/java/cn/hutool/core/collection/ListUtil.java
+++ b/hutool-core/src/main/java/cn/hutool/core/collection/ListUtil.java
@@ -2,7 +2,9 @@ package cn.hutool.core.collection;
import cn.hutool.core.comparator.PinyinComparator;
import cn.hutool.core.comparator.PropertyComparator;
+import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Editor;
+import cn.hutool.core.lang.Matcher;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.PageUtil;
@@ -419,4 +421,27 @@ public class ListUtil {
}
return list2;
}
+
+ /**
+ * 获取匹配规则定义中匹配到元素的所有位置
+ *
+ * @param 元素类型
+ * @param list 列表
+ * @param matcher 匹配器,为空则全部匹配
+ * @return 位置数组
+ * @since 5.2.5
+ */
+ public static int[] indexOfAll(List list, Matcher matcher){
+ final List indexList = new ArrayList<>();
+ if (null != list) {
+ int index = 0;
+ for (T t : list) {
+ if (null == matcher || matcher.match(t)) {
+ indexList.add(index);
+ }
+ index++;
+ }
+ }
+ return Convert.convert(int[].class, indexList);
+ }
}
diff --git a/hutool-core/src/main/java/cn/hutool/core/map/TableMap.java b/hutool-core/src/main/java/cn/hutool/core/map/TableMap.java
index 7b4be3645..b80ec2ed0 100644
--- a/hutool-core/src/main/java/cn/hutool/core/map/TableMap.java
+++ b/hutool-core/src/main/java/cn/hutool/core/map/TableMap.java
@@ -1,13 +1,22 @@
package cn.hutool.core.map;
-import java.io.Serializable;
-import java.util.*;
-
import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.ObjectUtil;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
/**
- * 无重复键的Map
+ * 可重复键的Map
*
* @author looly
*
@@ -73,6 +82,34 @@ public class TableMap implements Map, Serializable {
return null;
}
+ /**
+ * 获取指定key对应的所有值
+ *
+ * @param key 键
+ * @return 值列表
+ * @since 5.2.5
+ */
+ public List getValues(K key){
+ return CollUtil.getAny(
+ this.values,
+ ListUtil.indexOfAll(this.keys, (ele)-> ObjectUtil.equal(ele, key))
+ );
+ }
+
+ /**
+ * 获取指定value对应的所有key
+ *
+ * @param value 值
+ * @return 值列表
+ * @since 5.2.5
+ */
+ public List getKeys(V value){
+ return CollUtil.getAny(
+ this.keys,
+ ListUtil.indexOfAll(this.values, (ele)-> ObjectUtil.equal(ele, value))
+ );
+ }
+
@Override
public V put(K key, V value) {
keys.add(key);
@@ -106,16 +143,19 @@ public class TableMap implements Map, Serializable {
values.clear();
}
+ @SuppressWarnings("NullableProblems")
@Override
public Set keySet() {
return new HashSet<>(keys);
}
+ @SuppressWarnings("NullableProblems")
@Override
public Collection values() {
- return new HashSet<>(values);
+ return Collections.unmodifiableList(this.values);
}
+ @SuppressWarnings("NullableProblems")
@Override
public Set> entrySet() {
HashSet> hashSet = new HashSet<>();
diff --git a/hutool-core/src/test/java/cn/hutool/core/collection/ListUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/collection/ListUtilTest.java
index 36ce84875..61aa2855c 100644
--- a/hutool-core/src/test/java/cn/hutool/core/collection/ListUtilTest.java
+++ b/hutool-core/src/test/java/cn/hutool/core/collection/ListUtilTest.java
@@ -15,4 +15,13 @@ public class ListUtilTest {
Assert.assertEquals("edit2", filter.get(1));
Assert.assertEquals("edit3", filter.get(2));
}
+
+ @Test
+ public void indexOfAll() {
+ List a = ListUtil.toLinkedList("1", "2", "3", "4", "3", "2", "1");
+ final int[] indexArray = ListUtil.indexOfAll(a, "2"::equals);
+ Assert.assertArrayEquals(new int[]{1,5}, indexArray);
+ final int[] indexArray2 = ListUtil.indexOfAll(a, "1"::equals);
+ Assert.assertArrayEquals(new int[]{0,6}, indexArray2);
+ }
}
From ccccbf67aa24ffe4d17e9606b388d3df31484630 Mon Sep 17 00:00:00 2001
From: Looly
Date: Tue, 31 Mar 2020 11:06:39 +0800
Subject: [PATCH 010/157] fix code and add sh
---
CHANGELOG.md | 3 +-
bin/cobertura.sh | 3 +
bin/simple_install.sh | 3 +
.../main/java/cn/hutool/json/JSONArray.java | 17 +++-
.../main/java/cn/hutool/json/JSONObject.java | 31 +++++--
.../java/cn/hutool/json/JSONObjectIter.java | 12 +--
.../java/cn/hutool/json/JSONObjectTest.java | 90 ++++++++++---------
.../java/cn/hutool/json/test/bean/UserA.java | 32 +------
8 files changed, 101 insertions(+), 90 deletions(-)
create mode 100644 bin/cobertura.sh
create mode 100644 bin/simple_install.sh
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 73dac269f..180f1db1e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,12 +3,13 @@
-------------------------------------------------------------------------------------------------------------
-## 5.2.6 (2020-03-26)
+## 5.2.6 (2020-04-01)
### 新特性
* 【extra 】 JschUtil增加execByShell方法(issue#I1CYES@Gitee)
* 【core 】 StrUtil增加subBetweenAll方法,Console增加where和lineNumber方法(issue#812@Github)
* 【core 】 TableMap增加getKeys和getValues方法
+* 【json 】 JSONObject和JSONArray增加set方法,标识put弃用
### Bug修复
* 【extra 】 修复SpringUtil使用devtools重启报错问题
diff --git a/bin/cobertura.sh b/bin/cobertura.sh
new file mode 100644
index 000000000..1611b93f0
--- /dev/null
+++ b/bin/cobertura.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+exec mvn -T 1 cobertura:cobertura
diff --git a/bin/simple_install.sh b/bin/simple_install.sh
new file mode 100644
index 000000000..d3b9281e2
--- /dev/null
+++ b/bin/simple_install.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+exec mvn -T 1C clean install -Dmaven.test.skip=true -Dmaven.javadoc.skip=true
diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONArray.java b/hutool-json/src/main/java/cn/hutool/json/JSONArray.java
index bd8bd5d85..5a17702f7 100644
--- a/hutool-json/src/main/java/cn/hutool/json/JSONArray.java
+++ b/hutool-json/src/main/java/cn/hutool/json/JSONArray.java
@@ -252,8 +252,21 @@ public class JSONArray implements JSON, JSONGetter, List