Merge remote-tracking branch 'upstream/v5-dev' into v5-dev

This commit is contained in:
totalo 2021-03-10 14:53:49 +08:00
commit bb5b524418
201 changed files with 1959 additions and 1047 deletions

View File

@ -3,17 +3,45 @@
-------------------------------------------------------------------------------------------------------------
# 5.5.9 (2021-02-18)
# 5.6.0 (2021-03-10)
### 新特性
* 【poi 】 重要不再兼容POI-3.x增加兼容POI-5.xissue#I35J6B@Gitee
* 【core 】 FileTypeUtil使用长匹配优先pr#1457@Github
* 【core 】 IterUtil和CollUtil增加isEqualList方法issue#I3A3PY@Gitee
* 【crypto 】 增加PBKDF2issue#1416@Github
* 【core 】 增加FuncKeyMapissue#1402@Github
* 【core 】 增加StrMatcherissue#1379@Github
* 【core 】 NumberUtil增加factorial针对BigInterger方法issue#1379@Github
* 【core 】 TreeNode增加equals方法issue#1467@Github
### Bug修复
* 【socket 】 修复Client创建失败资源未释放问题。
* 【core 】 修复DataSizeUtil中EB单位错误问题issue#I39O7I@Gitee
-------------------------------------------------------------------------------------------------------------
# 5.5.9 (2021-02-26)
### 新特性
* 【crypto 】 PemUtil.readPemKey支持ECpr#1366@Github
* 【extra 】 Ftp等cd方法增加同步issue#1397@Github
* 【core 】 StrUtil增加endWithAnyIgnoreCaseissue#I37I0B@Gitee
* 【crypto 】 Sm2增加getD和getQ方法issue#I37Z4C@Gitee
* 【cache 】 AbstractCache增加keySet方法issue#I37Z4C@Gitee
* 【core 】 NumberWordFormatter增加formatSimple方法pr#1436@Github
* 【crypto 】 增加读取openSSL生成的sm2私钥
* 【crypto 】 增加众多方法SM2兼容各类密钥格式issue#I37Z75@Gitee
### Bug修复
* 【json 】 JSONUtil.isJson方法改变trim策略解决特殊空白符导致判断失败问题
* 【json 】 修复SQLEXception导致的栈溢出issue#1399@Github
* 【extra 】 修复Ftp中异常参数没有传入问题issue#1397@Github
* 【crypto 】 修复Sm2使用D构造空指针问题issue#I37Z4C@Gitee
* 【poi 】 修复ExcelPicUtil中图表报错问题issue#I38857@Gitee
* 【core 】 修复ListUtil.page方法返回空列表无法编辑问题issue#1415@Github
* 【core 】 修复ListUtil.sub中step不通结果不一致问题issue#1409@Github
* 【db 】 修复Condition转换参数值时未转换数字异常issue#I38LTM@Gitee
-------------------------------------------------------------------------------------------------------------

View File

