【问题标题】:java.lang.IllegalStateException: Iterator already obtainedjava.lang.IllegalStateException:已获得迭代器
【发布时间】:2014-08-01 21:58:59
【问题描述】:

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

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

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

【问题讨论】:

    标签: java java-8


    【解决方案1】:

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

    (Source)

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

    与其创建一个DirectoryStream&lt;Path&gt; ds = Files.newDirectoryStream(Paths.get("/sys/block"), "sd*"); 并在所有3 个StreamSupport.stream 调用中使用它,不如创建3 个DirectoryStream&lt;Path&gt;

    例子:

    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);
        }
    

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

    【讨论】:

    • 非常好!我可以问额外的问题吗?如果找不到文件,我会得到 java.nio.file.NoSuchFileException 我怎样才能跳过文件而不中断程序执行?
    • @PeterPenzov 我相信你可以用 try 块包装导致异常的调用并捕获异常。我不确定在哪里引发了异常。我假设在mapflatMap 中。例如,如果它在map 中抛出,则执行.map(p -&gt; try {p.resolve("..");}catch(NoSuchFileException ex){})
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-09
    • 2016-06-13
    • 2013-11-05
    • 2016-12-24
    • 2017-03-25
    相关资源
    最近更新 更多