Browse Source

add method

Looly 6 years ago
parent
commit
52fb6267a5

+ 1 - 0
CHANGELOG.md

@@ -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)

+ 14 - 0
hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java

@@ -1390,6 +1390,20 @@ public class CollUtil {
 	}
 
 	/**
+	 * 如果给定集合为空,返回默认集合
+	 *
+	 * @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是否为空
 	 * 
 	 * @param map 集合

+ 208 - 143
hutool-core/src/main/java/cn/hutool/core/io/watch/WatchMonitor.java

@@ -34,245 +34,293 @@ import cn.hutool.core.util.StrUtil;
 import cn.hutool.core.util.URLUtil;
 
 /**
- * 路径监听器<br>
+ * 路径监听器
+ *
+ * <p>
  * 监听器可监听目录或文件<br>
  * 如果监听的Path不存在,则递归创建空目录然后监听此空目录<br>
  * 递归监听目录时,并不会监听新创建的目录
- * 
- * @author Looly
  *
+ * @author Looly
  */
-public class WatchMonitor extends Thread implements Closeable, Serializable{
+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,        //事件丢失
+			OVERFLOW,      //事件丢失
 			ENTRY_MODIFY, //修改
 			ENTRY_CREATE,  //创建
 			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 url    URL
 	 * @param events 监听的事件列表
 	 * @return 监听对象
 	 */
-	public static WatchMonitor create(URL url, WatchEvent.Kind<?>... events){
+	public static WatchMonitor create(URL url, WatchEvent.Kind<?>... events) {
 		return create(url, 0, events);
 	}
-	
+
 	/**
 	 * 创建并初始化监听
-	 * @param url URL
-	 * @param events 监听的事件列表
+	 *
+	 * @param url      URL
+	 * @param events   监听的事件列表
 	 * @param maxDepth 当监听目录时,监听目录的最大深度,当设置值为1(或小于1)时,表示不递归监听子目录
 	 * @return 监听对象
 	 */
-	public static WatchMonitor create(URL url, int maxDepth, WatchEvent.Kind<?>... events){
+	public static WatchMonitor create(URL url, int maxDepth, WatchEvent.Kind<?>... events) {
 		return create(URLUtil.toURI(url), maxDepth, events);
 	}
-	
+
 	/**
 	 * 创建并初始化监听
-	 * @param uri URI
+	 *
+	 * @param uri    URI
 	 * @param events 监听的事件列表
 	 * @return 监听对象
 	 */
-	public static WatchMonitor create(URI uri, WatchEvent.Kind<?>... events){
+	public static WatchMonitor create(URI uri, WatchEvent.Kind<?>... events) {
 		return create(uri, 0, events);
 	}
-	
+
 	/**
 	 * 创建并初始化监听
-	 * @param uri URI
-	 * @param events 监听的事件列表
+	 *
+	 * @param uri      URI
+	 * @param events   监听的事件列表
 	 * @param maxDepth 当监听目录时,监听目录的最大深度,当设置值为1(或小于1)时,表示不递归监听子目录
 	 * @return 监听对象
 	 */
-	public static WatchMonitor create(URI uri, int maxDepth, WatchEvent.Kind<?>... events){
+	public static WatchMonitor create(URI uri, int maxDepth, WatchEvent.Kind<?>... events) {
 		return create(Paths.get(uri), maxDepth, events);
 	}
-	
+
 	/**
 	 * 创建并初始化监听
-	 * @param file 文件
+	 *
+	 * @param file   文件
 	 * @param events 监听的事件列表
 	 * @return 监听对象
 	 */
-	public static WatchMonitor create(File file, WatchEvent.Kind<?>... events){
+	public static WatchMonitor create(File file, WatchEvent.Kind<?>... events) {
 		return create(file, 0, events);
 	}
-	
+
 	/**
 	 * 创建并初始化监听
-	 * @param file 文件
-	 * @param events 监听的事件列表
+	 *
+	 * @param file     文件
+	 * @param events   监听的事件列表
 	 * @param maxDepth 当监听目录时,监听目录的最大深度,当设置值为1(或小于1)时,表示不递归监听子目录
 	 * @return 监听对象
 	 */
-	public static WatchMonitor create(File file, int maxDepth, WatchEvent.Kind<?>... events){
+	public static WatchMonitor create(File file, int maxDepth, WatchEvent.Kind<?>... events) {
 		return create(file.toPath(), maxDepth, events);
 	}
-	
+
 	/**
 	 * 创建并初始化监听
-	 * @param path 路径
+	 *
+	 * @param path   路径
 	 * @param events 监听的事件列表
 	 * @return 监听对象
 	 */
-	public static WatchMonitor create(String path, WatchEvent.Kind<?>... events){
+	public static WatchMonitor create(String path, WatchEvent.Kind<?>... events) {
 		return create(path, 0, events);
 	}
-	
+
 	/**
 	 * 创建并初始化监听
-	 * @param path 路径
-	 * @param events 监听的事件列表
+	 *
+	 * @param path     路径
+	 * @param events   监听的事件列表
 	 * @param maxDepth 当监听目录时,监听目录的最大深度,当设置值为1(或小于1)时,表示不递归监听子目录
 	 * @return 监听对象
 	 */
-	public static WatchMonitor create(String path, int maxDepth, WatchEvent.Kind<?>... events){
+	public static WatchMonitor create(String path, int maxDepth, WatchEvent.Kind<?>... events) {
 		return create(Paths.get(path), maxDepth, events);
 	}
-	
+
 	/**
 	 * 创建并初始化监听
-	 * @param path 路径
+	 *
+	 * @param path   路径
 	 * @param events 监听事件列表
 	 * @return 监听对象
 	 */
-	public static WatchMonitor create(Path path, WatchEvent.Kind<?>... events){
+	public static WatchMonitor create(Path path, WatchEvent.Kind<?>... events) {
 		return create(path, 0, events);
 	}
-	
+
 	/**
 	 * 创建并初始化监听
-	 * @param path 路径
-	 * @param events 监听事件列表
+	 *
+	 * @param path     路径
+	 * @param events   监听事件列表
 	 * @param maxDepth 当监听目录时,监听目录的最大深度,当设置值为1(或小于1)时,表示不递归监听子目录
 	 * @return 监听对象
 	 */
-	public static WatchMonitor create(Path path, int maxDepth, WatchEvent.Kind<?>... events){
+	public static WatchMonitor create(Path path, int maxDepth, WatchEvent.Kind<?>... events) {
 		return new WatchMonitor(path, maxDepth, events);
 	}
-	
+
 	//--------- createAll
+
 	/**
 	 * 创建并初始化监听,监听所有事件
-	 * @param uri URI
+	 *
+	 * @param uri     URI
 	 * @param watcher {@link Watcher}
 	 * @return {@link WatchMonitor}
 	 */
-	public static WatchMonitor createAll(URI uri, Watcher watcher){
+	public static WatchMonitor createAll(URI uri, Watcher watcher) {
 		return createAll(Paths.get(uri), watcher);
 	}
-	
+
 	/**
 	 * 创建并初始化监听,监听所有事件
-	 * @param url URL
+	 *
+	 * @param url     URL
 	 * @param watcher {@link Watcher}
 	 * @return {@link WatchMonitor}
 	 */
-	public static WatchMonitor createAll(URL url, Watcher watcher){
+	public static WatchMonitor createAll(URL url, Watcher watcher) {
 		try {
 			return createAll(Paths.get(url.toURI()), watcher);
 		} catch (URISyntaxException e) {
 			throw new WatchException(e);
 		}
 	}
-	
+
 	/**
 	 * 创建并初始化监听,监听所有事件
-	 * @param file 被监听文件
+	 *
+	 * @param file    被监听文件
 	 * @param watcher {@link Watcher}
 	 * @return {@link WatchMonitor}
 	 */
-	public static WatchMonitor createAll(File file, Watcher watcher){
+	public static WatchMonitor createAll(File file, Watcher watcher) {
 		return createAll(file.toPath(), watcher);
 	}
-	
+
 	/**
 	 * 创建并初始化监听,监听所有事件
-	 * @param path 路径
+	 *
+	 * @param path    路径
 	 * @param watcher {@link Watcher}
 	 * @return {@link WatchMonitor}
 	 */
-	public static WatchMonitor createAll(String path, Watcher watcher){
+	public static WatchMonitor createAll(String path, Watcher watcher) {
 		return createAll(Paths.get(path), watcher);
 	}
-	
+
 	/**
 	 * 创建并初始化监听,监听所有事件
-	 * @param path 路径
+	 *
+	 * @param path    路径
 	 * @param watcher {@link Watcher}
 	 * @return {@link WatchMonitor}
 	 */
-	public static WatchMonitor createAll(Path path, Watcher watcher){
+	public static WatchMonitor createAll(Path path, Watcher watcher) {
 		final WatchMonitor watchMonitor = create(path, EVENTS_ALL);
 		watchMonitor.setWatcher(watcher);
 		return watchMonitor;
 	}
 	//------------------------------------------------------ Static method end
-	
+
 	//------------------------------------------------------ Constructor method start
+
 	/**
 	 * 构造
-	 * @param file 文件
+	 *
+	 * @param file   文件
 	 * @param events 监听的事件列表
 	 */
 	public WatchMonitor(File file, WatchEvent.Kind<?>... events) {
 		this(file.toPath(), events);
 	}
-	
+
 	/**
 	 * 构造
-	 * @param path 字符串路径
+	 *
+	 * @param path   字符串路径
 	 * @param events 监听的事件列表
 	 */
 	public WatchMonitor(String path, WatchEvent.Kind<?>... events) {
 		this(Paths.get(path), events);
 	}
-	
+
 	/**
 	 * 构造
-	 * @param path 字符串路径
+	 *
+	 * @param path   字符串路径
 	 * @param events 监听事件列表
 	 */
 	public WatchMonitor(Path path, WatchEvent.Kind<?>... events) {
 		this(path, 0, events);
 	}
-	
+
 	/**
 	 * 构造<br>
 	 * 例如设置:
@@ -281,10 +329,10 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
 	 * maxDepth = 2 表示监听当前目录以及下层目录
 	 * maxDepth = 3 表示监听当前目录以及下层
 	 * </pre>
-	 * 
-	 * @param path 字符串路径
+	 *
+	 * @param path     字符串路径
 	 * @param maxDepth 递归目录的最大深度,当小于2时不递归下层目录
-	 * @param events 监听事件列表
+	 * @param events   监听事件列表
 	 */
 	public WatchMonitor(Path path, int maxDepth, WatchEvent.Kind<?>... events) {
 		this.path = path;
@@ -293,7 +341,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
 		this.init();
 	}
 	//------------------------------------------------------ Constructor method end
-	
+
 	/**
 	 * 初始化<br>
 	 * 初始化包括:
@@ -301,111 +349,89 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
 	 * 1、解析传入的路径,判断其为目录还是文件
 	 * 2、创建{@link WatchService} 对象
 	 * </pre>
-	 * 
+	 *
 	 * @throws WatchException 监听异常,IO异常时抛出此异常
 	 */
-	public void init() throws WatchException{
+	public void init() throws WatchException {
 		//获取目录或文件路径
-		if(false ==Files.exists(this.path, LinkOption.NOFOLLOW_LINKS)) {
+		if (false == Files.exists(this.path, LinkOption.NOFOLLOW_LINKS)) {
+			// 不存在的路径
 			final Path lastPathEle = FileUtil.getLastPathEle(this.path);
-			if(null != lastPathEle) {
+			if (null != lastPathEle) {
 				final String lastPathEleStr = lastPathEle.toString();
 				//带有点表示有扩展名,按照未创建的文件对待。Linux下.d的为目录,排除之
-				if(StrUtil.contains(lastPathEleStr, StrUtil.C_DOT) && false ==StrUtil.endWithIgnoreCase(lastPathEleStr, ".d")) {
+				if (StrUtil.contains(lastPathEleStr, StrUtil.C_DOT) && false == StrUtil.endWithIgnoreCase(lastPathEleStr, ".d")) {
 					this.filePath = this.path;
 					this.path = this.filePath.getParent();
 				}
 			}
-			
+
 			//创建不存在的目录或父目录
 			try {
 				Files.createDirectories(this.path);
 			} catch (IOException e) {
 				throw new IORuntimeException(e);
 			}
-		}else if(Files.isRegularFile(this.path, LinkOption.NOFOLLOW_LINKS)){
+		} else if (Files.isRegularFile(this.path, LinkOption.NOFOLLOW_LINKS)) {
+			// 文件路径
 			this.filePath = this.path;
 			this.path = this.filePath.getParent();
 		}
-		
+
 		//初始化监听
 		try {
 			watchService = FileSystems.getDefault().newWatchService();
 		} catch (IOException e) {
 			throw new WatchException(e);
 		}
-		
+
 		isClosed = false;
 	}
-	
+
 	/**
 	 * 设置监听<br>
 	 * 多个监听请使用{@link WatcherChain}
-	 * 
+	 *
 	 * @param watcher 监听
 	 * @return {@link WatchMonitor}
 	 */
-	public WatchMonitor setWatcher(Watcher watcher){
+	public WatchMonitor setWatcher(Watcher watcher) {
 		this.watcher = watcher;
 		return this;
 	}
-	
+
 	@Override
 	public void run() {
 		watch();
 	}
-	
+
 	/**
 	 * 开始监听事件,阻塞当前进程
 	 */
-	public void watch(){
+	public void watch() {
 		watch(this.watcher);
 	}
-	
+
 	/**
 	 * 开始监听事件,阻塞当前进程
+	 *
 	 * @param watcher 监听
 	 * @throws WatchException 监听异常,如果监听关闭抛出此异常
 	 */
-	public void watch(Watcher watcher) throws WatchException{
-		if(isClosed){
+	public void watch(Watcher watcher) throws WatchException {
+		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);
 		}
 	}
-	
+
 	/**
 	 * 当监听目录时,监听目录的最大深度<br>
 	 * 当设置值为1(或小于1)时,表示不递归监听子目录<br>
@@ -415,7 +441,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
 	 * maxDepth = 2 表示监听当前目录以及下层目录
 	 * maxDepth = 3 表示监听当前目录以及下层
 	 * </pre>
-	 * 
+	 *
 	 * @param maxDepth 最大深度,当设置值为1(或小于1)时,表示不递归监听子目录,监听所有子目录请传{@link Integer#MAX_VALUE}
 	 * @return this
 	 */
@@ -423,37 +449,76 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
 		this.maxDepth = maxDepth;
 		return this;
 	}
-	
+
 	/**
 	 * 关闭监听
 	 */
 	@Override
-	public void close(){
+	public void close() {
 		isClosed = true;
 		IoUtil.close(watchService);
 	}
-	
+
 	//------------------------------------------------------ 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();
+	}
+
 	/**
 	 * 注册监听路径
 	 */
 	private void registerPath() {
 		registerPath(this.path, (null != this.filePath) ? 0 : this.maxDepth);
 	}
-	
+
 	/**
 	 * 将指定路径加入到监听中
-	 * @param path 路径
+	 *
+	 * @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) {
+			if (maxDepth > 1) {
 				//遍历所有子目录并加入监听
-				Files.walkFileTree(path, EnumSet.noneOf(FileVisitOption.class), maxDepth, new SimpleFileVisitor<Path>(){
+				Files.walkFileTree(path, EnumSet.noneOf(FileVisitOption.class), maxDepth, new SimpleFileVisitor<Path>() {
 					@Override
 					public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
 						registerPath(dir, 0);//继续添加目录
@@ -462,7 +527,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
 				});
 			}
 		} catch (IOException e) {
-			if(e instanceof AccessDeniedException) {
+			if (e instanceof AccessDeniedException) {
 				//对于禁止访问的目录,跳过监听
 				return;
 			}

+ 12 - 7
hutool-core/src/main/java/cn/hutool/core/io/watch/Watcher.java

@@ -5,34 +5,39 @@ import java.nio.file.WatchEvent;
 
 /**
  * 观察者(监视器)
+ *
  * @author Looly
  */
 public interface Watcher {
 	/**
 	 * 文件创建时执行的方法
-	 * @param event 事件
+	 *
+	 * @param event       事件
 	 * @param currentPath 事件发生的当前Path路径
 	 */
 	void onCreate(WatchEvent<?> event, Path currentPath);
-	
+
 	/**
 	 * 文件修改时执行的方法<br>
 	 * 文件修改可能触发多次
-	 * @param event 事件
+	 *
+	 * @param event       事件
 	 * @param currentPath 事件发生的当前Path路径
 	 */
 	void onModify(WatchEvent<?> event, Path currentPath);
-	
+
 	/**
 	 * 文件删除时执行的方法
-	 * @param event 事件
+	 *
+	 * @param event       事件
 	 * @param currentPath 事件发生的当前Path路径
 	 */
 	void onDelete(WatchEvent<?> event, Path currentPath);
-	
+
 	/**
 	 * 事件丢失或出错时执行的方法
-	 * @param event 事件
+	 *
+	 * @param event       事件
 	 * @param currentPath 事件发生的当前Path路径
 	 */
 	void onOverflow(WatchEvent<?> event, Path currentPath);

+ 16 - 13
hutool-core/src/main/java/cn/hutool/core/map/MapUtil.java

@@ -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

+ 13 - 0
hutool-core/src/main/java/cn/hutool/core/util/ArrayUtil.java

@@ -34,6 +34,19 @@ public class ArrayUtil {
 	}
 
 	/**
+	 * 如果给定数组为空,返回默认数组
+	 *
+	 * @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>
 	 * 如果此对象为非数组,理解为此对象为数组的第一个元素,则返回false<br>