java.lang.IllegalStateException:Iterator已经获得

时间:2014-08-01 21:59:00

标签: java java-8

我修改了这段代码,在一个目录中执行了几项任务:

public class HDDSerialNumber
{

    public void getHDDSerialNumber() throws IOException
    {
        try (DirectoryStream<Path> ds = Files.newDirectoryStream(Paths.get("/sys/block"), "sd*"))
        {
            // Get HDD Model
            StreamSupport.stream(ds.spliterator(), false)
                .map(p -> p.resolve("device/model")).flatMap(wrap(Files::lines))
                .forEach(System.out::println);

            // Get HDD Vendor
            StreamSupport.stream(ds.spliterator(), false)
                .map(p -> p.resolve("device/vendor")).flatMap(wrap(Files::lines))
                .forEach(System.out::println);

            // Get HDD Vendor
            StreamSupport.stream(ds.spliterator(), false)
                .map(p -> p.resolve("device/state")).flatMap(wrap(Files::lines))
                .forEach(System.out::println);
        }
    }

    static <T, R> Function<T, R> wrap(IOFunction<T, R> f)
    {
        return t ->
        {
            try
            {
                return f.apply(t);
            }
            catch (IOException ex)
            {
                throw new UncheckedIOException(ex);
            }
        };
    }

    interface IOFunction<T, R>
    {
        R apply(T in) throws IOException;
    }
}

但是当我运行代码时,我得到了这个错误堆栈:

run:
ST320LT012-9WS14
Exception in thread "main" java.lang.IllegalStateException: Iterator already obtained
    at sun.nio.fs.UnixDirectoryStream.iterator(UnixDirectoryStream.java:118)
    at sun.nio.fs.UnixSecureDirectoryStream.iterator(UnixSecureDirectoryStream.java:73)
    at java.lang.Iterable.spliterator(Iterable.java:101)
    at hardware.HDDSerialNumber.getHDDSerialNumber(HDDSerialNumber.java:25)
    at hardware.Hardware.main(Hardware.java:12)
Java Result: 1

你能帮我解决一下代码吗?我想已经获得的Iterator在这个例子中只能使用一次,但我不知道如何解决这个问题。

1 个答案:

答案 0 :(得分:6)

  

虽然DirectoryStream扩展了Iterable,但它不是通用的Iterable,因为它只支持一个Iterator;调用iterator方法来获取第二个或后续的迭代器会抛出IllegalStateException。

Source

IterableFiles.newDirectoryStream实现DirectoryStream)返回的Iterable的迭代器只能使用一次。您可以通过分别为正在创建的3个流中的每个流调用Files.newDirectoryStream来解决此问题。

不是创建一个DirectoryStream<Path> ds = Files.newDirectoryStream(Paths.get("/sys/block"), "sd*");并在所有3个StreamSupport.stream调用中使用它,而是创建3个DirectoryStream<Path>

示例:

public void getHDDSerialNumber() throws IOException
{
    try (DirectoryStream<Path> ds = Files.newDirectoryStream(Paths.get("/sys/block"), "sd*"))
    {
        // Get HDD Model
        StreamSupport.stream(ds.spliterator(), false)
            .map(p -> p.resolve("device/model")).flatMap(wrap(Files::lines))
            .forEach(System.out::println);
    }
    try (DirectoryStream<Path> ds = Files.newDirectoryStream(Paths.get("/sys/block"), "sd*"))
    {
        // Get HDD Vendor
        StreamSupport.stream(ds.spliterator(), false)
            .map(p -> p.resolve("device/vendor")).flatMap(wrap(Files::lines))
            .forEach(System.out::println);
    }
    try (DirectoryStream<Path> ds = Files.newDirectoryStream(Paths.get("/sys/block"), "sd*"))
    {
        // Get HDD State
        StreamSupport.stream(ds.spliterator(), false)
            .map(p -> p.resolve("device/state")).flatMap(wrap(Files::lines))
            .forEach(System.out::println);
    }
}

编辑:

如果你想处理一个在不中断程序执行的情况下不存在的文件的情况,请抓住在这种情况下抛出的异常。

例如:

    try (DirectoryStream<Path> ds = Files.newDirectoryStream(Paths.get("/sys/block"), "sd*"))
    {
        // Get HDD State
        StreamSupport.stream(ds.spliterator(), false)
            .map(p -> p.resolve("device/state"))
            .flatMap(wrap(path - > try {
                                     return Files.lines(path);
                                   } catch (IOException ioEx) {
                                     return Stream.empty();
                                   }))
            .forEach(System.out::println);
    }

这将捕获异常并返回一个空的Stream。