Использование Optional.map () вместо Optional.ifPresent () для выполнения кода, который может вызывать исключение и возвращать любые исключения в качестве возвращаемого значения - PullRequest
1 голос
/ 30 мая 2020

Я пытаюсь понять, как правильно использовать класс java.util.Optional. Учитывая следующий пример кода:

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 ...
    }
}

, я хотел бы преобразовать этот метод для использования значения Optional<URL> из службы introspectionService.

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

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

Это явно не может быть скомпилировано, потому что подпись of ifPresent () принимает Consumer, который не позволяет генерировать исключения из метода accept ().

Я придумал следующий обходной путь, и мне было интересно, есть ли лучший способ:

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

    Optional<IOException> ioException = 
    resourceRoot.map(rootUrl-> {
        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();
    }
}

Есть ли альтернатива лучше?

Ответы [ 2 ]

0 голосов
/ 30 мая 2020

Я думаю, что это не подходящее место для использования Optional, пока у вас есть другие классы, которые обрабатывают то же самое, что вы ищете.

стоит взглянуть на класс Files и соответствующим образом изменить свой дизайн

0 голосов
/ 30 мая 2020

РЕДАКТИРОВАТЬ: Как предложил M C Emperor, вы можете поймать IOException, а затем бросить UncheckedIOException.


Вот более общий c способ сделать это, сделав компилятор считает, что проверенное исключение действительно не проверено.

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

Вы можете определить sneakyThrow, как указано ниже (я получил его из этой статьи). Из-за стирания типа и вывода типа (T выводится из RuntimeException или Error), он компилируется без ошибок, но по-прежнему работает, как если бы вы на самом деле сказали throw e.

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

Lombok имеет аннотацию SneakyThrows, которая помогает вам в этом.

Таким образом, вам не нужно заключать его в RuntimeException или что-то в этом роде - исключение составляет просто IOException во время выполнения.

...