2014-02-09 6 views
12

Некоторые предпосылки, затем некоторые вопросы.Хороший шаблон? <X extends Exception> ... method() throws X

Я только недавно обнаружил, что интерфейс (или класс) может быть общим в типе (отмеченного) исключения, которое могут быть выбраны его методы. Например:

interface GenericRunnable<X extends Exception> { 
    void run() throws X; 
} 

Дело в том, если вы позже экземпляр этого, скажем, IOException и вызвать метод run, компилятор знает, что вам нужно либо поймать IOException или пометить его как брошено. Еще лучше, если X был RuntimeException, вам совсем не нужно его обрабатывать.

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

public <X extends Exception> void runTwice(GenericRunnable<X> runnable) throws X { 
    runnable.run(); runnable.run(); 
} 
... 
public myMethod() throws MyException { 
    runTwice(myRunnable); 
} 

Мы называем общий метод полезности runTwice (возможно, определенный во внешней библиотеке), чтобы запустить свой собственный специфический метод с конкретным проверяемым исключением, и мы не теряем какую-либо информации о том, каких конкретных проверяемом исключении могут быть брошенным.

Альтернативой было бы просто использовать throws Exception как по методу Runnable.run, так и по методу runTwice. Это не ограничивает реализацию интерфейса Runnable, но преимущество проверенных исключений будет потеряно. Или вообще не могло быть throws, также теряя преимущество проверенных исключений и потенциально заставляя реализацию обернуть.

Потому что я никогда не видел throws X, может быть, я что-то пропустил. Кроме того, я видел пример обратного вызова, который использовался как аргумент против отмеченных исключений несколько раз, без его опровержения. (Этот вопрос не интересует плюсы и минусы проверенных исключений.)

throws X В целом хорошая идея? Каковы плюсы и минусы? Можете ли вы привести несколько примеров, которые либо используют throws X, либо не должны были иметь?

В принципе, я хотел бы получить дополнительную информацию. Вы можете прокомментировать следующие примеры.

  • OutputStream бросает IOException (возможно, ByteArrayOutputStream мог простирается GenericOutputStream<RuntimeException>)

  • Callable/Future.get

  • фонда бассейн borrowObject/makeObject

(С Editi Я не спрашиваю, могли ли они/должны были быть разработаны по-разному в ретроспективе. Скорее, throws X будет лучше, чем throws Exception.)

+3

Класс потоков не мог быть спроектирован так, потому что они были разработаны до того, как эта функция была добавлена ​​(т. Е. Дженерики). – tbodt

+0

У Guava ['Throwables'] (http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/base/Throwables.html) есть несколько примеров. Но этот вопрос кажется слишком широким. Постарайтесь усовершенствовать свои различные вопросы на протяжении всего поста в нечто более целенаправленное. –

+0

Да. Java развивается со временем. Это означает, что всегда есть места в старых классах/функциях, где более новые были использованы, но не были доступны, и, поскольку все работает достаточно хорошо без них, для этого не было достаточного оправдания , Вы можете, конечно, реализовать свои собственные обертки/повторные применения старых классов, чтобы использовать новые функции, и если они действительно окажутся достаточно полезными, они могут быть приняты; что на самом деле является частью того, как выросли библиотеки Java. Но это происходит только при наличии достаточной реальной добавленной стоимости и достаточного спроса, чтобы оправдать ее. – keshlam

ответ

2

Я использую этот шаблон все время, в основном для функционального java.

Плюсы:

  1. Вы можете иметь несколько разновидностей узора высшего порядка, как посетитель, а именно:

    interface ExceptionalVoidVisitor< E extends Exception > { 
        void handleA(A a) throws E; 
        void handleB(B b) throws E; 
    } 
    interface VoidVisitor extends ExceptionalVoidVisitor<RuntimeException> {} 
    interface ExceptionalVisitor< T, E extends Exception > { 
        T handleA(A a) throws E; 
        T handleB(B b) throws E; 
    } 
    interface Visitor<T> extends ExceptionalVisitor< T, RuntimeException > {} 
    
  2. Ваш клиент может объявить базовый класс исключений для всех исключений он может бросить, и вы получите полностью общую библиотеку.

Минусы:

  1. Как вы обнаружили, что нет никакого способа, чтобы обрабатывать исключение общего типа; вы должны позволить ему убежать.
  2. Другой вариант - принять генератор E, который может быть неудобным для клиентов.
+0

Приятно слышать, что это общий шаблон для вас. Я не буду беспокоиться о том, чтобы использовать его сам в будущем. – user2357

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

  • Нет связанных вопросов^_^