mirror of
https://gitee.com/dromara/hutool.git
synced 2025-05-08 22:58:05 +08:00
add method
This commit is contained in:
parent
90cd958e37
commit
52fb6267a5
@ -11,6 +11,7 @@
|
||||
* 【core】 ClassScanner支持自定义ClassLoader
|
||||
* 【core】 修改错别字(pr#568@Github)
|
||||
* 【core】 增加DateUtil.parseCST方法(issue#570@Github)
|
||||
* 【core】 增加defaultIfEmpty方法
|
||||
|
||||
### Bug修复
|
||||
* 【all】 修复阶乘计算错误bug(issue#I12XE4@Gitee)
|
||||
|
@ -1389,6 +1389,20 @@ public class CollUtil {
|
||||
return collection == null || collection.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果给定集合为空,返回默认集合
|
||||
*
|
||||
* @param <T> 集合类型
|
||||
* @param <E> 集合元素类型
|
||||
* @param collection 集合
|
||||
* @param defaultCollection 默认数组
|
||||
* @return 非空(empty)的原集合或默认集合
|
||||
* @since 4.6.9
|
||||
*/
|
||||
public static <T extends Collection<E>, E> T defaultIfEmpty(T collection, T defaultCollection){
|
||||
return isEmpty(collection) ? defaultCollection : collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map是否为空
|
||||
*
|
||||
|
@ -34,26 +34,37 @@ import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.core.util.URLUtil;
|
||||
|
||||
/**
|
||||
* 路径监听器<br>
|
||||
* 路径监听器
|
||||
*
|
||||
* <p>
|
||||
* 监听器可监听目录或文件<br>
|
||||
* 如果监听的Path不存在,则递归创建空目录然后监听此空目录<br>
|
||||
* 递归监听目录时,并不会监听新创建的目录
|
||||
*
|
||||
* @author Looly
|
||||
*
|
||||
*/
|
||||
public class WatchMonitor extends Thread implements Closeable, Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 事件丢失 */
|
||||
/**
|
||||
* 事件丢失
|
||||
*/
|
||||
public static final WatchEvent.Kind<?> OVERFLOW = StandardWatchEventKinds.OVERFLOW;
|
||||
/** 修改事件 */
|
||||
/**
|
||||
* 修改事件
|
||||
*/
|
||||
public static final WatchEvent.Kind<?> ENTRY_MODIFY = StandardWatchEventKinds.ENTRY_MODIFY;
|
||||
/** 创建事件 */
|
||||
/**
|
||||
* 创建事件
|
||||
*/
|
||||
public static final WatchEvent.Kind<?> ENTRY_CREATE = StandardWatchEventKinds.ENTRY_CREATE;
|
||||
/** 删除事件 */
|
||||
/**
|
||||
* 删除事件
|
||||
*/
|
||||
public static final WatchEvent.Kind<?> ENTRY_DELETE = StandardWatchEventKinds.ENTRY_DELETE;
|
||||
/** 全部事件 */
|
||||
/**
|
||||
* 全部事件
|
||||
*/
|
||||
public static final WatchEvent.Kind<?>[] EVENTS_ALL = {//
|
||||
OVERFLOW, //事件丢失
|
||||
ENTRY_MODIFY, //修改
|
||||
@ -61,29 +72,47 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
|
||||
ENTRY_DELETE //删除
|
||||
};
|
||||
|
||||
/** 监听路径,必须为目录 */
|
||||
/**
|
||||
* 监听路径,必须为目录
|
||||
*/
|
||||
private Path path;
|
||||
/** 递归目录的最大深度,当小于1时不递归下层目录 */
|
||||
/**
|
||||
* 递归目录的最大深度,当小于1时不递归下层目录
|
||||
*/
|
||||
private int maxDepth;
|
||||
/** 监听的文件,对于单文件监听不为空 */
|
||||
/**
|
||||
* 监听的文件,对于单文件监听不为空
|
||||
*/
|
||||
private Path filePath;
|
||||
|
||||
/** 监听服务 */
|
||||
/**
|
||||
* 监听服务
|
||||
*/
|
||||
private WatchService watchService;
|
||||
/** 监听器 */
|
||||
/**
|
||||
* 监听器
|
||||
*/
|
||||
private Watcher watcher;
|
||||
/** 监听事件列表 */
|
||||
/**
|
||||
* 监听事件列表
|
||||
*/
|
||||
private WatchEvent.Kind<?>[] events;
|
||||
|
||||
/** 监听是否已经关闭 */
|
||||
/**
|
||||
* 监听是否已经关闭
|
||||
*/
|
||||
private boolean isClosed;
|
||||
|
||||
/** WatchKey 和 Path的对应表 */
|
||||
/**
|
||||
* WatchKey 和 Path的对应表
|
||||
*/
|
||||
private Map<WatchKey, Path> watchKeyPathMap = new HashMap<>();
|
||||
|
||||
//------------------------------------------------------ Static method start
|
||||
|
||||
/**
|
||||
* 创建并初始化监听
|
||||
*
|
||||
* @param url URL
|
||||
* @param events 监听的事件列表
|
||||
* @return 监听对象
|
||||
@ -94,6 +123,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
|
||||
|
||||
/**
|
||||
* 创建并初始化监听
|
||||
*
|
||||
* @param url URL
|
||||
* @param events 监听的事件列表
|
||||
* @param maxDepth 当监听目录时,监听目录的最大深度,当设置值为1(或小于1)时,表示不递归监听子目录
|
||||
@ -105,6 +135,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
|
||||
|
||||
/**
|
||||
* 创建并初始化监听
|
||||
*
|
||||
* @param uri URI
|
||||
* @param events 监听的事件列表
|
||||
* @return 监听对象
|
||||
@ -115,6 +146,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
|
||||
|
||||
/**
|
||||
* 创建并初始化监听
|
||||
*
|
||||
* @param uri URI
|
||||
* @param events 监听的事件列表
|
||||
* @param maxDepth 当监听目录时,监听目录的最大深度,当设置值为1(或小于1)时,表示不递归监听子目录
|
||||
@ -126,6 +158,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
|
||||
|
||||
/**
|
||||
* 创建并初始化监听
|
||||
*
|
||||
* @param file 文件
|
||||
* @param events 监听的事件列表
|
||||
* @return 监听对象
|
||||
@ -136,6 +169,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
|
||||
|
||||
/**
|
||||
* 创建并初始化监听
|
||||
*
|
||||
* @param file 文件
|
||||
* @param events 监听的事件列表
|
||||
* @param maxDepth 当监听目录时,监听目录的最大深度,当设置值为1(或小于1)时,表示不递归监听子目录
|
||||
@ -147,6 +181,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
|
||||
|
||||
/**
|
||||
* 创建并初始化监听
|
||||
*
|
||||
* @param path 路径
|
||||
* @param events 监听的事件列表
|
||||
* @return 监听对象
|
||||
@ -157,6 +192,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
|
||||
|
||||
/**
|
||||
* 创建并初始化监听
|
||||
*
|
||||
* @param path 路径
|
||||
* @param events 监听的事件列表
|
||||
* @param maxDepth 当监听目录时,监听目录的最大深度,当设置值为1(或小于1)时,表示不递归监听子目录
|
||||
@ -168,6 +204,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
|
||||
|
||||
/**
|
||||
* 创建并初始化监听
|
||||
*
|
||||
* @param path 路径
|
||||
* @param events 监听事件列表
|
||||
* @return 监听对象
|
||||
@ -178,6 +215,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
|
||||
|
||||
/**
|
||||
* 创建并初始化监听
|
||||
*
|
||||
* @param path 路径
|
||||
* @param events 监听事件列表
|
||||
* @param maxDepth 当监听目录时,监听目录的最大深度,当设置值为1(或小于1)时,表示不递归监听子目录
|
||||
@ -188,8 +226,10 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
|
||||
}
|
||||
|
||||
//--------- createAll
|
||||
|
||||
/**
|
||||
* 创建并初始化监听,监听所有事件
|
||||
*
|
||||
* @param uri URI
|
||||
* @param watcher {@link Watcher}
|
||||
* @return {@link WatchMonitor}
|
||||
@ -200,6 +240,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
|
||||
|
||||
/**
|
||||
* 创建并初始化监听,监听所有事件
|
||||
*
|
||||
* @param url URL
|
||||
* @param watcher {@link Watcher}
|
||||
* @return {@link WatchMonitor}
|
||||
@ -214,6 +255,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
|
||||
|
||||
/**
|
||||
* 创建并初始化监听,监听所有事件
|
||||
*
|
||||
* @param file 被监听文件
|
||||
* @param watcher {@link Watcher}
|
||||
* @return {@link WatchMonitor}
|
||||
@ -224,6 +266,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
|
||||
|
||||
/**
|
||||
* 创建并初始化监听,监听所有事件
|
||||
*
|
||||
* @param path 路径
|
||||
* @param watcher {@link Watcher}
|
||||
* @return {@link WatchMonitor}
|
||||
@ -234,6 +277,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
|
||||
|
||||
/**
|
||||
* 创建并初始化监听,监听所有事件
|
||||
*
|
||||
* @param path 路径
|
||||
* @param watcher {@link Watcher}
|
||||
* @return {@link WatchMonitor}
|
||||
@ -246,8 +290,10 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
|
||||
//------------------------------------------------------ Static method end
|
||||
|
||||
//------------------------------------------------------ Constructor method start
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param file 文件
|
||||
* @param events 监听的事件列表
|
||||
*/
|
||||
@ -257,6 +303,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param path 字符串路径
|
||||
* @param events 监听的事件列表
|
||||
*/
|
||||
@ -266,6 +313,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param path 字符串路径
|
||||
* @param events 监听事件列表
|
||||
*/
|
||||
@ -307,6 +355,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
|
||||
public void init() throws WatchException {
|
||||
//获取目录或文件路径
|
||||
if (false == Files.exists(this.path, LinkOption.NOFOLLOW_LINKS)) {
|
||||
// 不存在的路径
|
||||
final Path lastPathEle = FileUtil.getLastPathEle(this.path);
|
||||
if (null != lastPathEle) {
|
||||
final String lastPathEleStr = lastPathEle.toString();
|
||||
@ -324,6 +373,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
} else if (Files.isRegularFile(this.path, LinkOption.NOFOLLOW_LINKS)) {
|
||||
// 文件路径
|
||||
this.filePath = this.path;
|
||||
this.path = this.filePath.getParent();
|
||||
}
|
||||
@ -364,6 +414,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
|
||||
|
||||
/**
|
||||
* 开始监听事件,阻塞当前进程
|
||||
*
|
||||
* @param watcher 监听
|
||||
* @throws WatchException 监听异常,如果监听关闭抛出此异常
|
||||
*/
|
||||
@ -371,38 +422,13 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
|
||||
if (isClosed) {
|
||||
throw new WatchException("Watch Monitor is closed !");
|
||||
}
|
||||
|
||||
// 按照层级注册路径及其子路径
|
||||
registerPath();
|
||||
// log.debug("Start watching path: [{}]", this.path);
|
||||
|
||||
while (false == isClosed) {
|
||||
WatchKey wk;
|
||||
try {
|
||||
wk = watchService.take();
|
||||
} catch (InterruptedException | ClosedWatchServiceException e) {
|
||||
// log.warn(e);
|
||||
return;
|
||||
}
|
||||
|
||||
final Path currentPath = watchKeyPathMap.get(wk);
|
||||
WatchEvent.Kind<?> kind;
|
||||
for (WatchEvent<?> event : wk.pollEvents()) {
|
||||
kind = event.kind();
|
||||
if(null != this.filePath && false == this.filePath.endsWith(event.context().toString())){
|
||||
// log.debug("[{}] is not fit for [{}], pass it.", event.context(), this.filePath.getFileName());
|
||||
continue;
|
||||
}
|
||||
|
||||
if(kind == StandardWatchEventKinds.ENTRY_CREATE){
|
||||
watcher.onCreate(event, currentPath);
|
||||
}else if(kind == StandardWatchEventKinds.ENTRY_MODIFY){
|
||||
watcher.onModify(event, currentPath);
|
||||
}else if(kind == StandardWatchEventKinds.ENTRY_DELETE){
|
||||
watcher.onDelete(event, currentPath);
|
||||
}else if(kind == StandardWatchEventKinds.OVERFLOW){
|
||||
watcher.onOverflow(event, currentPath);
|
||||
}
|
||||
}
|
||||
wk.reset();
|
||||
doTakeAndWatch(watcher);
|
||||
}
|
||||
}
|
||||
|
||||
@ -434,6 +460,45 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
|
||||
}
|
||||
|
||||
//------------------------------------------------------ private method start
|
||||
|
||||
/**
|
||||
* 执行事件获取并处理
|
||||
*
|
||||
* @param watcher {@link Watcher}
|
||||
*/
|
||||
private void doTakeAndWatch(Watcher watcher){
|
||||
WatchKey wk;
|
||||
try {
|
||||
wk = watchService.take();
|
||||
} catch (InterruptedException | ClosedWatchServiceException e) {
|
||||
// 用户中断
|
||||
return;
|
||||
}
|
||||
|
||||
final Path currentPath = watchKeyPathMap.get(wk);
|
||||
WatchEvent.Kind<?> kind;
|
||||
for (WatchEvent<?> event : wk.pollEvents()) {
|
||||
kind = event.kind();
|
||||
|
||||
// 如果监听文件,检查当前事件是否与所监听文件关联
|
||||
if (null != this.filePath && false == this.filePath.endsWith(event.context().toString())) {
|
||||
// log.debug("[{}] is not fit for [{}], pass it.", event.context(), this.filePath.getFileName());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (kind == StandardWatchEventKinds.ENTRY_CREATE) {
|
||||
watcher.onCreate(event, currentPath);
|
||||
} else if (kind == StandardWatchEventKinds.ENTRY_MODIFY) {
|
||||
watcher.onModify(event, currentPath);
|
||||
} else if (kind == StandardWatchEventKinds.ENTRY_DELETE) {
|
||||
watcher.onDelete(event, currentPath);
|
||||
} else if (kind == StandardWatchEventKinds.OVERFLOW) {
|
||||
watcher.onOverflow(event, currentPath);
|
||||
}
|
||||
}
|
||||
wk.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册监听路径
|
||||
*/
|
||||
@ -443,13 +508,13 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
|
||||
|
||||
/**
|
||||
* 将指定路径加入到监听中
|
||||
*
|
||||
* @param path 路径
|
||||
* @param maxDepth 递归下层目录的最大深度
|
||||
* @return {@link WatchKey}
|
||||
*/
|
||||
private void registerPath(Path path, int maxDepth) {
|
||||
try {
|
||||
final WatchKey key = path.register(watchService, ArrayUtil.isEmpty(this.events) ? EVENTS_ALL : this.events);
|
||||
final WatchKey key = path.register(this.watchService, ArrayUtil.defaultIfEmpty(this.events, EVENTS_ALL));
|
||||
watchKeyPathMap.put(key, path);
|
||||
if (maxDepth > 1) {
|
||||
//遍历所有子目录并加入监听
|
||||
|
@ -5,11 +5,13 @@ import java.nio.file.WatchEvent;
|
||||
|
||||
/**
|
||||
* 观察者(监视器)
|
||||
*
|
||||
* @author Looly
|
||||
*/
|
||||
public interface Watcher {
|
||||
/**
|
||||
* 文件创建时执行的方法
|
||||
*
|
||||
* @param event 事件
|
||||
* @param currentPath 事件发生的当前Path路径
|
||||
*/
|
||||
@ -18,6 +20,7 @@ public interface Watcher {
|
||||
/**
|
||||
* 文件修改时执行的方法<br>
|
||||
* 文件修改可能触发多次
|
||||
*
|
||||
* @param event 事件
|
||||
* @param currentPath 事件发生的当前Path路径
|
||||
*/
|
||||
@ -25,6 +28,7 @@ public interface Watcher {
|
||||
|
||||
/**
|
||||
* 文件删除时执行的方法
|
||||
*
|
||||
* @param event 事件
|
||||
* @param currentPath 事件发生的当前Path路径
|
||||
*/
|
||||
@ -32,6 +36,7 @@ public interface Watcher {
|
||||
|
||||
/**
|
||||
* 事件丢失或出错时执行的方法
|
||||
*
|
||||
* @param event 事件
|
||||
* @param currentPath 事件发生的当前Path路径
|
||||
*/
|
||||
|
@ -1,19 +1,7 @@
|
||||
package cn.hutool.core.map;
|
||||
|
||||
import java.util.AbstractMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
@ -73,6 +61,21 @@ public class MapUtil {
|
||||
return (null == set) ? Collections.<K, V>emptyMap() : set;
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果给定Map为空,返回默认Map
|
||||
*
|
||||
* @param <T> 集合类型
|
||||
* @param <K> 键类型
|
||||
* @param <V> 值类型
|
||||
* @param map Map
|
||||
* @param defaultMap 默认Map
|
||||
* @return 非空(empty)的原Map或默认Map
|
||||
* @since 4.6.9
|
||||
*/
|
||||
public static <T extends Map<K, V>, K, V> T defaultIfEmpty(T map, T defaultMap){
|
||||
return isEmpty(map) ? defaultMap : map;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------- new HashMap
|
||||
/**
|
||||
* 新建一个HashMap
|
||||
|
@ -33,6 +33,19 @@ public class ArrayUtil {
|
||||
return array == null || array.length == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果给定数组为空,返回默认数组
|
||||
*
|
||||
* @param <T> 数组元素类型
|
||||
* @param array 数组
|
||||
* @param defaultArray 默认数组
|
||||
* @return 非空(empty)的原数组或默认数组
|
||||
* @since 4.6.9
|
||||
*/
|
||||
public static <T> T[] defaultIfEmpty(T[] array, T[] defaultArray){
|
||||
return isEmpty(array) ? defaultArray : array;
|
||||
}
|
||||
|
||||
/**
|
||||
* 数组是否为空<br>
|
||||
* 此方法会匹配单一对象,如果此对象为{@code null}则返回true<br>
|
||||
|
Loading…
Reference in New Issue
Block a user