2016-12-28 1 views
7

Пусть у меня есть метод библиотеки, как это (очень сокращенный):Что вернуть, когда родовые методы возвращают «ничего», но null не могут быть возвращены?

public static <V> Optional<V> doSomethingWith(Callable<V> callable) { 
    try { 
     return Optional.of(callable.call()); 
    } catch (Exception ex) { 
     // Do something with ex 
     return Optional.empty(); 
    } 
} 

И я хочу что-то, что не возвращает значения, как:

Library.</*What1*/>doSomethingWith(() -> { 
     foo(); 
     return /*what2*/; 
    }); 

Мой первый инстинкт родовое метод, который не возвращает значение, делает тип Void и возвращает null, однако, поскольку результат обернут в Optional, это приведет к исключению.

Какие разумные заполнители для /*What1*/ и /*what2*/, которые не выглядят совершенно случайно, как Integer и 0?

Я стараюсь избегать Optional.ofNullable, потому что здесь используется пустой символ, указывающий, что callable.call() не прошел нормально.

+3

Не можете ли вы изменить метод библиотеки, чтобы использовать 'Optional.ofNullable'? Какой смысл возвращать необязательный, если он всегда присутствует? –

+0

Метод библиотеки очень сокращен. Он может фактически возвращать 'Optional.empty()' при возникновении условия. –

+0

Вы можете просто добавить локальный класс с разумным именем и вернуть экземпляр этого класса. – glee8e

ответ

4

Обычно я использую Boolean.TRUE, чтобы отметить успех, но вы можете вернуться Void.class. Оба дешевы в том смысле, что не каждый возврат создает новый объект, который нужно отбросить. Хотя Class<Void> не только Void он может служить для маркировки чего-либо как void.

Как уже упоминалось, вы также можете создать свой собственный класс результатов/-enum.

Или вы можете, конечно, вернуться Optional.<Void>nothing(), тоже. Это приведет к некоторым Optional<Optional<Void>>, но и сделает трюк.

Если вы считаете, что все вышеперечисленное является уродливым, я опасаюсь, что API, вероятно, не будет соответствовать вашим потребностям. Поднимите запрос на проблему/запрос или найдите что-то еще.

+0

Мне нравится опция enum best. Тем более, что вчера мне просто интересно, почему нет встроенного (не примитивного) типа, который имеет ровно 2 возможности. Для сравнения: 'Void' имеет одну возможность:' null' и 'Boolean' имеет три:' null', 'FALSE',' TRUE'. («Объект», конечно, имеет бесконечные возможности.) –

6

Если вам нужен тип подсказки для общего параметра, который никогда не будет использоваться, вы можете использовать Void, JDK делает это тоже в некоторых случаях, например. при преобразовании Runnable в CompletableFuture<T> он использует Пустоту для Т.

Если вы используете Optional.ofNullable, то вы можете просто вернуть null для what2, который является единственным допустимым значением для Void.

[edit] Я пытаюсь избежать Optional.ofNullable, поскольку здесь используется пустое значение, указывающее, что callable.call() не завершился нормально.

Тогда вы используете неправильный инструмент для работы. CompletionStage или CompletableFuture имеет правильную семантику.

0

Использовать Void для типа возврата, который является логическим выбором для «ничего», но на самом деле возвращает экземпляр Void.

Хотя javadoc for Void говорит, что:

... uninstantiable класс заполнителем ...

Вы можете все-таки создать его экземпляр:

try { 
    Constructor<Void> c = Void.class.getDeclaredConstructor(); 
    c.setAccessible(true); 
    return c.newInstance(); 
} catch (Exception perfunctory) { 
    return null; // won't happen 
} 
+6

Плохой совет. Вы нарушаете несколько контрактов, когда вы взламываете экземпляр «Void» в существование, не говоря уже о возможных изменениях реализации в будущих/альтернативных JDK, которые в любом случае приводят к тому, что «не произойдет». –

+0

@mark, какие контракты, ** конкретно **, нарушены? Просьба указать ссылки и т. Д. Я утверждаю, что таких контрактов нет и что, если будущие версии изменят конструктор таким образом, что этот код не будет работать (очень маловероятно), тогда беспокоиться об этом. – Bohemian

1

Вы также можете создать свой собственный тип, аналогичный Void

public class Result { 
    public static final Result OK = new Result(); 

    private Result(){} 
} 

, а затем вернуть Result.OK.

Вы также можете улучшить этот тип, чтобы представлять также ошибки, если вам нужно.

Но, возможно, использование java Void предпочтительнее, если вам не нужно ничего особенного.

+0

Я бы использовал перечисление для этого. – TheConstructor

+0

Это зависит от того, что вам нужно сделать, с помощью singleton вы не можете управлять ОШИБКОЙ, потому что с ним вам понадобится другой экземпляр каждый раз с другим сообщением. – rascio

+0

Enums наследуют еще несколько методов (например, 'toString'), почему я обычно предпочитаю их для сигнальных экземпляров, таких как предложенный' Result.OK'. Проблема OP не будет существовать, если бы какой-то класс «ResultOrError» использовался в API вместо «Необязательно». – TheConstructor

Смежные вопросы