@ -125,19 +125,19 @@ Each module can be introduced individually, or all modules can be introduced by
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.5.9</version>
<version>5.6.0</version>
</dependency>
```
### Gradle
```
compile 'cn.hutool:hutool-all:5.5.9'
compile 'cn.hutool:hutool-all:5.6.0'
```
## Download
- [Maven1](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.5.9/)
- [Maven2](http://repo2.maven.org/maven2/cn/hutool/hutool-all/5.5.9/)
- [Maven1](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.6.0/)
- [Maven2](http://repo2.maven.org/maven2/cn/hutool/hutool-all/5.6.0/)
> note:
> Hutool 5.x supports JDK8+ and is not tested on Android platforms, and cannot guarantee that all tool classes or tool methods are available.

View File

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

View File

@ -1 +1 @@
5.5.9
5.6.0

View File

@ -1 +1 @@
var version = '5.5.9'
var version = '5.6.0'

View File

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

View File

@ -1,11 +1,11 @@
/**
* Hutool是Hu + tool的自造词前者致敬我的前任公司后者为工具之意谐音糊涂寓意追求万事都作糊涂观无所谓失无所谓得的境界
*
*
* <p>
* Hutool是一个Java工具包也只是一个工具包它帮助我们简化每一行代码减少每一个方法让Java语言也可以甜甜的<br>
* Hutool最初是我项目中util包的一个整理后来慢慢积累并加入更多非业务相关功能并广泛学习其它开源项目精髓经过自己整理修改最终形成丰富的开源工具集
* </p>
*
*
* @author looly
*
*/

View File

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

View File

@ -13,10 +13,10 @@ import cn.hutool.core.util.ClassUtil;
*
*/
public final class ProxyUtil {
/**
* 使用切面代理对象
*
*
* @param <T> 切面对象类型
* @param target 目标对象
* @param aspectClass 切面对象类
@ -25,10 +25,10 @@ public final class ProxyUtil {
public static <T> T proxy(T target, Class<? extends Aspect> aspectClass){
return ProxyFactory.createProxy(target, aspectClass);
}
/**
* 使用切面代理对象
*
*
* @param <T> 被代理对象类型
* @param target 被代理对象
* @param aspect 切面对象
@ -47,8 +47,8 @@ public final class ProxyUtil {
* 3调用$Proxy0的$Proxy0(InvocationHandler)构造函数 创建$Proxy0的对象并且用interfaces参数遍历其所有接口的方法这些实现方法的实现本质上是通过反射调用被代理对象的方法<br>
* 4将$Proxy0的实例返回给客户端 <br>
* 5当调用代理类的相应方法时相当于调用 {@link InvocationHandler#invoke(Object, java.lang.reflect.Method, Object[])} 方法
*
*
*
*
* @param <T> 被代理对象类型
* @param classloader 被代理类对应的ClassLoader
* @param invocationHandler {@link InvocationHandler} 被代理类通过实现此接口提供动态代理功能
@ -59,10 +59,10 @@ public final class ProxyUtil {
public static <T> T newProxyInstance(ClassLoader classloader, InvocationHandler invocationHandler, Class<?>... interfaces) {
return (T) Proxy.newProxyInstance(classloader, interfaces, invocationHandler);
}
/**
* 创建动态代理对象
*
*
* @param <T> 被代理对象类型
* @param invocationHandler {@link InvocationHandler} 被代理类通过实现此接口提供动态代理功能
* @param interfaces 代理类中需要实现的被代理类的接口方法

View File

@ -1,6 +1,6 @@
/**
* 切面实现提供一些基本的切面实现
*
*
* @author looly
*
*/

View File

@ -1,6 +1,6 @@
/**
* 代理拦截器实现
*
*
* @author looly
*
*/

View File

@ -1,6 +1,6 @@
/**
* JDK动态代理封装提供非IOC下的切面支持
*
*
* @author looly
*
*/

View File

@ -6,7 +6,7 @@ import net.sf.cglib.proxy.Enhancer;
/**
* 基于Cglib的切面代理工厂
*
*
* @author looly
*
*/

View File

@ -6,7 +6,7 @@ import org.springframework.cglib.proxy.Enhancer;
/**
* 基于Spring-cglib的切面代理工厂
*
*
* @author looly
*
*/

View File

@ -1,6 +1,6 @@
/**
* 代理实现
*
*
* @author looly
*
*/

View File

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

View File

@ -16,7 +16,7 @@ import java.util.BitSet;
*/
public class BitSetBloomFilter implements BloomFilter{
private static final long serialVersionUID = 1L;
private final BitSet bitSet;
private final int bitSetSize;
private final int addedElements;
@ -24,7 +24,7 @@ public class BitSetBloomFilter implements BloomFilter{
/**
* 构造一个布隆过滤器过滤器的容量为c * n 个bit.
*
*
* @param c 当前过滤器预先开辟的最大包含记录,通常要比预计存入的记录多一倍.
* @param n 当前过滤器预计所要包含的记录.
* @param k 哈希函数的个数等同每条记录要占用的bit数.
@ -38,7 +38,7 @@ public class BitSetBloomFilter implements BloomFilter{
/**
* 通过文件初始化过滤器.
*
*
* @param path 文件路径
* @param charset 字符集
* @throws IOException IO异常
@ -58,7 +58,7 @@ public class BitSetBloomFilter implements BloomFilter{
IoUtil.close(reader);
}
}
@Override
public boolean add(String str) {
if (contains(str)) {
@ -72,7 +72,7 @@ public class BitSetBloomFilter implements BloomFilter{
}
return true;
}
/**
* 判定是否包含指定字符串
* @param str 字符串
@ -89,7 +89,7 @@ public class BitSetBloomFilter implements BloomFilter{
}
return true;
}
/**
* @return 得到当前过滤器的错误率.
*/
@ -100,7 +100,7 @@ public class BitSetBloomFilter implements BloomFilter{
/**
* 将字符串的字节表示进行多哈希编码.
*
*
* @param str 待添加进过滤器的字符串字节表示.
* @param hashNumber 要经过的哈希个数.
* @return 各个哈希的结果数组.
@ -109,7 +109,7 @@ public class BitSetBloomFilter implements BloomFilter{
int[] result = new int[hashNumber];
for(int i = 0; i < hashNumber; i++) {
result[i] = hash(str, i);
}
return result;
}

View File

@ -12,7 +12,7 @@ import java.io.Serializable;
public interface BloomFilter extends Serializable{
/**
*
*
* @param str 字符串
* @return 判断一个字符串是否bitMap中存在
*/
@ -21,7 +21,7 @@ public interface BloomFilter extends Serializable{
/**
* 在boolean的bitMap中增加一个字符串<br>
* 如果存在就返回<code>false</code> .如果不存在.先增加这个字符串.再返回<code>true</code>
*
*
* @param str 字符串
* @return 是否加入成功如果存在就返回<code>false</code> .如果不存在返回<code>true</code>
*/

View File

@ -2,7 +2,7 @@ package cn.hutool.bloomfilter;
/**
* 布隆过滤器工具
*
*
* @author looly
* @since 4.1.5
*/
@ -10,7 +10,7 @@ public class BloomFilterUtil {
/**
* 创建一个BitSet实现的布隆过滤器过滤器的容量为c * n 个bit.
*
*
* @param c 当前过滤器预先开辟的最大包含记录,通常要比预计存入的记录多一倍.
* @param n 当前过滤器预计所要包含的记录.
* @param k 哈希函数的个数等同每条记录要占用的bit数.
@ -22,7 +22,7 @@ public class BloomFilterUtil {
/**
* 创建BitMap实现的布隆过滤器
*
*
* @param m BitMap的大小
* @return BitMapBloomFilter
*/

View File

@ -2,7 +2,7 @@ package cn.hutool.bloomfilter.bitMap;
/**
* BitMap接口用于将某个int或long值映射到一个数组中从而判定某个值是否存在
*
*
* @author looly
*
*/
@ -13,14 +13,14 @@ public interface BitMap{
/**
* 加入值
*
*
* @param i
*/
void add(long i);
/**
* 检查是否包含值
*
*
* @param i
* @return 是否包含
*/
@ -28,7 +28,7 @@ public interface BitMap{
/**
* 移除值
*
*
* @param i
*/
void remove(long i);

View File

@ -4,7 +4,7 @@ import java.io.Serializable;
/**
* 过滤器BitMap在32位机器上.这个类能发生更好的效果.一般情况下建议使用此类
*
*
* @author loolly
*
*/
@ -22,7 +22,7 @@ public class IntMap implements BitMap, Serializable {
/**
* 构造
*
*
* @param size 容量
*/
public IntMap(int size) {

View File

@ -4,7 +4,7 @@ import java.io.Serializable;
/**
* 过滤器BitMap在64位机器上.这个类能发生更好的效果.一般机器不建议使用
*
*
* @author loolly
*
*/
@ -22,7 +22,7 @@ public class LongMap implements BitMap, Serializable {
/**
* 构造
*
*
* @param size 容量
*/
public LongMap(int size) {

View File

@ -1,6 +1,6 @@
/**
* BitMap实现
*
*
* @author looly
*
*/

View File

@ -7,7 +7,7 @@ import cn.hutool.bloomfilter.bitMap.LongMap;
/**
* 抽象Bloom过滤器
*
*
* @author loolly
*
*/
@ -20,7 +20,7 @@ public abstract class AbstractFilter implements BloomFilter {
/**
* 构造
*
*
* @param maxValue 最大值
* @param machineNum 机器位数
*/
@ -30,7 +30,7 @@ public abstract class AbstractFilter implements BloomFilter {
/**
* 构造32位
*
*
* @param maxValue 最大值
*/
public AbstractFilter(long maxValue) {
@ -39,7 +39,7 @@ public abstract class AbstractFilter implements BloomFilter {
/**
* 初始化
*
*
* @param maxValue 最大值
* @param machineNum 机器位数
*/
@ -75,7 +75,7 @@ public abstract class AbstractFilter implements BloomFilter {
/**
* 自定义Hash方法
*
*
* @param str 字符串
* @return HashCode
*/

View File

@ -8,11 +8,11 @@ public class ELFFilter extends AbstractFilter {
public ELFFilter(long maxValue, int machineNumber) {
super(maxValue, machineNumber);
}
public ELFFilter(long maxValue) {
super(maxValue);
}
@Override
public long hash(String str) {
return HashUtil.elfHash(str) % size;

View File

@ -7,11 +7,11 @@ public class HfFilter extends AbstractFilter {
public HfFilter(long maxValue, int machineNum) {
super(maxValue, machineNum);
}
public HfFilter(long maxValue) {
super(maxValue);
}
@Override
public long hash(String str) {
int length = str.length() ;

View File

@ -19,11 +19,11 @@ public class JSFilter extends AbstractFilter {
for (int i = 0; i < str.length(); i++) {
hash ^= ((hash << 5) + str.charAt(i) + (hash >> 2));
}
if(hash<0) {
hash*=-1 ;
}
return hash % size;
}

View File

@ -1,6 +1,6 @@
/**
* 各种Hash算法的过滤器实现
*
*
* @author looly
*
*/

View File

@ -1,6 +1,6 @@
/**
* 布隆过滤提供一些Hash算法的布隆过滤
*
*
* @author looly
*
*/

View File

@ -8,14 +8,14 @@ import cn.hutool.bloomfilter.bitMap.IntMap;
import cn.hutool.bloomfilter.bitMap.LongMap;
public class BitMapBloomFilterTest {
@Test
public void filterTest() {
BitMapBloomFilter filter = new BitMapBloomFilter(10);
filter.add("123");
filter.add("abc");
filter.add("ddd");
Assert.assertTrue(filter.contains("abc"));
Assert.assertTrue(filter.contains("ddd"));
Assert.assertTrue(filter.contains("123"));

View File

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

View File

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

View File

@ -13,10 +13,10 @@ import cn.hutool.cache.impl.WeakCache;
*@since 3.0.1
*/
public class CacheUtil {
/**
* 创建FIFO(first in first out) 先进先出缓存.
*
*
* @param <K> Key类型
* @param <V> Value类型
* @param capacity 容量
@ -26,10 +26,10 @@ public class CacheUtil {
public static <K, V> FIFOCache<K, V> newFIFOCache(int capacity, long timeout){
return new FIFOCache<>(capacity, timeout);
}
/**
* 创建FIFO(first in first out) 先进先出缓存.
*
*
* @param <K> Key类型
* @param <V> Value类型
* @param capacity 容量
@ -38,10 +38,10 @@ public class CacheUtil {
public static <K, V> FIFOCache<K, V> newFIFOCache(int capacity){
return new FIFOCache<>(capacity);
}
/**
* 创建LFU(least frequently used) 最少使用率缓存.
*
*
* @param <K> Key类型
* @param <V> Value类型
* @param capacity 容量
@ -51,10 +51,10 @@ public class CacheUtil {
public static <K, V> LFUCache<K, V> newLFUCache(int capacity, long timeout){
return new LFUCache<>(capacity, timeout);
}
/**
* 创建LFU(least frequently used) 最少使用率缓存.
*
*
* @param <K> Key类型
* @param <V> Value类型
* @param capacity 容量
@ -63,11 +63,11 @@ public class CacheUtil {
public static <K, V> LFUCache<K, V> newLFUCache(int capacity){
return new LFUCache<>(capacity);
}
/**
* 创建LRU (least recently used)最近最久未使用缓存.
*
*
* @param <K> Key类型
* @param <V> Value类型
* @param capacity 容量
@ -77,10 +77,10 @@ public class CacheUtil {
public static <K, V> LRUCache<K, V> newLRUCache(int capacity, long timeout){
return new LRUCache<>(capacity, timeout);
}
/**
* 创建LRU (least recently used)最近最久未使用缓存.
*
*
* @param <K> Key类型
* @param <V> Value类型
* @param capacity 容量
@ -89,10 +89,10 @@ public class CacheUtil {
public static <K, V> LRUCache<K, V> newLRUCache(int capacity){
return new LRUCache<>(capacity);
}
/**
* 创建定时缓存.
*
*
* @param <K> Key类型
* @param <V> Value类型
* @param timeout 过期时长单位毫秒
@ -101,10 +101,10 @@ public class CacheUtil {
public static <K, V> TimedCache<K, V> newTimedCache(long timeout){
return new TimedCache<>(timeout);
}
/**
* 创建弱引用缓存.
*
*
* @param <K> Key类型
* @param <V> Value类型
* @param timeout 过期时长单位毫秒
@ -114,10 +114,10 @@ public class CacheUtil {
public static <K, V> WeakCache<K, V> newWeakCache(long timeout){
return new WeakCache<>(timeout);
}
/**
* 创建无缓存实现.
*
*
* @param <K> Key类型
* @param <V> Value类型
* @return {@link NoCache}

View File

@ -23,7 +23,7 @@ public abstract class AbstractFileCache implements Serializable{
protected final long timeout;
/** 缓存实现 */
protected final Cache<File, byte[]> cache;
/** 已使用缓存空间 */
protected int usedSize;
@ -122,7 +122,7 @@ public abstract class AbstractFileCache implements Serializable{
return bytes;
}
// ---------------------------------------------------------------- protected method start
/**
* 初始化实现文件缓存的缓存对象

View File

@ -12,7 +12,7 @@ import cn.hutool.cache.impl.LFUCache;
*/
public class LFUFileCache extends AbstractFileCache{
private static final long serialVersionUID = 1L;
/**
* 构造<br>
* 最大文件大小为缓存容量的一半<br>

View File

@ -12,7 +12,7 @@ import cn.hutool.cache.impl.LRUCache;
*/
public class LRUFileCache extends AbstractFileCache{
private static final long serialVersionUID = 1L;
/**
* 构造<br>
* 最大文件大小为缓存容量的一半<br>

View File

@ -1,6 +1,6 @@
/**
* 提供针对文件的缓存实现
*
*
* @author looly
*
*/

View File

@ -7,6 +7,7 @@ import cn.hutool.core.lang.func.Func0;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Lock;
@ -307,11 +308,22 @@ public abstract class AbstractCache<K, V> implements Cache<K, V> {
* @return this
* @since 5.5.2
*/
@Override
public AbstractCache<K, V> setListener(CacheListener<K, V> listener) {
this.listener = listener;
return this;
}
/**
* 返回所有键
*
* @return 所有键
* @since 5.5.9
*/
public Set<K> keySet(){
return this.cacheMap.keySet();
}
/**
* 对象移除回调默认无动作<br>
* 子类可重写此方法用于监听移除事件如果重写listener将无效

View File

@ -12,20 +12,20 @@ import java.util.concurrent.atomic.AtomicLong;
*/
public class CacheObj<K, V> implements Serializable{
private static final long serialVersionUID = 1L;
protected final K key;
protected final V obj;
/** 上次访问时间 */
private volatile long lastAccess;
/** 访问次数 */
protected AtomicLong accessCount = new AtomicLong();
/** 对象存活时长0表示永久存活*/
private final long ttl;
/**
* 构造
*
*
* @param key
* @param obj
* @param ttl 超时时长
@ -36,10 +36,10 @@ public class CacheObj<K, V> implements Serializable{
this.ttl = ttl;
this.lastAccess = System.currentTimeMillis();
}
/**
* 判断是否过期
*
*
* @return 是否过期
*/
boolean isExpired() {
@ -49,10 +49,10 @@ public class CacheObj<K, V> implements Serializable{
}
return false;
}
/**
* 获取值
*
*
* @param isUpdateLastAccess 是否更新最后访问时间
* @return 获得对象
* @since 4.0.10
@ -64,7 +64,7 @@ public class CacheObj<K, V> implements Serializable{
accessCount.getAndIncrement();
return this.obj;
}
/**
* 获取键
* @return
@ -73,7 +73,7 @@ public class CacheObj<K, V> implements Serializable{
public K getKey() {
return this.key;
}
/**
* 获取值
* @return
@ -82,7 +82,7 @@ public class CacheObj<K, V> implements Serializable{
public V getValue() {
return this.obj;
}
@Override
public String toString() {
return "CacheObj [key=" + key + ", obj=" + obj + ", lastAccess=" + lastAccess + ", accessCount=" + accessCount + ", ttl=" + ttl + "]";

View File

@ -6,7 +6,7 @@ import java.util.NoSuchElementException;
/**
* {@link cn.hutool.cache.impl.AbstractCache} 的CacheObj迭代器.
*
*
* @author looly
*
* @param <K> 键类型
@ -21,7 +21,7 @@ public class CacheObjIterator<K, V> implements Iterator<CacheObj<K, V>>, Seriali
/**
* 构造
*
*
* @param iterator {@link Iterator}
*/
CacheObjIterator(Iterator<CacheObj<K, V>> iterator) {

View File

@ -48,7 +48,7 @@ public class LRUCache<K, V> extends AbstractCache<K, V> {
// ---------------------------------------------------------------- prune
/**
* 只清理超时对象LRU的实现会交给<code>LinkedHashMap</code>
* 只清理超时对象LRU的实现会交给{@code LinkedHashMap}
*/
@Override
protected int pruneCache() {

View File

@ -7,7 +7,7 @@ import java.util.Iterator;
/**
* 无缓存实现用于快速关闭缓存
*
*
* @param <K> 键类型
* @param <V> 值类型
* @author Looly,jodd
@ -49,7 +49,7 @@ public class NoCache<K, V> implements Cache<K, V> {
public V get(K key, boolean isUpdateLastAccess) {
return null;
}
@Override
public V get(K key, Func0<V> supplier) {
return get(key, true, supplier);
@ -78,7 +78,7 @@ public class NoCache<K, V> implements Cache<K, V> {
}
};
}
@Override
public Iterator<CacheObj<K, V>> cacheObjIterator() {
return null;

View File

@ -1,6 +1,6 @@
/**
* 提供各种缓存实现
*
*
* @author looly
*
*/

View File

@ -1,6 +1,6 @@
/**
* 提供简易的缓存实现此模块参考了jodd工具中的Cache模块
*
*
* @author looly
*
*/

View File

@ -14,7 +14,7 @@ import org.junit.Test;
*
*/
public class CacheTest {
@Test
public void fifoCacheTest(){
Cache<String,String> fifoCache = CacheUtil.newFIFOCache(3);
@ -28,22 +28,22 @@ public class CacheTest {
fifoCache.put("key2", "value2", DateUnit.SECOND.getMillis() * 3);
fifoCache.put("key3", "value3", DateUnit.SECOND.getMillis() * 3);
fifoCache.put("key4", "value4", DateUnit.SECOND.getMillis() * 3);
//由于缓存容量只有3当加入第四个元素的时候根据FIFO规则最先放入的对象将被移除
String value1 = fifoCache.get("key1");
Assert.assertNull(value1);
}
@Test
public void lfuCacheTest(){
Cache<String, String> lfuCache = CacheUtil.newLFUCache(3);
lfuCache.put("key1", "value1", DateUnit.SECOND.getMillis() * 3);
//使用次数+1
lfuCache.get("key1");
lfuCache.get("key1");
lfuCache.put("key2", "value2", DateUnit.SECOND.getMillis() * 3);
lfuCache.put("key3", "value3", DateUnit.SECOND.getMillis() * 3);
lfuCache.put("key4", "value4", DateUnit.SECOND.getMillis() * 3);
//由于缓存容量只有3当加入第四个元素的时候根据LFU规则最少使用的将被移除2,3被移除
String value1 = lfuCache.get("key1");
String value2 = lfuCache.get("key2");
@ -52,7 +52,7 @@ public class CacheTest {
Assert.assertNull(value2);
Assert.assertNull(value3);
}
@Test
public void lruCacheTest(){
Cache<String, String> lruCache = CacheUtil.newLRUCache(3);
@ -71,7 +71,7 @@ public class CacheTest {
String value2 = lruCache.get("key2");
Assert.assertNull(value2);
}
@Test
public void timedCacheTest(){
TimedCache<String, String> timedCache = CacheUtil.newTimedCache(4);
@ -80,29 +80,29 @@ public class CacheTest {
timedCache.put("key2", "value2", DateUnit.SECOND.getMillis() * 5);//5秒过期
timedCache.put("key3", "value3");//默认过期(4毫秒)
timedCache.put("key4", "value4", Long.MAX_VALUE);//永不过期
//启动定时任务每5毫秒秒检查一次过期
timedCache.schedulePrune(5);
//等待5毫秒
ThreadUtil.sleep(5);
//5毫秒后由于value2设置了5毫秒过期因此只有value2被保留下来
String value1 = timedCache.get("key1");
Assert.assertNull(value1);
String value2 = timedCache.get("key2");
Assert.assertEquals("value2", value2);
//5毫秒后由于设置了默认过期key3只被保留4毫秒因此为null
String value3 = timedCache.get("key3");
Assert.assertNull(value3);
String value3Supplier = timedCache.get("key3", () -> "Default supplier");
Assert.assertEquals("Default supplier", value3Supplier);
// 永不过期
String value4 = timedCache.get("key4");
Assert.assertEquals("value4", value4);
//取消定时清理
timedCache.cancelPruneSchedule();
}

View File

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

View File

@ -13,7 +13,7 @@ import java.util.concurrent.ThreadLocalRandom;
/**
* 圆圈干扰验证码
*
*
* @author looly
* @since 3.2.3
*
@ -23,7 +23,7 @@ public class CircleCaptcha extends AbstractCaptcha {
/**
* 构造
*
*
* @param width 图片宽
* @param height 图片高
*/
@ -33,7 +33,7 @@ public class CircleCaptcha extends AbstractCaptcha {
/**
* 构造
*
*
* @param width 图片宽
* @param height 图片高
* @param codeCount 字符个数
@ -44,7 +44,7 @@ public class CircleCaptcha extends AbstractCaptcha {
/**
* 构造
*
*
* @param width 图片宽
* @param height 图片高
* @param codeCount 字符个数
@ -71,7 +71,7 @@ public class CircleCaptcha extends AbstractCaptcha {
// ----------------------------------------------------------------------------------------------------- Private method start
/**
* 绘制字符串
*
*
* @param g {@link Graphics2D}画笔
* @param code 验证码
*/
@ -85,7 +85,7 @@ public class CircleCaptcha extends AbstractCaptcha {
/**
* 画随机干扰
*
*
* @param g {@link Graphics2D}
*/
private void drawInterfere(Graphics2D g) {

View File

@ -5,7 +5,7 @@ import java.io.Serializable;
/**
* 验证码接口提供验证码对象接口定义
*
*
* @author looly
*
*/
@ -18,14 +18,14 @@ public interface ICaptcha extends Serializable{
/**
* 获取验证码的文字内容
*
*
* @return 验证码文字内容
*/
String getCode();
/**
* 验证验证码是否正确建议忽略大小写
*
*
* @param userInputCode 用户输入的验证码
* @return 是否与生成的一直
*/
@ -33,7 +33,7 @@ public interface ICaptcha extends Serializable{
/**
* 将验证码写出到目标流中
*
*
* @param out 目标流
*/
void write(OutputStream out);

View File

@ -14,7 +14,7 @@ import cn.hutool.core.util.RandomUtil;
/**
* 使用干扰线方式生成的图形验证码
*
*
* @author looly
* @since 3.1.2
*/
@ -24,7 +24,7 @@ public class LineCaptcha extends AbstractCaptcha {
// -------------------------------------------------------------------- Constructor start
/**
* 构造默认5位验证码150条干扰线
*
*
* @param width 图片宽
* @param height 图片高
*/
@ -34,7 +34,7 @@ public class LineCaptcha extends AbstractCaptcha {
/**
* 构造
*
*
* @param width 图片宽
* @param height 图片高
* @param codeCount 字符个数
@ -63,7 +63,7 @@ public class LineCaptcha extends AbstractCaptcha {
// ----------------------------------------------------------------------------------------------------- Private method start
/**
* 绘制字符串
*
*
* @param g {@link Graphics}画笔
* @param code 验证码
*/
@ -77,7 +77,7 @@ public class LineCaptcha extends AbstractCaptcha {
/**
* 绘制干扰线
*
*
* @param g {@link Graphics2D}画笔
*/
private void drawInterfere(Graphics2D g) {

View File

@ -13,7 +13,7 @@ import java.awt.image.BufferedImage;
/**
* 扭曲干扰验证码
*
*
* @author looly
* @since 3.2.3
*
@ -23,7 +23,7 @@ public class ShearCaptcha extends AbstractCaptcha {
/**
* 构造
*
*
* @param width 图片宽
* @param height 图片高
*/
@ -33,7 +33,7 @@ public class ShearCaptcha extends AbstractCaptcha {
/**
* 构造
*
*
* @param width 图片宽
* @param height 图片高
* @param codeCount 字符个数
@ -44,7 +44,7 @@ public class ShearCaptcha extends AbstractCaptcha {
/**
* 构造
*
*
* @param width 图片宽
* @param height 图片高
* @param codeCount 字符个数
@ -73,7 +73,7 @@ public class ShearCaptcha extends AbstractCaptcha {
// ----------------------------------------------------------------------------------------------------- Private method start
/**
* 绘制字符串
*
*
* @param g {@link Graphics}画笔
* @param code 验证码
*/
@ -87,7 +87,7 @@ public class ShearCaptcha extends AbstractCaptcha {
/**
* 扭曲
*
*
* @param g {@link Graphics}
* @param w1 w1
* @param h1 h1
@ -100,7 +100,7 @@ public class ShearCaptcha extends AbstractCaptcha {
/**
* X坐标扭曲
*
*
* @param g {@link Graphics}
* @param w1
* @param h1
@ -125,7 +125,7 @@ public class ShearCaptcha extends AbstractCaptcha {
/**
* Y坐标扭曲
*
*
* @param g {@link Graphics}
* @param w1
* @param h1
@ -150,7 +150,7 @@ public class ShearCaptcha extends AbstractCaptcha {
/**
* 干扰线
*
*
* @param g {@link Graphics}
* @param x1 x1
* @param y1 y1

View File

@ -5,21 +5,21 @@ import cn.hutool.core.util.RandomUtil;
/**
* 随机字符验证码生成器<br>
* 可以通过传入的基础集合和长度随机生成验证码字符
*
*
* @author looly
* @since 4.1.2
*/
public abstract class AbstractGenerator implements CodeGenerator {
private static final long serialVersionUID = 8685744597154953479L;
/** 基础字符集合,用于随机获取字符串的字符集合 */
protected final String baseStr;
/** 验证码长度 */
protected final int length;
/**
* 构造使用字母+数字做为基础
*
*
* @param count 生成验证码长度
*/
public AbstractGenerator(int count) {
@ -28,7 +28,7 @@ public abstract class AbstractGenerator implements CodeGenerator {
/**
* 构造
*
*
* @param baseStr 基础字符集合用于随机获取字符串的字符集合
* @param length 生成验证码长度
*/
@ -39,7 +39,7 @@ public abstract class AbstractGenerator implements CodeGenerator {
/**
* 获取长度验证码
*
*
* @return 验证码长度
*/
public int getLength() {

View File

@ -4,7 +4,7 @@ import java.io.Serializable;
/**
* 验证码文字生成器
*
*
* @author looly
* @since 4.1.2
*/
@ -12,7 +12,7 @@ public interface CodeGenerator extends Serializable{
/**
* 生成验证码
*
*
* @return 验证码
*/
String generate();
@ -20,7 +20,7 @@ public interface CodeGenerator extends Serializable{
/**
* 验证用户输入的字符串是否与生成的验证码匹配<br>
* 用户通过实现此方法定义验证码匹配方式
*
*
* @param code 生成的随机验证码
* @param userInputCode 用户输入的验证码
* @return 是否验证通过

View File

@ -7,7 +7,7 @@ import cn.hutool.core.util.StrUtil;
/**
* 数字计算验证码生成器
*
*
* @author looly
* @since 4.1.2
*/
@ -28,7 +28,7 @@ public class MathGenerator implements CodeGenerator {
/**
* 构造
*
*
* @param numberLength 参与计算最大数字位数
*/
public MathGenerator(int numberLength) {
@ -75,7 +75,7 @@ public class MathGenerator implements CodeGenerator {
/**
* 根据长度获取参与计算数字最大值
*
*
* @return 最大值
*/
private int getLimit() {

View File

@ -6,7 +6,7 @@ import cn.hutool.core.util.StrUtil;
/**
* 随机字符验证码生成器<br>
* 可以通过传入的基础集合和长度随机生成验证码字符
*
*
* @author looly
* @since 4.1.2
*/
@ -15,7 +15,7 @@ public class RandomGenerator extends AbstractGenerator {
/**
* 构造使用字母+数字做为基础
*
*
* @param count 生成验证码长度
*/
public RandomGenerator(int count) {
@ -24,7 +24,7 @@ public class RandomGenerator extends AbstractGenerator {
/**
* 构造
*
*
* @param baseStr 基础字符集合用于随机获取字符串的字符集合
* @param length 生成验证码长度
*/
@ -36,7 +36,7 @@ public class RandomGenerator extends AbstractGenerator {
public String generate() {
return RandomUtil.randomString(this.baseStr, this.length);
}
@Override
public boolean verify(String code, String userInputCode) {
if (StrUtil.isNotBlank(userInputCode)) {

View File

@ -1,6 +1,6 @@
/**
* 验证码生成策略实现
*
*
* @author looly
* @since 4.1.2
*/

View File

@ -1,6 +1,6 @@
/**
* 图片验证码实现
*
*
* @author looly
*
*/

View File

@ -4,7 +4,7 @@ import org.junit.Ignore;
import org.junit.Test;
public class CaptchaUtilTest {
@Test
@Ignore
public void createTest() {

View File

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

View File

@ -43,7 +43,7 @@ public class CombinationAnnotationElement implements AnnotatedElement, Serializa
/**
* 构造
*
*
* @param element 需要解析注解的元素可以是ClassMethodFieldConstructorReflectPermission
*/
public CombinationAnnotationElement(AnnotatedElement element) {
@ -73,17 +73,17 @@ public class CombinationAnnotationElement implements AnnotatedElement, Serializa
final Collection<Annotation> annotations = this.declaredAnnotationMap.values();
return annotations.toArray(new Annotation[0]);
}
/**
* 初始化
*
*
* @param element 元素
*/
private void init(AnnotatedElement element) {
final Annotation[] declaredAnnotations = element.getDeclaredAnnotations();
this.declaredAnnotationMap = new HashMap<>();
parseDeclared(declaredAnnotations);
final Annotation[] annotations = element.getAnnotations();
if(Arrays.equals(declaredAnnotations, annotations)) {
this.annotationMap = this.declaredAnnotationMap;
@ -109,7 +109,7 @@ public class CombinationAnnotationElement implements AnnotatedElement, Serializa
}
}
}
/**
* 进行递归解析注解直到全部都是元注解为止
*

View File

@ -1,6 +1,6 @@
/**
* 注解包提供增强型注解和注解工具类
*
*
* @author looly
*
*/

View File

@ -11,9 +11,9 @@ import cn.hutool.core.lang.func.Func0;
*/
public enum BeanDescCache {
INSTANCE;
private final SimpleCache<Class<?>, BeanDesc> bdCache = new SimpleCache<>();
/**
* 获得属性名和{@link BeanDesc}Map映射
* @param beanClass Bean的类

View File

@ -13,19 +13,19 @@ public class BeanException extends RuntimeException{
public BeanException(Throwable e) {
super(ExceptionUtil.getMessage(e), e);
}
public BeanException(String message) {
super(message);
}
public BeanException(String messageTemplate, Object... params) {
super(StrUtil.format(messageTemplate, params));
}
public BeanException(String message, Throwable throwable) {
super(message, throwable);
}
public BeanException(Throwable throwable, String messageTemplate, Object... params) {
super(StrUtil.format(messageTemplate, params), throwable);
}

View File

@ -23,9 +23,9 @@ import java.util.Map;
* <li>.表达式可以获取Bean对象中的属性字段值或者Map中key对应的值</li>
* <li>[]表达式可以获取集合等对象中对应index的值</li>
* </ol>
*
*
* 表达式栗子
*
*
* <pre>
* persion
* persion.name
@ -33,7 +33,7 @@ import java.util.Map;
* person.friends[5].name
* ['person']['friends'][5]['name']
* </pre>
*
*
* @author Looly
* @since 4.0.6
*/
@ -54,9 +54,9 @@ public class BeanPath implements Serializable{
* <li>.表达式可以获取Bean对象中的属性字段值或者Map中key对应的值</li>
* <li>[]表达式可以获取集合等对象中对应index的值</li>
* </ol>
*
*
* 表达式栗子
*
*
* <pre>
* persion
* persion.name
@ -64,7 +64,7 @@ public class BeanPath implements Serializable{
* person.friends[5].name
* ['person']['friends'][5]['name']
* </pre>
*
*
* @param expression 表达式
* @return BeanPath
*/
@ -74,7 +74,7 @@ public class BeanPath implements Serializable{
/**
* 构造
*
*
* @param expression 表达式
*/
public BeanPath(String expression) {
@ -83,7 +83,7 @@ public class BeanPath implements Serializable{
/**
* 获取Bean中对应表达式的值
*
*
* @param bean Bean对象或Map或List等
* @return 如果对应值不存在则返回null
*/
@ -95,29 +95,29 @@ public class BeanPath implements Serializable{
* 设置表达式指定位置或filed对应的值<br>
* 若表达式指向一个List则设置其坐标对应位置的值若指向Map则put对应key的值Bean则设置字段的值<br>
* 注意
*
*
* <pre>
* 1. 如果为List如果下标不大于List长度则替换原有值否则追加值
* 2. 如果为数组如果下标不大于数组长度则替换原有值否则追加值
* </pre>
*
*
* @param bean BeanMap或List
* @param value
*/
public void set(Object bean, Object value) {
set(bean, this.patternParts, value);
}
/**
* 设置表达式指定位置或filed对应的值<br>
* 若表达式指向一个List则设置其坐标对应位置的值若指向Map则put对应key的值Bean则设置字段的值<br>
* 注意
*
*
* <pre>
* 1. 如果为List如果下标不大于List长度则替换原有值否则追加值
* 2. 如果为数组如果下标不大于数组长度则替换原有值否则追加值
* </pre>
*
*
* @param bean BeanMap或List
* @param patternParts 表达式块列表
* @param value
@ -135,7 +135,7 @@ public class BeanPath implements Serializable{
// ------------------------------------------------------------------------------------------------------------------------------------- Private method start
/**
* 获取Bean中对应表达式的值
*
*
* @param patternParts 表达式分段列表
* @param bean Bean对象或Map或List等
* @param ignoreLast 是否忽略最后一个值忽略最后一个值则用于set否则用于read
@ -215,7 +215,7 @@ public class BeanPath implements Serializable{
/**
* 初始化
*
*
* @param expression 表达式
*/
private void init(String expression) {
@ -277,7 +277,7 @@ public class BeanPath implements Serializable{
/**
* 对于非表达式去除单引号
*
*
* @param expression 表达式
* @return 表达式
*/

View File

@ -25,7 +25,7 @@ import java.util.Map;
* 3. Map Bean
* 4. Map Map
* </pre>
*
*
* @author looly
*
* @param <T> 目标对象类型
@ -33,7 +33,7 @@ import java.util.Map;
*/
public class BeanCopier<T> implements Copier<T>, Serializable {
private static final long serialVersionUID = 1L;
/** 源对象 */
private final Object source;
/** 目标对象 */
@ -45,7 +45,7 @@ public class BeanCopier<T> implements Copier<T>, Serializable {
/**
* 创建BeanCopier
*
*
* @param <T> 目标Bean类型
* @param source 来源对象可以是Bean或者Map
* @param dest 目标Bean对象
@ -58,7 +58,7 @@ public class BeanCopier<T> implements Copier<T>, Serializable {
/**
* 创建BeanCopier
*
*
* @param <T> 目标Bean类型
* @param source 来源对象可以是Bean或者Map
* @param dest 目标Bean对象
@ -72,7 +72,7 @@ public class BeanCopier<T> implements Copier<T>, Serializable {
/**
* 构造
*
*
* @param source 来源对象可以是Bean或者Map
* @param dest 目标Bean对象
* @param destType 目标的泛型类型用于标注有泛型参数的Bean对象
@ -115,7 +115,7 @@ public class BeanCopier<T> implements Copier<T>, Serializable {
/**
* Bean和Bean之间属性拷贝
*
*
* @param providerBean 来源Bean
* @param destBean 目标Bean
*/
@ -125,7 +125,7 @@ public class BeanCopier<T> implements Copier<T>, Serializable {
/**
* Map转Bean属性拷贝
*
*
* @param map Map
* @param bean Bean
*/
@ -138,7 +138,7 @@ public class BeanCopier<T> implements Copier<T>, Serializable {
/**
* Map转Map
*
*
* @param source 源Map
* @param dest 目标Map
*/
@ -151,7 +151,7 @@ public class BeanCopier<T> implements Copier<T>, Serializable {
/**
* 对象转Map
*
*
* @param bean bean对象
* @param targetMap 目标的Map
* @since 4.1.22
@ -201,7 +201,7 @@ public class BeanCopier<T> implements Copier<T>, Serializable {
/**
* 值提供器转Bean<br>
* 此方法通过遍历目标Bean的字段从ValueProvider查找对应值
*
*
* @param valueProvider 值提供器
* @param bean Bean
*/

View File

@ -6,17 +6,17 @@ import java.lang.reflect.Type;
* 值提供者用于提供Bean注入时参数对应值得抽象接口<br>
* 继承或匿名实例化此接口<br>
* 在Bean注入过程中Bean获得字段名通过外部方式根据这个字段名查找相应的字段值然后注入Bean<br>
*
*
* @author Looly
* @param <T> KEY类型一般情况下为 {@link String}
*
*/
public interface ValueProvider<T>{
/**
* 获取值<br>
* 返回值一般需要匹配被注入类型如果不匹配会调用默认转换 Convert#convert(Type, Object)实现转换
*
*
* @param key Bean对象中参数名
* @param valueType 被注入的值的类型
* @return 对应参数名的值
@ -26,7 +26,7 @@ public interface ValueProvider<T>{
/**
* 是否包含指定KEY如果不包含则忽略注入<br>
* 此接口方法单独需要实现的意义在于有些值提供者比如Mapkey是存在的但是value为null此时如果需要注入这个null需要根据此方法判断
*
*
* @param key Bean对象中参数名
* @return 是否包含指定KEY
*/

View File

@ -1,6 +1,6 @@
/**
* Bean拷贝实现包括拷贝选项等
*
*
* @author looly
*
*/

View File

@ -1,6 +1,6 @@
/**
* Bean值提供者方式封装
*
*
* @author looly
*
*/

View File

@ -1,6 +1,6 @@
/**
* Bean相关操作包括Bean信息描述Bean路径表达式动态BeanBean工具等
*
*
* @author looly
*
*/

View File

@ -4,7 +4,7 @@ import java.io.Serializable;
/**
* 建造者模式接口定义
*
*
* @param <T> 建造对象类型
* @author Looly
* @since 4.2.2
@ -12,7 +12,7 @@ import java.io.Serializable;
public interface Builder<T> extends Serializable{
/**
* 构建
*
*
* @return 被构建的对象
*/
T build();

View File

@ -8,7 +8,7 @@ import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.Comparator;
/**
/**
* 用于构建 {@link java.lang.Comparable#compareTo(Object)} 方法的辅助工具
*
* <p>
@ -33,7 +33,7 @@ import java.util.Comparator;
* }
* }
* </pre>
*
*
* 字段值按照顺序比较如果某个字段返回非0结果比较终止使用{@code toComparison()}返回结果后续比较忽略
*
* <p>
@ -52,7 +52,7 @@ import java.util.Comparator;
*/
public class CompareToBuilder implements Builder<Integer> {
private static final long serialVersionUID = 1L;
/** 当前比较状态 */
private int comparison;
@ -60,12 +60,11 @@ public class CompareToBuilder implements Builder<Integer> {
* 构造构造后调用append方法增加比较项然后调用{@link #toComparison()}获取结果
*/
public CompareToBuilder() {
super();
comparison = 0;
}
//-----------------------------------------------------------------------
/**
/**
* 通过反射比较两个Bean对象对象字段可以为private比较规则如下
*
* <ul>
@ -94,7 +93,7 @@ public class CompareToBuilder implements Builder<Integer> {
* <p>Compares two <code>Object</code>s via reflection.</p>
*
* <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
* is used to bypass normal access control checks. This will fail under a
* is used to bypass normal access control checks. This will fail under a
* security manager unless the appropriate permissions are set.</p>
*
* <ul>
@ -126,7 +125,7 @@ public class CompareToBuilder implements Builder<Integer> {
* <p>Compares two <code>Object</code>s via reflection.</p>
*
* <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
* is used to bypass normal access control checks. This will fail under a
* is used to bypass normal access control checks. This will fail under a
* security manager unless the appropriate permissions are set.</p>
*
* <ul>
@ -159,7 +158,7 @@ public class CompareToBuilder implements Builder<Integer> {
* <p>Compares two <code>Object</code>s via reflection.</p>
*
* <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
* is used to bypass normal access control checks. This will fail under a
* is used to bypass normal access control checks. This will fail under a
* security manager unless the appropriate permissions are set.</p>
*
* <ul>
@ -192,7 +191,7 @@ public class CompareToBuilder implements Builder<Integer> {
* <p>Compares two <code>Object</code>s via reflection.</p>
*
* <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
* is used to bypass normal access control checks. This will fail under a
* is used to bypass normal access control checks. This will fail under a
* security manager unless the appropriate permissions are set.</p>
*
* <ul>
@ -221,10 +220,10 @@ public class CompareToBuilder implements Builder<Integer> {
* @since 2.2 (2.0 as <code>reflectionCompare(Object, Object, boolean, Class)</code>)
*/
public static int reflectionCompare(
final Object lhs,
final Object rhs,
final boolean compareTransients,
final Class<?> reflectUpToClass,
final Object lhs,
final Object rhs,
final boolean compareTransients,
final Class<?> reflectUpToClass,
final String... excludeFields) {
if (lhs == rhs) {
@ -249,7 +248,7 @@ public class CompareToBuilder implements Builder<Integer> {
/**
* <p>Appends to <code>builder</code> the comparison of <code>lhs</code>
* to <code>rhs</code> using the fields defined in <code>clazz</code>.</p>
*
*
* @param lhs left-hand object
* @param rhs right-hand object
* @param clazz <code>Class</code> that defines fields to be compared
@ -264,7 +263,7 @@ public class CompareToBuilder implements Builder<Integer> {
final CompareToBuilder builder,
final boolean useTransients,
final String[] excludeFields) {
final Field[] fields = clazz.getDeclaredFields();
AccessibleObject.setAccessible(fields, true);
for (int i = 0; i < fields.length && builder.comparison == 0; i++) {
@ -300,7 +299,7 @@ public class CompareToBuilder implements Builder<Integer> {
comparison = superCompareTo;
return this;
}
//-----------------------------------------------------------------------
/**
* <p>Appends to the <code>builder</code> the comparison of
@ -312,7 +311,7 @@ public class CompareToBuilder implements Builder<Integer> {
* a <code>null</code> object is less than a non-<code>null</code> object</li>
* <li>Check the object contents</li>
* </ol>
*
*
* <p><code>lhs</code> must either be an array or implement {@link Comparable}.</p>
*
* @param lhs left-hand object
@ -441,7 +440,7 @@ public class CompareToBuilder implements Builder<Integer> {
/**
* Appends to the <code>builder</code> the comparison of
* two <code>short</code>s.
*
*
* @param lhs left-hand value
* @param rhs right-hand value
* @return this - used to chain append calls
@ -473,7 +472,7 @@ public class CompareToBuilder implements Builder<Integer> {
/**
* Appends to the <code>builder</code> the comparison of
* two <code>byte</code>s.
*
*
* @param lhs left-hand value
* @param rhs right-hand value
* @return this - used to chain append calls
@ -575,7 +574,7 @@ public class CompareToBuilder implements Builder<Integer> {
public CompareToBuilder append(final Object[] lhs, final Object[] rhs) {
return append(lhs, rhs, null);
}
/**
* <p>Appends to the <code>builder</code> the deep comparison of
* two <code>Object</code> arrays.</p>
@ -950,7 +949,7 @@ public class CompareToBuilder implements Builder<Integer> {
* the <code>builder</code> has judged the "left-hand" side
* as less than, greater than, or equal to the "right-hand"
* side.
*
*
* @return final comparison result
* @see #build()
*/
@ -963,7 +962,7 @@ public class CompareToBuilder implements Builder<Integer> {
* the <code>builder</code> has judged the "left-hand" side
* as less than, greater than, or equal to the "right-hand"
* side.
*
*
* @return final comparison result as an Integer
* @see #toComparison()
* @since 3.0

View File

@ -85,17 +85,17 @@ import cn.hutool.core.util.ArrayUtil;
*/
public class HashCodeBuilder implements Builder<Integer> {
private static final long serialVersionUID = 1L;
/**
* The default initial value to use in reflection hash code building.
*/
private static final int DEFAULT_INITIAL_VALUE = 17;
/**
* The default multipler value to use in reflection hash code building.
*/
private static final int DEFAULT_MULTIPLIER_VALUE = 37;
/**
* <p>
* A registry of objects used by reflection methods to detect cyclical object references and avoid infinite loops.
@ -103,7 +103,7 @@ public class HashCodeBuilder implements Builder<Integer> {
*
* @since 2.3
*/
private static final ThreadLocal<Set<IDKey>> REGISTRY = new ThreadLocal<Set<IDKey>>();
private static final ThreadLocal<Set<IDKey>> REGISTRY = new ThreadLocal<>();
/*
* NOTE: we cannot store the actual objects in a HashSet, as that would use the very hashCode()
@ -380,7 +380,7 @@ public class HashCodeBuilder implements Builder<Integer> {
* if the object is <code>null</code>
*/
public static int reflectionHashCode(final Object object, final boolean testTransients) {
return reflectionHashCode(DEFAULT_INITIAL_VALUE, DEFAULT_MULTIPLIER_VALUE, object,
return reflectionHashCode(DEFAULT_INITIAL_VALUE, DEFAULT_MULTIPLIER_VALUE, object,
testTransients, null);
}
@ -457,7 +457,7 @@ public class HashCodeBuilder implements Builder<Integer> {
* if the object is <code>null</code>
*/
public static int reflectionHashCode(final Object object, final String... excludeFields) {
return reflectionHashCode(DEFAULT_INITIAL_VALUE, DEFAULT_MULTIPLIER_VALUE, object, false,
return reflectionHashCode(DEFAULT_INITIAL_VALUE, DEFAULT_MULTIPLIER_VALUE, object, false,
null, excludeFields);
}

View File

@ -13,13 +13,13 @@ import java.io.Serializable;
*/
final class IDKey implements Serializable{
private static final long serialVersionUID = 1L;
private final Object value;
private final int id;
/**
* 构造
*
*
* @param obj 计算唯一ID的对象
*/
public IDKey(final Object obj) {
@ -32,7 +32,7 @@ final class IDKey implements Serializable{
/**
* returns hashcode - i.e. the system identity hashcode.
*
*
* @return the hashcode
*/
@Override
@ -42,7 +42,7 @@ final class IDKey implements Serializable{
/**
* checks if instances are equal
*
*
* @param other The other object to compare to
* @return if the instances are for the same object
*/

View File

@ -1,7 +1,7 @@
/**
* 建造者工具<br>
* 用于建造特定对象或结果
*
*
* @author looly
*
*/

View File

@ -13,19 +13,19 @@ public class CloneRuntimeException extends RuntimeException{
public CloneRuntimeException(Throwable e) {
super(ExceptionUtil.getMessage(e), e);
}
public CloneRuntimeException(String message) {
super(message);
}
public CloneRuntimeException(String messageTemplate, Object... params) {
super(StrUtil.format(messageTemplate, params));
}
public CloneRuntimeException(String message, Throwable throwable) {
super(message, throwable);
}
public CloneRuntimeException(Throwable throwable, String messageTemplate, Object... params) {
super(StrUtil.format(messageTemplate, params), throwable);
}

View File

@ -7,7 +7,7 @@ package cn.hutool.core.clone;
* @param <T> 继承类的类型
*/
public class CloneSupport<T> implements Cloneable<T>{
@SuppressWarnings("unchecked")
@Override
public T clone() {
@ -17,5 +17,5 @@ public class CloneSupport<T> implements Cloneable<T>{
throw new CloneRuntimeException(e);
}
}
}

View File

@ -7,7 +7,7 @@ package cn.hutool.core.clone;
* @param <T> 实现克隆接口的类型
*/
public interface Cloneable<T> extends java.lang.Cloneable{
/**
* 克隆当前对象浅复制
* @return 克隆后的对象

View File

@ -1,6 +1,6 @@
/**
* 克隆封装
*
*
* @author looly
*
*/

View File

@ -10,7 +10,7 @@ import cn.hutool.core.lang.Assert;
*
*/
public class BCD {
/**
* 字符串转BCD码
* @param asc ASCII字符串
@ -53,7 +53,7 @@ public class BCD {
}
return bbt;
}
/**
* ASCII转BCD
* @param ascii ASCII byte数组
@ -100,8 +100,8 @@ public class BCD {
}
return new String(temp);
}
//----------------------------------------------------------------- Private method start
/**
* 转换单个byte为BCD

View File

@ -14,7 +14,7 @@ import cn.hutool.core.util.StrUtil;
*
*/
public class Base32 {
private Base32() {}
private static final String BASE32_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
@ -73,10 +73,10 @@ public class Base32 {
return base32.toString();
}
/**
* base32编码
*
*
* @param source 被编码的base32字符串
* @return 被加密后的字符串
*/
@ -86,7 +86,7 @@ public class Base32 {
/**
* base32编码
*
*
* @param source 被编码的base32字符串
* @param charset 字符集
* @return 被加密后的字符串
@ -97,7 +97,7 @@ public class Base32 {
/**
* base32编码
*
*
* @param source 被编码的base32字符串
* @param charset 字符集
* @return 被加密后的字符串
@ -155,10 +155,10 @@ public class Base32 {
}
return bytes;
}
/**
* base32解码
*
*
* @param source 被解码的base32字符串
* @return 被加密后的字符串
*/
@ -168,7 +168,7 @@ public class Base32 {
/**
* base32解码
*
*
* @param source 被解码的base32字符串
* @param charset 字符集
* @return 被加密后的字符串
@ -176,10 +176,10 @@ public class Base32 {
public static String decodeStr(String source, String charset) {
return StrUtil.str(decode(source), charset);
}
/**
* base32解码
*
*
* @param source 被解码的base32字符串
* @param charset 字符集
* @return 被加密后的字符串

View File

@ -12,7 +12,7 @@ import cn.hutool.core.util.StrUtil;
/**
* Base62工具类提供Base62的编码和解码方案<br>
*
*
* @author Looly
* @since 4.5.9
*/
@ -24,7 +24,7 @@ public class Base62 {
// -------------------------------------------------------------------- encode
/**
* Base62编码
*
*
* @param source 被编码的Base62字符串
* @return 被加密后的字符串
*/
@ -34,7 +34,7 @@ public class Base62 {
/**
* Base62编码
*
*
* @param source 被编码的Base62字符串
* @param charset 字符集
* @return 被加密后的字符串
@ -45,7 +45,7 @@ public class Base62 {
/**
* Base62编码
*
*
* @param source 被编码的Base62字符串
* @return 被加密后的字符串
*/
@ -55,7 +55,7 @@ public class Base62 {
/**
* Base62编码
*
*
* @param in 被编码Base62的流一般为图片流或者文件流
* @return 被加密后的字符串
*/
@ -65,7 +65,7 @@ public class Base62 {
/**
* Base62编码
*
*
* @param file 被编码Base62的文件
* @return 被加密后的字符串
*/
@ -76,7 +76,7 @@ public class Base62 {
// -------------------------------------------------------------------- decode
/**
* Base62解码
*
*
* @param source 被解码的Base62字符串
* @return 被加密后的字符串
*/
@ -86,7 +86,7 @@ public class Base62 {
/**
* Base62解码
*
*
* @param source 被解码的Base62字符串
* @return 被加密后的字符串
*/
@ -96,7 +96,7 @@ public class Base62 {
/**
* Base62解码
*
*
* @param source 被解码的Base62字符串
* @param charset 字符集
* @return 被加密后的字符串
@ -107,7 +107,7 @@ public class Base62 {
/**
* Base62解码
*
*
* @param Base62 被解码的Base62字符串
* @param destFile 目标文件
* @return 目标文件
@ -118,7 +118,7 @@ public class Base62 {
/**
* Base62解码
*
*
* @param base62Str 被解码的Base62字符串
* @param out 写出到的流
* @param isCloseOut 是否关闭输出流
@ -129,7 +129,7 @@ public class Base62 {
/**
* Base62解码
*
*
* @param base62Str 被解码的Base62字符串
* @return 被加密后的字符串
*/
@ -139,7 +139,7 @@ public class Base62 {
/**
* 解码Base62
*
*
* @param base62bytes Base62输入
* @return 解码后的bytes
*/

View File

@ -48,16 +48,16 @@ public class Base62Codec implements Serializable{
/**
* 创建GMP风格的Base62编码解码器对象
*
*
* @return Base62Codec
*/
public static Base62Codec createGmp() {
return new Base62Codec(GMP);
}
/**
* 创建Inverted风格的Base62编码解码器对象
*
*
* @return Base62Codec
*/
public static Base62Codec createInverted() {
@ -69,7 +69,7 @@ public class Base62Codec implements Serializable{
/**
* 构造
*
*
* @param alphabet 自定义字母表
*/
public Base62Codec(byte[] alphabet) {
@ -93,7 +93,7 @@ public class Base62Codec implements Serializable{
/**
* 解码Base62消息
*
*
* @param encoded Base62内容
* @return 消息
*/
@ -105,7 +105,7 @@ public class Base62Codec implements Serializable{
// --------------------------------------------------------------------------------------------------------------- Private method start
/**
* 按照字典转换bytes
*
*
* @param indices 内容
* @param dictionary 字典
* @return 转换值
@ -122,7 +122,7 @@ public class Base62Codec implements Serializable{
/**
* 使用定义的字母表从源基准到目标基准
*
*
* @param message 消息bytes
* @param sourceBase 源基准长度
* @param targetBase 目标基准长度
@ -167,7 +167,7 @@ public class Base62Codec implements Serializable{
/**
* 估算结果长度
*
*
* @param inputLength 输入长度
* @param sourceBase 源基准长度
* @param targetBase 目标基准长度

View File

@ -8,7 +8,7 @@ import cn.hutool.core.util.StrUtil;
/**
* Base64解码实现
*
*
* @author looly
*
*/
@ -41,7 +41,7 @@ public class Base64Decoder {
/**
* base64解码
*
*
* @param source 被解码的base64字符串
* @return 被加密后的字符串
*/
@ -51,7 +51,7 @@ public class Base64Decoder {
/**
* base64解码
*
*
* @param source 被解码的base64字符串
* @param charset 字符集
* @return 被加密后的字符串
@ -62,7 +62,7 @@ public class Base64Decoder {
/**
* base64解码
*
*
* @param source 被解码的base64字符串
* @return 被加密后的字符串
*/
@ -72,7 +72,7 @@ public class Base64Decoder {
/**
* 解码Base64
*
*
* @param in 输入
* @return 解码后的bytes
*/
@ -85,7 +85,7 @@ public class Base64Decoder {
/**
* 解码Base64
*
*
* @param in 输入
* @param pos 开始位置
* @param length 长度
@ -133,7 +133,7 @@ public class Base64Decoder {
// ----------------------------------------------------------------------------------------------- Private start
/**
* 获取下一个有效的byte字符
*
*
* @param in 输入
* @param pos 当前位置调用此方法后此位置保持在有效字符的下一个位置
* @param maxPos 最大位置
@ -157,7 +157,7 @@ public class Base64Decoder {
/**
* int包装使之可变
*
*
* @author looly
*
*/

View File

@ -7,7 +7,7 @@ import java.nio.charset.Charset;
/**
* Base64编码
*
*
* @author looly
* @since 3.2.0
*/
@ -40,7 +40,7 @@ public class Base64Encoder {
// -------------------------------------------------------------------- encode
/**
* 编码为Base64非URL安全的
*
*
* @param arr 被编码的数组
* @param lineSep 在76个char之后是CRLF还是EOF
* @return 编码后的bytes
@ -51,7 +51,7 @@ public class Base64Encoder {
/**
* 编码为Base64URL安全的
*
*
* @param arr 被编码的数组
* @param lineSep 在76个char之后是CRLF还是EOF
* @return 编码后的bytes
@ -63,7 +63,7 @@ public class Base64Encoder {
/**
* base64编码
*
*
* @param source 被编码的base64字符串
* @return 被加密后的字符串
*/
@ -73,7 +73,7 @@ public class Base64Encoder {
/**
* base64编码URL安全
*
*
* @param source 被编码的base64字符串
* @return 被加密后的字符串
* @since 3.0.6
@ -84,7 +84,7 @@ public class Base64Encoder {
/**
* base64编码
*
*
* @param source 被编码的base64字符串
* @param charset 字符集
* @return 被加密后的字符串
@ -95,7 +95,7 @@ public class Base64Encoder {
/**
* base64编码URL安全的
*
*
* @param source 被编码的base64字符串
* @param charset 字符集
* @return 被加密后的字符串
@ -107,7 +107,7 @@ public class Base64Encoder {
/**
* base64编码
*
*
* @param source 被编码的base64字符串
* @return 被加密后的字符串
*/
@ -117,7 +117,7 @@ public class Base64Encoder {
/**
* base64编码,URL安全的
*
*
* @param source 被编码的base64字符串
* @return 被加密后的字符串
* @since 3.0.6
@ -129,7 +129,7 @@ public class Base64Encoder {
/**
* 编码为Base64<br>
* 如果isMultiLine为{@code true}则每76个字符一个换行符否则在一行显示
*
*
* @param arr 被编码的数组
* @param isMultiLine 在76个char之后是CRLF还是EOF
* @param isUrlSafe 是否使用URL安全字符一般为{@code false}

View File

@ -11,7 +11,7 @@ import cn.hutool.core.util.StrUtil;
/**
* 莫尔斯电码的编码和解码实现<br>
* 参考https://github.com/TakWolf/Java-MorseCoder
*
*
* @author looly, TakWolf
* @since 4.4.1
*/
@ -22,7 +22,7 @@ public class Morse {
/**
* 注册莫尔斯电码表
*
*
* @param abc 字母和字符
* @param dict 二进制
*/
@ -104,7 +104,7 @@ public class Morse {
/**
* 构造
*
*
* @param dit 点表示的字符
* @param dah 横线表示的字符
* @param split 分隔符
@ -117,13 +117,13 @@ public class Morse {
/**
* 编码
*
*
* @param text 文本
* @return 密文
*/
public String encode(String text) {
Assert.notNull(text, "Text should not be null.");
text = text.toUpperCase();
final StringBuilder morseBuilder = new StringBuilder();
final int len = text.codePointCount(0, text.length());
@ -140,7 +140,7 @@ public class Morse {
/**
* 解码
*
*
* @param morse 莫尔斯电码
* @return 明文
*/

View File

@ -3,7 +3,7 @@ package cn.hutool.core.codec;
/**
* RotNrotate by N places回转N位密码是一种简易的替换式密码也是过去在古罗马开发的凯撒加密的一种变体<br>
* 代码来自https://github.com/orclight/jencrypt
*
*
* @author looly,shuzhilong
* @since 4.4.1
*/
@ -18,7 +18,7 @@ public class Rot {
/**
* Rot-13编码同时编码数字
*
*
* @param message 被编码的消息
* @return 编码后的字符串
*/
@ -28,7 +28,7 @@ public class Rot {
/**
* Rot-13编码
*
*
* @param message 被编码的消息
* @param isEnocdeNumber 是否编码数字
* @return 编码后的字符串
@ -39,7 +39,7 @@ public class Rot {
/**
* RotN编码
*
*
* @param message 被编码的消息
* @param offset 位移常用位移13
* @param isEnocdeNumber 是否编码数字
@ -57,7 +57,7 @@ public class Rot {
/**
* Rot-13解码同时解码数字
*
*
* @param rot 被解码的消息密文
* @return 解码后的字符串
*/
@ -67,7 +67,7 @@ public class Rot {
/**
* Rot-13解码
*
*
* @param rot 被解码的消息密文
* @param isDecodeNumber 是否解码数字
* @return 解码后的字符串
@ -78,7 +78,7 @@ public class Rot {
/**
* RotN解码
*
*
* @param rot 被解码的消息密文
* @param offset 位移常用位移13
* @param isDecodeNumber 是否解码数字
@ -97,7 +97,7 @@ public class Rot {
// ------------------------------------------------------------------------------------------ Private method start
/**
* 解码字符
*
*
* @param c 字符
* @param offset 位移
* @param isDecodeNumber 是否解码数字
@ -129,7 +129,7 @@ public class Rot {
/**
* 编码字符
*
*
* @param c 字符
* @param offset 位移
* @param isDecodeNumber 是否编码数字

View File

@ -1,6 +1,6 @@
/**
* BaseN以及BCD编码封装
*
*
* @author looly
*
*/

View File

@ -58,7 +58,7 @@ public class ArrayIter<E> implements Iterator<E>, Iterable<E>, Serializable{
if(endIndex > 0 && endIndex < this.endIndex){
this.endIndex = endIndex;
}
if(startIndex >=0 && startIndex < this.endIndex){
this.startIndex = startIndex;
}

View File

@ -15,15 +15,15 @@ import java.util.PriorityQueue;
*/
public class BoundedPriorityQueue<E> extends PriorityQueue<E>{
private static final long serialVersionUID = 3794348988671694820L;
//容量
private final int capacity;
private final Comparator<? super E> comparator;
public BoundedPriorityQueue(int capacity) {
this(capacity, null);
}
/**
* 构造
* @param capacity 容量
@ -63,7 +63,7 @@ public class BoundedPriorityQueue<E> extends PriorityQueue<E>{
}
return super.offer(e);
}
/**
* 添加多个元素<br>
* 参数为集合的情况请使用{@link PriorityQueue#addAll}
@ -73,7 +73,7 @@ public class BoundedPriorityQueue<E> extends PriorityQueue<E>{
public boolean addAll(E[] c) {
return this.addAll(Arrays.asList(c));
}
/**
* @return 返回排序后的列表
*/
@ -82,7 +82,7 @@ public class BoundedPriorityQueue<E> extends PriorityQueue<E>{
list.sort(comparator);
return list;
}
@Override
public Iterator<E> iterator() {
return toList().iterator();

View File

@ -2780,11 +2780,11 @@ public class CollUtil {
}
/**
* 取最
* 取最
*
* @param <T> 元素类型
* @param coll 集合
* @return
* @return
* @see Collections#min(Collection)
* @since 4.6.5
*/
@ -2988,4 +2988,25 @@ public class CollUtil {
}
return total;
}
/**
* 判断两个{@link Collection} 是否元素和顺序相同返回{@code true}的条件是
* <ul>
* <li>两个{@link Collection}必须长度相同</li>
* <li>两个{@link Collection}元素相同index的对象必须equals满足{@link Objects#equals(Object, Object)}</li>
* </ul>
* 此方法来自Apache-Commons-Collections4
*
* @param list1 列表1
* @param list2 列表2
* @return 是否相同
* @since 5.6.0
*/
public static boolean isEqualList(final Collection<?> list1, final Collection<?> list2) {
if (list1 == null || list2 == null || list1.size() != list2.size()) {
return false;
}
return IterUtil.isEqualList(list1, list2);
}
}

View File

@ -2,7 +2,7 @@ package cn.hutool.core.collection;
/**
* 集合相关工具类包括数组{@link CollUtil} 的别名工具类类
*
*
* @author xiaoleilu
* @see CollUtil
*/

View File

@ -7,7 +7,7 @@ import java.util.concurrent.ConcurrentHashMap;
/**
* 通过{@link ConcurrentHashMap}实现的线程安全HashSet
*
*
* @author Looly
*
* @param <E> 元素类型
@ -32,7 +32,7 @@ public class ConcurrentHashSet<E> extends AbstractSet<E> implements java.io.Seri
/**
* 构造<br>
* 触发因子为默认的0.75
*
*
* @param initialCapacity 初始大小
*/
public ConcurrentHashSet(int initialCapacity) {
@ -41,7 +41,7 @@ public class ConcurrentHashSet<E> extends AbstractSet<E> implements java.io.Seri
/**
* 构造
*
*
* @param initialCapacity 初始大小
* @param loadFactor 加载因子此参数决定数据增长时触发的百分比
*/
@ -51,7 +51,7 @@ public class ConcurrentHashSet<E> extends AbstractSet<E> implements java.io.Seri
/**
* 构造
*
*
* @param initialCapacity 初始大小
* @param loadFactor 触发因子此参数决定数据增长时触发的百分比
* @param concurrencyLevel 线程并发度
@ -59,7 +59,7 @@ public class ConcurrentHashSet<E> extends AbstractSet<E> implements java.io.Seri
public ConcurrentHashSet(int initialCapacity, float loadFactor, int concurrencyLevel) {
map = new ConcurrentHashMap<>(initialCapacity, loadFactor, concurrencyLevel);
}
/**
* 从已有集合中构造
* @param iter {@link Iterable}

View File

@ -8,14 +8,14 @@ import java.util.List;
* 复制 {@link Iterator}<br>
* 为了解决并发情况下{@link Iterator}遍历导致的问题当Iterator被修改会抛出ConcurrentModificationException
* 故使用复制原Iterator的方式解决此问题
*
*
* <p>
* 解决方法为在构造方法中遍历Iterator中的元素装入新的List中然后遍历之
* 当然修改这个复制后的Iterator是没有意义的因此remove方法将会抛出异常
*
*
* <p>
* 需要注意的是在构造此对象时需要保证原子性原对象不被修改最好加锁构造此对象构造完毕后解锁
*
*
*
* @param <E> 元素类型
* @author Looly
@ -25,7 +25,7 @@ public class CopiedIter<E> implements Iterator<E>, Iterable<E>, Serializable {
private static final long serialVersionUID = 1L;
private final Iterator<E> listIterator;
public static <V> CopiedIter<V> copyOf(Iterator<V> iterator){
return new CopiedIter<>(iterator);
}

View File

@ -13,9 +13,9 @@ import java.util.Iterator;
*/
public class EnumerationIter<E> implements Iterator<E>, Iterable<E>, Serializable{
private static final long serialVersionUID = 1L;
private final Enumeration<E> e;
/**
* 构造
* @param enumeration {@link Enumeration}对象

View File

@ -18,6 +18,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.function.Function;
/**
@ -612,7 +613,7 @@ public class IterUtil {
/**
* Enumeration转换为Iterator
* <p>
* Adapt the specified <code>Enumeration</code> to the <code>Iterator</code> interface
* Adapt the specified {@code Enumeration} to the {@code Iterator} interface
*
* @param <E> 集合元素类型
* @param e {@link Enumeration}
@ -859,4 +860,39 @@ public class IterUtil {
}
return size;
}
/**
* 判断两个{@link Iterable} 是否元素和顺序相同返回{@code true}的条件是
* <ul>
* <li>两个{@link Iterable}必须长度相同</li>
* <li>两个{@link Iterable}元素相同index的对象必须equals满足{@link Objects#equals(Object, Object)}</li>
* </ul>
* 此方法来自Apache-Commons-Collections4
*
* @param list1 列表1
* @param list2 列表2
* @return 是否相同
* @since 5.6.0
*/
public static boolean isEqualList(final Iterable<?> list1, final Iterable<?> list2) {
if (list1 == list2) {
return true;
}
final Iterator<?> it1 = list1.iterator();
final Iterator<?> it2 = list2.iterator();
Object obj1;
Object obj2;
while (it1.hasNext() && it2.hasNext()) {
obj1 = it1.next();
obj2 = it2.next();
if (false == Objects.equals(obj1, obj2)) {
return false;
}
}
// 当两个Iterable长度不一致时返回false
return false == (it1.hasNext() || it2.hasNext());
}
}

View File

@ -13,9 +13,9 @@ import java.util.Iterator;
*/
public class IteratorEnumeration<E> implements Enumeration<E>, Serializable{
private static final long serialVersionUID = 1L;
private final Iterator<E> iterator;
/**
* 构造
* @param iterator {@link Iterator}对象

View File

@ -17,7 +17,7 @@ import cn.hutool.core.lang.Assert;
/**
* 将Reader包装为一个按照行读取的Iterator<br>
* 此对象遍历结束后应关闭之推荐使用方式:
*
*
* <pre>
* LineIterator it = null;
* try {
@ -30,7 +30,7 @@ import cn.hutool.core.lang.Assert;
* it.close();
* }
* </pre>
*
*
* 此类来自于Apache Commons io
*
* @author looly
@ -45,7 +45,7 @@ public class LineIter implements Iterator<String>, Iterable<String>, Closeable,
private String cachedLine;
/** A flag indicating if the iterator has been fully read. */
private boolean finished = false;
/**
* 构造
*
@ -148,7 +148,7 @@ public class LineIter implements Iterator<String>, Iterable<String>, Closeable,
/**
* 重写此方法来判断是否每一行都被返回默认全部为true
*
*
* @param line 需要验证的行
* @return 是否通过验证
*/

View File

@ -246,7 +246,7 @@ public class ListUtil {
// 每页条目数大于总数直接返回所有
if (resultSize <= pageSize) {
if (pageNo < (PageUtil.getFirstPageNo() + 1)) {
return Collections.unmodifiableList(list);
return unmodifiable(list);
} else {
// 越界直接返回空
return new ArrayList<>(0);
@ -262,11 +262,11 @@ public class ListUtil {
if (startEnd[1] > resultSize) {
startEnd[1] = resultSize;
if (startEnd[0] > startEnd[1]) {
return empty();
return new ArrayList<>(0);
}
}
return list.subList(startEnd[0], startEnd[1]);
return sub(list, startEnd[0], startEnd[1]);
}
/**
@ -366,7 +366,8 @@ public class ListUtil {
}
/**
* 截取集合的部分
* 截取集合的部分<br>
* 此方法与{@link List#subList(int, int)} 不同在于子列表是新的副本操作子列表不会影响原列表
*
* @param <T> 集合元素类型
* @param list 被截取的数组
@ -407,8 +408,8 @@ public class ListUtil {
end = size;
}
if (step <= 1) {
return list.subList(start, end);
if (step < 1) {
step = 1;
}
final List<T> result = new ArrayList<>();

View File

@ -21,7 +21,6 @@ public class ComparableComparator<E extends Comparable<? super E>> implements Co
* 构造
*/
public ComparableComparator() {
super();
}
/**

View File

@ -28,9 +28,9 @@ import java.util.concurrent.TimeUnit;
/**
* 类型转换器
*
*
* @author xiaoleilu
*
*
*/
public class Convert {
@ -38,7 +38,7 @@ public class Convert {
* 转换为字符串<br>
* 如果给定的值为null或者转换失败返回默认值<br>
* 转换失败不会报错
*
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
@ -51,17 +51,17 @@ public class Convert {
* 转换为字符串<br>
* 如果给定的值为{@code null}或者转换失败返回默认值{@code null}<br>
* 转换失败不会报错
*
*
* @param value 被转换的值
* @return 结果
*/
public static String toStr(Object value) {
return toStr(value, null);
}
/**
* 转换为String数组
*
*
* @param value 被转换的值
* @return String数组
* @since 3.2.0
@ -74,7 +74,7 @@ public class Convert {
* 转换为字符<br>
* 如果给定的值为null或者转换失败返回默认值<br>
* 转换失败不会报错
*
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
@ -87,17 +87,17 @@ public class Convert {
* 转换为字符<br>
* 如果给定的值为{@code null}或者转换失败返回默认值{@code null}<br>
* 转换失败不会报错
*
*
* @param value 被转换的值
* @return 结果
*/
public static Character toChar(Object value) {
return toChar(value, null);
}
/**
* 转换为Character数组
*
*
* @param value 被转换的值
* @return Character数组
* @since 3.2.0
@ -110,7 +110,7 @@ public class Convert {
* 转换为byte<br>
* 如果给定的值为{@code null}或者转换失败返回默认值<br>
* 转换失败不会报错
*
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
@ -123,17 +123,17 @@ public class Convert {
* 转换为byte<br>
* 如果给定的值为{@code null}或者转换失败返回默认值{@code null}<br>
* 转换失败不会报错
*
*
* @param value 被转换的值
* @return 结果
*/
public static Byte toByte(Object value) {
return toByte(value, null);
}
/**
* 转换为Byte数组
*
*
* @param value 被转换的值
* @return Byte数组
* @since 3.2.0
@ -157,7 +157,7 @@ public class Convert {
* 转换为Short<br>
* 如果给定的值为{@code null}或者转换失败返回默认值<br>
* 转换失败不会报错
*
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
@ -170,17 +170,17 @@ public class Convert {
* 转换为Short<br>
* 如果给定的值为{@code null}或者转换失败返回默认值{@code null}<br>
* 转换失败不会报错
*
*
* @param value 被转换的值
* @return 结果
*/
public static Short toShort(Object value) {
return toShort(value, null);
}
/**
* 转换为Short数组
*
*
* @param value 被转换的值
* @return Short数组
* @since 3.2.0
@ -193,7 +193,7 @@ public class Convert {
* 转换为Number<br>
* 如果给定的值为空或者转换失败返回默认值<br>
* 转换失败不会报错
*
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
@ -206,17 +206,17 @@ public class Convert {
* 转换为Number<br>
* 如果给定的值为空或者转换失败返回默认值{@code null}<br>
* 转换失败不会报错
*
*
* @param value 被转换的值
* @return 结果
*/
public static Number toNumber(Object value) {
return toNumber(value, null);
}
/**
* 转换为Number数组
*
*
* @param value 被转换的值
* @return Number数组
* @since 3.2.0
@ -229,7 +229,7 @@ public class Convert {
* 转换为int<br>
* 如果给定的值为空或者转换失败返回默认值<br>
* 转换失败不会报错
*
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
@ -242,7 +242,7 @@ public class Convert {
* 转换为int<br>
* 如果给定的值为{@code null}或者转换失败返回默认值{@code null}<br>
* 转换失败不会报错
*
*
* @param value 被转换的值
* @return 结果
*/
@ -264,7 +264,7 @@ public class Convert {
* 转换为long<br>
* 如果给定的值为空或者转换失败返回默认值<br>
* 转换失败不会报错
*
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
@ -277,7 +277,7 @@ public class Convert {
* 转换为long<br>
* 如果给定的值为{@code null}或者转换失败返回默认值{@code null}<br>
* 转换失败不会报错
*
*
* @param value 被转换的值
* @return 结果
*/
@ -287,7 +287,7 @@ public class Convert {
/**
* 转换为Long数组<br>
*
*
* @param value 被转换的值
* @return 结果
*/
@ -299,7 +299,7 @@ public class Convert {
* 转换为double<br>
* 如果给定的值为空或者转换失败返回默认值<br>
* 转换失败不会报错
*
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
@ -312,7 +312,7 @@ public class Convert {
* 转换为double<br>
* 如果给定的值为空或者转换失败返回默认值{@code null}<br>
* 转换失败不会报错
*
*
* @param value 被转换的值
* @return 结果
*/
@ -322,7 +322,7 @@ public class Convert {
/**
* 转换为Double数组<br>
*
*
* @param value 被转换的值
* @return 结果
*/
@ -334,7 +334,7 @@ public class Convert {
* 转换为Float<br>
* 如果给定的值为空或者转换失败返回默认值<br>
* 转换失败不会报错
*
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
@ -347,7 +347,7 @@ public class Convert {
* 转换为Float<br>
* 如果给定的值为空或者转换失败返回默认值{@code null}<br>
* 转换失败不会报错
*
*
* @param value 被转换的值
* @return 结果
*/
@ -357,7 +357,7 @@ public class Convert {
/**
* 转换为Float数组<br>
*
*
* @param value 被转换的值
* @return 结果
*/
@ -369,7 +369,7 @@ public class Convert {
* 转换为boolean<br>
* String支持的值为truefalseyesokno1,0 如果给定的值为空或者转换失败返回默认值<br>
* 转换失败不会报错
*
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
@ -382,7 +382,7 @@ public class Convert {
* 转换为boolean<br>
* 如果给定的值为空或者转换失败返回默认值{@code null}<br>
* 转换失败不会报错
*
*
* @param value 被转换的值
* @return 结果
*/
@ -392,7 +392,7 @@ public class Convert {
/**
* 转换为Boolean数组<br>
*
*
* @param value 被转换的值
* @return 结果
*/
@ -404,7 +404,7 @@ public class Convert {
* 转换为BigInteger<br>
* 如果给定的值为空或者转换失败返回默认值<br>
* 转换失败不会报错
*
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
@ -417,7 +417,7 @@ public class Convert {
* 转换为BigInteger<br>
* 如果给定的值为空或者转换失败返回默认值{@code null}<br>
* 转换失败不会报错
*
*
* @param value 被转换的值
* @return 结果
*/
@ -429,7 +429,7 @@ public class Convert {
* 转换为BigDecimal<br>
* 如果给定的值为空或者转换失败返回默认值<br>
* 转换失败不会报错
*
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
@ -442,19 +442,19 @@ public class Convert {
* 转换为BigDecimal<br>
* 如果给定的值为空或者转换失败返回null<br>
* 转换失败不会报错
*
*
* @param value 被转换的值
* @return 结果
*/
public static BigDecimal toBigDecimal(Object value) {
return toBigDecimal(value, null);
}
/**
* 转换为Date<br>
* 如果给定的值为空或者转换失败返回默认值<br>
* 转换失败不会报错
*
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
@ -489,7 +489,7 @@ public class Convert {
public static LocalDateTime toLocalDateTime(Object value) {
return toLocalDateTime(value, null);
}
/**
* Instant<br>
* 如果给定的值为空或者转换失败返回默认值<br>
@ -508,7 +508,7 @@ public class Convert {
* 转换为Date<br>
* 如果给定的值为空或者转换失败返回{@code null}<br>
* 转换失败不会报错
*
*
* @param value 被转换的值
* @return 结果
* @since 4.1.6
@ -516,11 +516,11 @@ public class Convert {
public static Date toDate(Object value) {
return toDate(value, null);
}
/**
* 转换为Enum对象<br>
* 如果给定的值为空或者转换失败返回默认值<br>
*
*
* @param <E> 枚举类型
* @param clazz Enum的Class
* @param value
@ -535,7 +535,7 @@ public class Convert {
/**
* 转换为Enum对象<br>
* 如果给定的值为空或者转换失败返回默认值{@code null}<br>
*
*
* @param <E> 枚举类型
* @param clazz Enum的Class
* @param value
@ -547,7 +547,7 @@ public class Convert {
/**
* 转换为集合类
*
*
* @param collectionType 集合类型
* @param elementType 集合中元素类型
* @param value 被转换的值
@ -557,10 +557,10 @@ public class Convert {
public static Collection<?> toCollection(Class<?> collectionType, Class<?> elementType, Object value) {
return new CollectionConverter(collectionType, elementType).convert(value, null);
}
/**
* 转换为ArrayList元素类型默认Object
*
*
* @param value 被转换的值
* @return {@link List}
* @since 4.1.11
@ -568,10 +568,10 @@ public class Convert {
public static List<?> toList(Object value) {
return convert(List.class, value);
}
/**
* 转换为ArrayList
*
*
* @param <T> 元素类型
* @param elementType 集合中元素类型
* @param value 被转换的值
@ -598,10 +598,10 @@ public class Convert {
public static <K, V> Map<K, V> toMap(Class<K> keyType, Class<V> valueType, Object value) {
return (Map<K, V>) new MapConverter(HashMap.class, keyType, valueType).convert(value, null);
}
/**
* 转换值为指定类型类型采用字符串表示
*
*
* @param <T> 目标类型
* @param className 类的字符串表示
* @param value
@ -612,10 +612,10 @@ public class Convert {
public static <T> T convertByClassName(String className, Object value) throws ConvertException{
return convert(ClassUtil.loadClass(className), value);
}
/**
* 转换值为指定类型
*
*
* @param <T> 目标类型
* @param type 类型
* @param value
@ -626,10 +626,10 @@ public class Convert {
public static <T> T convert(Class<T> type, Object value) throws ConvertException{
return convert((Type)type, value);
}
/**
* 转换值为指定类型
*
*
* @param <T> 目标类型
* @param reference 类型参考用于持有转换后的泛型类型
* @param value
@ -642,7 +642,7 @@ public class Convert {
/**
* 转换值为指定类型
*
*
* @param <T> 目标类型
* @param type 类型
* @param value
@ -652,10 +652,10 @@ public class Convert {
public static <T> T convert(Type type, Object value) throws ConvertException{
return convert(type, value, null);
}
/**
* 转换值为指定类型
*
*
* @param <T> 目标类型
* @param type 类型
* @param value
@ -667,10 +667,10 @@ public class Convert {
public static <T> T convert(Class<T> type, Object value, T defaultValue) throws ConvertException {
return convert((Type)type, value, defaultValue);
}
/**
* 转换值为指定类型
*
*
* @param <T> 目标类型
* @param type 类型
* @param value
@ -681,11 +681,11 @@ public class Convert {
public static <T> T convert(Type type, Object value, T defaultValue) throws ConvertException {
return convertWithCheck(type, value, defaultValue, false);
}
/**
* 转换值为指定类型不抛异常转换<br>
* 当转换失败时返回{@code null}
*
*
* @param <T> 目标类型
* @param type 目标类型
* @param value
@ -695,11 +695,11 @@ public class Convert {
public static <T> T convertQuietly(Type type, Object value) {
return convertQuietly(type, value, null);
}
/**
* 转换值为指定类型不抛异常转换<br>
* 当转换失败时返回默认值
*
*
* @param <T> 目标类型
* @param type 目标类型
* @param value
@ -734,11 +734,11 @@ public class Convert {
throw e;
}
}
// ----------------------------------------------------------------------- 全角半角转换
/**
* 半角转全角
*
*
* @param input String.
* @return 全角字符串.
*/
@ -748,7 +748,7 @@ public class Convert {
/**
* 半角转全角
*
*
* @param input String
* @param notConvertSet 不替换的字符集合
* @return 全角字符串.
@ -773,7 +773,7 @@ public class Convert {
/**
* 全角转半角
*
*
* @param input String.
* @return 半角字符串
*/
@ -783,7 +783,7 @@ public class Convert {
/**
* 替换全角为半角
*
*
* @param text 文本
* @param notConvertSet 不替换的字符集合
* @return 替换后的字符
@ -813,7 +813,7 @@ public class Convert {
// --------------------------------------------------------------------- hex
/**
* 字符串转换成十六进制字符串结果为小写
*
*
* @param str 待转换的ASCII字符串
* @param charset 编码
* @return 16进制字符串
@ -825,7 +825,7 @@ public class Convert {
/**
* byte数组转16进制串
*
*
* @param bytes 被转换的byte数组
* @return 转换后的值
* @see HexUtil#encodeHexStr(byte[])
@ -836,7 +836,7 @@ public class Convert {
/**
* Hex字符串转换为Byte值
*
*
* @param src Byte字符串每个Byte之间没有分隔符
* @return byte[]
* @see HexUtil#decodeHex(char[])
@ -847,7 +847,7 @@ public class Convert {
/**
* 十六进制转换字符串
*
*
* @param hexStr Byte字符串(Byte之间无分隔符 :[616C6B])
* @param charset 编码 {@link Charset}
* @return 对应的字符串
@ -858,10 +858,10 @@ public class Convert {
public static String hexStrToStr(String hexStr, Charset charset) {
return hexToStr(hexStr, charset);
}
/**
* 十六进制转换字符串
*
*
* @param hexStr Byte字符串(Byte之间无分隔符 :[616C6B])
* @param charset 编码 {@link Charset}
* @return 对应的字符串
@ -874,7 +874,7 @@ public class Convert {
/**
* String的字符串转换成unicode的String
*
*
* @param strText 全角字符串
* @return String 每个unicode之间无分隔符
* @see UnicodeUtil#toUnicode(String)
@ -885,7 +885,7 @@ public class Convert {
/**
* unicode的String转换成String的字符串
*
*
* @param unicode Unicode符
* @return String 字符串
* @see UnicodeUtil#toString(String)
@ -897,7 +897,7 @@ public class Convert {
/**
* 给定字符串转换字符编码<br>
* 如果参数为空则返回原字符串不报错
*
*
* @param str 被转码的字符串
* @param sourceCharset 原字符集
* @param destCharset 目标字符集
@ -914,7 +914,7 @@ public class Convert {
/**
* 转换时间单位
*
*
* @param sourceDuration 时长
* @param sourceUnit 源单位
* @param destUnit 目标单位
@ -929,7 +929,7 @@ public class Convert {
// --------------------------------------------------------------- 原始包装类型转换
/**
* 原始类转为包装类非原始类返回原类
*
*
* @see BasicType#wrap(Class)
* @param clazz 原始类
* @return 包装类
@ -941,7 +941,7 @@ public class Convert {
/**
* 包装类转为原始类非包装类返回原类
*
*
* @see BasicType#unWrap(Class)
* @param clazz 包装类
* @return 原始类
@ -954,7 +954,7 @@ public class Convert {
// -------------------------------------------------------------------------- 数字和英文转换
/**
* 将阿拉伯数字转为英文表达方式
*
*
* @param number {@link Number}对象
* @return 英文表达式
* @since 3.0.9
@ -962,10 +962,25 @@ public class Convert {
public static String numberToWord(Number number) {
return NumberWordFormatter.format(number);
}
/**
* 将阿拉伯数字转为精简表示形式例如:
*
* <pre>
* 1200 - 1.2k
* </pre>
*
* @param number {@link Number}对象
* @return 英文表达式
* @since 5.5.9
*/
public static String numberToSimple(Number number) {
return NumberWordFormatter.formatSimple(number.longValue());
}
/**
* 将阿拉伯数字转为中文表达方式
*
*
* @param number 数字
* @param isUseTraditonal 是否使用繁体字金额形式
* @return 中文
@ -974,10 +989,10 @@ public class Convert {
public static String numberToChinese(double number, boolean isUseTraditonal) {
return NumberChineseFormatter.format(number, isUseTraditonal);
}
/**
* 金额转为中文形式
*
*
* @param n 数字
* @return 中文大写数字
* @since 3.2.3
@ -988,11 +1003,11 @@ public class Convert {
}
return NumberChineseFormatter.format(n.doubleValue(), true, true);
}
// -------------------------------------------------------------------------- 数字转换
/**
* int转byte
*
*
* @param intValue int值
* @return byte值
* @since 3.2.0
@ -1003,7 +1018,7 @@ public class Convert {
/**
* byte转无符号int
*
*
* @param byteValue byte值
* @return 无符号int值
* @since 3.2.0
@ -1015,7 +1030,7 @@ public class Convert {
/**
* byte数组转short
*
*
* @param bytes byte数组
* @return short值
* @since 3.2.0
@ -1039,7 +1054,7 @@ public class Convert {
/**
* byte[]转int值
*
*
* @param bytes byte数组
* @return int值
* @since 3.2.0
@ -1053,7 +1068,7 @@ public class Convert {
/**
* int转byte数组
*
*
* @param intValue int值
* @return byte数组
* @since 3.2.0
@ -1070,7 +1085,7 @@ public class Convert {
/**
* long转byte数组<br>
* from: https://stackoverflow.com/questions/4485128/how-do-i-convert-long-to-byte-and-back-in-java
*
*
* @param longValue long值
* @return byte数组
* @since 3.2.0
@ -1088,7 +1103,7 @@ public class Convert {
/**
* byte数组转long<br>
* from: https://stackoverflow.com/questions/4485128/how-do-i-convert-long-to-byte-and-back-in-java
*
*
* @param bytes byte数组
* @return long值
* @since 3.2.0

View File

@ -1,180 +1,182 @@
package cn.hutool.core.convert;
import cn.hutool.core.util.StrUtil;
import java.text.DecimalFormat;
/**
* 将浮点数类型的number转换成英语的表达方式 <br>
* 参考博客http://blog.csdn.net/eric_sunah/article/details/8713226
*
* @author Looly
* @since 3.0.9
*/
public class NumberWordFormatter {
private static final String[] NUMBER = new String[]{"", "ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN",
"EIGHT", "NINE"};
private static final String[] NUMBER_TEEN = new String[]{"TEN", "ELEVEN", "TWELVE", "THIRTEEN", "FOURTEEN",
"FIFTEEN", "SIXTEEN", "SEVENTEEN", "EIGHTEEN", "NINETEEN"};
private static final String[] NUMBER_TEN = new String[]{"TEN", "TWENTY", "THIRTY", "FORTY", "FIFTY", "SIXTY",
"SEVENTY", "EIGHTY", "NINETY"};
private static final String[] NUMBER_MORE = new String[]{"", "THOUSAND", "MILLION", "BILLION"};
private static final String[] NUMBER_SUFFIX = new String[]{"k", "w", "", "m", "", "", "b", "", "", "t", "", "", "p", "", "", "e"};
/**
* 将阿拉伯数字转为英文表达式
*
* @param x 阿拉伯数字可以为{@link Number}对象也可以是普通对象最后会使用字符串方式处理
* @return 英文表达式
*/
public static String format(Object x) {
if (x != null) {
return format(x.toString());
} else {
return "";
}
}
/**
* 将阿拉伯数字转化为简介计数单位例如 2100 => 2.1k
* 范围默认只到w
* @param value
* @return
*/
public static String formatValue(long value) {
return formatValue(value, true);
}
/**
* 将阿拉伯数字转化为简介计数单位例如 2100 => 2.1k
* @param value 对应数字的值
* @param isTwo 控制是否为kw
* @return
*/
public static String formatValue(long value, boolean isTwo) {
if (value < 1000) {
return String.valueOf(value);
}
int index = -1;
double res = value * 1.0d;
while (res > 10 && (!isTwo || index < 1)) {
if (res > 1000) {
res = res / 1000;
index++;
}
if (res > 10) {
res = res / 10;
index++;
}
}
DecimalFormat decimalFormat = new DecimalFormat("#.##");
return String.format("%s%s", decimalFormat.format(res), NUMBER_SUFFIX[index]);
}
/**
* 将阿拉伯数字转为英文表达式
*
* @param x 阿拉伯数字字符串
* @return 英文表达式
*/
private static String format(String x) {
int z = x.indexOf("."); // 取小数点位置
String lstr, rstr = "";
if (z > -1) { // 看是否有小数如果有则分别取左边和右边
lstr = x.substring(0, z);
rstr = x.substring(z + 1);
} else {
// 否则就是全部
lstr = x;
}
String lstrrev = StrUtil.reverse(lstr); // 对左边的字串取反
String[] a = new String[5]; // 定义5个字串变量来存放解析出来的叁位一组的字串
switch (lstrrev.length() % 3) {
case 1:
lstrrev += "00";
break;
case 2:
lstrrev += "0";
break;
}
StringBuilder lm = new StringBuilder(); // 用来存放转换后的整数部分
for (int i = 0; i < lstrrev.length() / 3; i++) {
a[i] = StrUtil.reverse(lstrrev.substring(3 * i, 3 * i + 3)); // 截取第一个三位
if (false == "000".equals(a[i])) { // 用来避免这种情况1000000 = one million
// thousand only
if (i != 0) {
lm.insert(0, transThree(a[i]) + " " + parseMore(i) + " "); // :
// thousandmillionbillion
} else {
// 防止i=0时 在多加两个空格.
lm = new StringBuilder(transThree(a[i]));
}
} else {
lm.append(transThree(a[i]));
}
}
String xs = ""; // 用来存放转换后小数部分
if (z > -1) {
xs = "AND CENTS " + transTwo(rstr) + " "; // 小数部分存在时转换小数
}
return lm.toString().trim() + " " + xs + "ONLY";
}
private static String parseFirst(String s) {
return NUMBER[Integer.parseInt(s.substring(s.length() - 1))];
}
private static String parseTeen(String s) {
return NUMBER_TEEN[Integer.parseInt(s) - 10];
}
private static String parseTen(String s) {
return NUMBER_TEN[Integer.parseInt(s.substring(0, 1)) - 1];
}
private static String parseMore(int i) {
return NUMBER_MORE[i];
}
// 两位
private static String transTwo(String s) {
String value;
// 判断位数
if (s.length() > 2) {
s = s.substring(0, 2);
} else if (s.length() < 2) {
s = "0" + s;
}
if (s.startsWith("0")) {// 07 - seven 是否小於10
value = parseFirst(s);
} else if (s.startsWith("1")) {// 17 seventeen 是否在10和20之间
value = parseTeen(s);
} else if (s.endsWith("0")) {// 是否在10与100之间的能被10整除的数
value = parseTen(s);
} else {
value = parseTen(s) + " " + parseFirst(s);
}
return value;
}
// 制作叁位的数
// s.length = 3
private static String transThree(String s) {
String value;
if (s.startsWith("0")) {// 是否小於100
value = transTwo(s.substring(1));
} else if ("00".equals(s.substring(1))) {// 是否被100整除
value = parseFirst(s.substring(0, 1)) + " HUNDRED";
} else {
value = parseFirst(s.substring(0, 1)) + " HUNDRED AND " + transTwo(s.substring(1));
}
return value;
}
}
package cn.hutool.core.convert;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
/**
* 将浮点数类型的number转换成英语的表达方式 <br>
* 参考博客http://blog.csdn.net/eric_sunah/article/details/8713226
*
* @author Looly,totalo
* @since 3.0.9
*/
public class NumberWordFormatter {
private static final String[] NUMBER = new String[]{"", "ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN",
"EIGHT", "NINE"};
private static final String[] NUMBER_TEEN = new String[]{"TEN", "ELEVEN", "TWELVE", "THIRTEEN", "FOURTEEN",
"FIFTEEN", "SIXTEEN", "SEVENTEEN", "EIGHTEEN", "NINETEEN"};
private static final String[] NUMBER_TEN = new String[]{"TEN", "TWENTY", "THIRTY", "FORTY", "FIFTY", "SIXTY",
"SEVENTY", "EIGHTY", "NINETY"};
private static final String[] NUMBER_MORE = new String[]{"", "THOUSAND", "MILLION", "BILLION"};
private static final String[] NUMBER_SUFFIX = new String[]{"k", "w", "", "m", "", "", "b", "", "", "t", "", "", "p", "", "", "e"};
/**
* 将阿拉伯数字转为英文表达式
*
* @param x 阿拉伯数字可以为{@link Number}对象也可以是普通对象最后会使用字符串方式处理
* @return 英文表达式
*/
public static String format(Object x) {
if (x != null) {
return format(x.toString());
} else {
return StrUtil.EMPTY;
}
}
/**
* 将阿拉伯数字转化为简洁计数单位例如 2100 = 2.1k
* 范围默认只到w
*
* @param value 被格式化的数字
* @return 格式化后的数字
* @since 5.5.9
*/
public static String formatSimple(long value) {
return formatSimple(value, true);
}
/**
* 将阿拉伯数字转化为简介计数单位例如 2100 = 2.1k
*
* @param value 对应数字的值
* @param isTwo 控制是否为只为kw例如当为{@code false}时返回4.38m{@code true}返回438.43w
* @return 格式化后的数字
* @since 5.5.9
*/
public static String formatSimple(long value, boolean isTwo) {
if (value < 1000) {
return String.valueOf(value);
}
int index = -1;
double res = value;
while (res > 10 && (false == isTwo || index < 1)) {
if (res > 1000) {
res = res / 1000;
index++;
}
if (res > 10) {
res = res / 10;
index++;
}
}
return String.format("%s%s", NumberUtil.decimalFormat("#.##", res), NUMBER_SUFFIX[index]);
}
/**
* 将阿拉伯数字转为英文表达式
*
* @param x 阿拉伯数字字符串
* @return 英文表达式
*/
private static String format(String x) {
int z = x.indexOf("."); // 取小数点位置
String lstr, rstr = "";
if (z > -1) { // 看是否有小数如果有则分别取左边和右边
lstr = x.substring(0, z);
rstr = x.substring(z + 1);
} else {
// 否则就是全部
lstr = x;
}
String lstrrev = StrUtil.reverse(lstr); // 对左边的字串取反
String[] a = new String[5]; // 定义5个字串变量来存放解析出来的叁位一组的字串
switch (lstrrev.length() % 3) {
case 1:
lstrrev += "00";
break;
case 2:
lstrrev += "0";
break;
}
StringBuilder lm = new StringBuilder(); // 用来存放转换后的整数部分
for (int i = 0; i < lstrrev.length() / 3; i++) {
a[i] = StrUtil.reverse(lstrrev.substring(3 * i, 3 * i + 3)); // 截取第一个三位
if (false == "000".equals(a[i])) { // 用来避免这种情况1000000 = one million
// thousand only
if (i != 0) {
lm.insert(0, transThree(a[i]) + " " + parseMore(i) + " "); // :
// thousandmillionbillion
} else {
// 防止i=0时 在多加两个空格.
lm = new StringBuilder(transThree(a[i]));
}
} else {
lm.append(transThree(a[i]));
}
}
String xs = ""; // 用来存放转换后小数部分
if (z > -1) {
xs = "AND CENTS " + transTwo(rstr) + " "; // 小数部分存在时转换小数
}
return lm.toString().trim() + " " + xs + "ONLY";
}
private static String parseFirst(String s) {
return NUMBER[Integer.parseInt(s.substring(s.length() - 1))];
}
private static String parseTeen(String s) {
return NUMBER_TEEN[Integer.parseInt(s) - 10];
}
private static String parseTen(String s) {
return NUMBER_TEN[Integer.parseInt(s.substring(0, 1)) - 1];
}
private static String parseMore(int i) {
return NUMBER_MORE[i];
}
// 两位
private static String transTwo(String s) {
String value;
// 判断位数
if (s.length() > 2) {
s = s.substring(0, 2);
} else if (s.length() < 2) {
s = "0" + s;
}
if (s.startsWith("0")) {// 07 - seven 是否小於10
value = parseFirst(s);
} else if (s.startsWith("1")) {// 17 seventeen 是否在10和20之间
value = parseTeen(s);
} else if (s.endsWith("0")) {// 是否在10与100之间的能被10整除的数
value = parseTen(s);
} else {
value = parseTen(s) + " " + parseFirst(s);
}
return value;
}
// 制作叁位的数
// s.length = 3
private static String transThree(String s) {
String value;
if (s.startsWith("0")) {// 是否小於100
value = transTwo(s.substring(1));
} else if ("00".equals(s.substring(1))) {// 是否被100整除
value = parseFirst(s.substring(0, 1)) + " HUNDRED";
} else {
value = parseFirst(s.substring(0, 1)) + " HUNDRED AND " + transTwo(s.substring(1));
}
return value;
}
}

Some files were not shown because too many files have changed in this diff Show More