Using Optional.map() instead of Optional.ifPresent() to execute code that may throw an exception and returning any exceptions as the return value

huangapple 未分类评论54阅读模式
英文:

Using Optional.map() instead of Optional.ifPresent() to execute code that may throw an exception and returning any exceptions as the return value

问题

public void doSomething(File destDir, String classifier) throws IOException {
    Optional<URL> resourceRoot = introspectionService.getResourceRoot(pattern);

    try {
        resourceRoot.map(rootUrl -> {
            try {
                JarFile jarFile = (JarFile) rootUrl.getContent(); //this can throw IOException
                // ... snipped for brevity ...
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            return null;
        }).orElseThrow(() -> new IOException("Resource root URL not present."));
    } catch (RuntimeException e) {
        if (e.getCause() instanceof IOException) {
            throw (IOException) e.getCause();
        }
    }
}

Note: The provided code may have limitations or potential issues, and using exceptions in this manner might not be the best practice. It's always recommended to consider other design patterns and practices that could lead to cleaner and more robust code.

英文:

I'm trying to get a feel for the proper way to use the java.util.Optional class. Given the following example code:

public void doSomething(File destDir, String classifier) throws IOException {
    URL resourceRoot = introspectionService.getResourceRoot(pattern);

    if (resourceRoot != null) {
        JarFile jarFile = (JarFile) resourceRoot.getContent(); //this can throw IOException
        ... snipped for brevity ...
    }
}

I would like to convert this method to use an Optional&lt;URL&gt; value from the introspectionService.

public void doSomething(File destDir, String classifier) throws IOException {
    Optional&lt;URL&gt; resourceRoot = introspectionService.getResourceRoot(pattern);

    resourceRoot.ifPresent(rootUrl-&gt; {
        JarFile jarFile = (JarFile) rootUrl.getContent(); //this can throw IOException
        ... snipped for brevity ...
    });
}

This obviously fails to compile because the signature of ifPresent() takes a Consumer which does not allow exceptions to be thrown from the accept() method.

I came up with the following work-around and was wondering if there is a better way:

public void doSomething(File destDir, String classifier) throws IOException {
    Optional&lt;URL&gt; resourceRoot = introspectionService.getResourceRoot(pattern);

    Optional&lt;IOException&gt; ioException = 
    resourceRoot.map(rootUrl-&gt; {
        try {
            JarFile jarFile = (JarFile) rootUrl.getContent(); //this can throw IOException
        ... snipped for brevity ...
            return null;
        }
        catch(IOException e) {
            return e;
        }
    });
    if (ioException.isPresent()) {
        throw ioException.get();
    }
}

Is there a better alternative?

答案1

得分: 0

EDIT: 正如MC Emperor建议的,您可以捕获IOException,然后抛出UncheckedIOException


以下是一种更通用的方法,通过让编译器认为已检查的异常实际上是未检查的方式来实现。

resourceRoot.map(rootUrl -> {
    try {
        JarFile jarFile = (JarFile) rootUrl.getContent(); //this can throw IOException
        // ... 省略部分代码 ...
        return null;
    }
    catch(IOException e) {
        sneakyThrow(e);
    }
});

您可以像下面这样定义sneakyThrow(我从这篇文章中找到的)。由于类型擦除和类型推断(T被推断为RuntimeExceptionError),它可以编译通过而不会出错,但在运行时仍然会像实际上使用throw e一样运行。

public static <T extends Throwable> void sneakyThrow(Throwable t) throws T {
    throw (T) t;
}

Lombok有一个SneakyThrows注解可以帮助您实现这一点。

这种方式下,您不必将其包装在RuntimeException或其他任何内容中 - 异常在运行时仍然只是一个IOException

英文:

EDIT: As MC Emperor suggested, you can catch the IOException and then throw an UncheckedIOException.


Here's a more generic way to do it by making the compiler think a checked exception is really unchecked.

resourceRoot.map(rootUrl-&gt; {
    try {
        JarFile jarFile = (JarFile) rootUrl.getContent(); //this can throw IOException
    ... snipped for brevity ...
        return null;
    }
    catch(IOException e) {
        sneakyThrow(e);
    }
});

You can define sneakyThrow as given below (I got it from this article). Because of type erasure and type inference (T is inferred to either RuntimeException or Error), it compiles without errors but still runs as if you actually said throw e.

public static &lt;T extends Throwable&gt; void sneakyThrow(Throwable t) throws T {
    throw (T) t;
}

Lombok has a SneakyThrows annotation that helps you do this.

This way, you don't have to wrap it in a RuntimeException or anything - the exception is simply an IOException at runtime too.

答案2

得分: 0

我认为在你有其他处理相同情况的类的情况下,这里不是使用 Optional 的合适地方。

值得查看 Files 类,并相应地调整你的设计。

英文:

I think this is not the right place to use Optional while you have other classes that handle the same thing you looking for.

it's worth to look at the Files class and change your design accordingly

huangapple
  • 本文由 发表于 2020年5月30日 06:08:31
  • 转载请务必保留本文链接:https://java.coder-hub.com/62095299.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定