遍历目录时遇UnsupportedOperationException及ConcurrentModificationException问题求助
解决目录遍历中的两个异常问题
让我一步步帮你捋清楚问题根源,再给你几个可靠的实现方案:
第一个异常:UnsupportedOperationException
你一开始的代码里,Arrays.asList(dircList)返回的并不是普通的ArrayList——它是一个固定大小的List包装类,直接映射了底层数组,不支持添加/删除元素的操作。所以当你调用l.addAll(x)的时候,就会抛出这个不支持操作的异常。
哪怕你后来改成List x = new ArrayList(Arrays.asList(c.listFiles())),但外层的l还是Arrays.asList返回的固定大小列表,所以依然会报错。
第二个异常:ConcurrentModificationException
你改用Queue之后,用for (File c : l)这种foreach遍历,本质上是用队列的迭代器在遍历。而Java集合的迭代器有快速失败机制:如果在遍历过程中修改了集合的结构(比如addAll),迭代器就会检测到,直接抛出这个异常,防止出现不一致的遍历结果。
靠谱的解决方案
下面给你三种可行的实现方式,按需选择:
方案1:用while循环操作队列(最稳妥的迭代方式)
放弃foreach,改用poll()方法逐个取出队列元素,这样在循环中添加新元素就不会触发并发修改异常:
import java.io.File; import java.util.HashSet; import java.util.LinkedList; import java.util.Queue; import java.util.Set; public static Set<File> iterateDirectory(String dir){ Set<File> children = new HashSet<>(); // 建议用System.getProperty获取用户目录,兼容性更好 File dirc = new File(System.getProperty("user.home") + dir); File[] dircList = dirc.listFiles(); // 处理目录不存在、无权限等情况,避免空指针 if (dircList == null) { return children; } Queue<File> queue = new LinkedList<>(Arrays.asList(dircList)); File currentFile; // 循环取出队列头部元素,直到队列为空 while ((currentFile = queue.poll()) != null) { if(currentFile.isDirectory()){ File[] subFiles = currentFile.listFiles(); if (subFiles != null && subFiles.length > 0) { queue.addAll(Arrays.asList(subFiles)); } } else { children.add(currentFile); } } return children; }
方案2:递归遍历(代码更简洁)
如果你的目录深度不会特别大(不会触发栈溢出),递归实现会更直观:
import java.io.File; import java.util.HashSet; import java.util.Set; public static Set<File> iterateDirectory(String dir){ Set<File> children = new HashSet<>(); File dirc = new File(System.getProperty("user.home") + dir); iterateDirRecursive(dirc, children); return children; } // 递归遍历子目录的私有方法 private static void iterateDirRecursive(File currentDir, Set<File> fileSet){ File[] files = currentDir.listFiles(); if (files == null) { return; } for (File file : files) { if (file.isDirectory()) { iterateDirRecursive(file, fileSet); } else { fileSet.add(file); } } }
方案3:Java 8+的Files.walk(最简洁的标准库实现)
从Java 8开始,NIO提供了专门的文件遍历API,一行代码搞定,还自带异常处理:
import java.io.File; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashSet; import java.util.Set; import java.util.stream.Collectors; public static Set<File> iterateDirectory(String dir){ Path startPath = Paths.get(System.getProperty("user.home"), dir); try { return Files.walk(startPath) .filter(Files::isRegularFile) // 只收集普通文件 .map(Path::toFile) .collect(Collectors.toSet()); } catch (Exception e) { e.printStackTrace(); return new HashSet<>(); } }
这个方案不仅代码最少,还能自动处理IO异常、符号链接(默认不跟随,可以通过参数调整),是Java 8+环境下的最优选择。
内容的提问来源于stack exchange,提问作者user12346306
相关产品推荐
相关产品推荐

