借用和竊取其他語言的概念和想法總是很高興的。 Scala的Option是我真正喜歡的一個主意,因此我用Java編寫了一個實現。 它包裝了一個可能為null或不為null的對象,并提供了一些可按某種功能使用的方法。 例如,isDefined方法添加了一種面向對象的方式來檢查值是否為null。 然后在其他地方使用它,例如getOrElse方法,該方法基本上說“給我您要包裝的內容,如果沒有,則回退”。
public T getOrElse(T fallback)
{return isDefined() ? get() : fallback;
}
實際上,這將替代傳統的Java,例如
public void foo()
{String s = dao.getValue();if (s == null){s = 'bar';}System.out.println(s);
}
與更簡潔和面向對象
public void foo()
{Option<String> s = dao.getValue();System.out.println(s.getOrElse('bar'));
}
但是,如果我想做一個除獲得后備值之外的事情-拋出異常,該怎么辦? 更重要的是,如果我要拋出特定類型的異常(即使用中特定且未硬編碼到Option中)怎么辦? 這需要一點技巧,并需要進行類型推斷。
因為這是Java,所以我們可以從一個新工廠– ExceptionFactory開始。 這是一個基本的實現,僅創建使用消息構造的異常,但是您當然可以根據需要擴展代碼。
public interface ExceptionFactory <E extends Exception>
{E create(String message);
}
注意<E extended Exception> –這是它如何工作的關鍵。 使用工廠,我們現在可以向Option添加新方法:
public <E extends Exception> T getOrThrow(ExceptionFactory<E> exceptionFactory,String message) throws E
{if (isDefined()){return get();}else{throw exceptionFactory.create(message);}
}
同樣,請注意引發E –這是從異常工廠推斷出來的。
不管您信不信,這就是所需費用的90%。 一種煩惱是需要異常工廠。 如果您能忍受這一切,那么一切都準備就緒。 讓我們定義幾個自定義異常,以了解實際情況。
public <E extends Exception> T getOrThrow(ExceptionFactory<E> exceptionFactory,String message) throws E
{if (isDefined()){return get();}else{throw exceptionFactory.create(message);}
}
與可疑的ExceptionB類似
public class ExceptionB extends Exception
{public ExceptionB(String message){super(message);}public static ExceptionFactory<ExceptionB> factory(){return new ExceptionFactory<ExceptionB>(){@Overridepublic ExceptionB create(String message){return new ExceptionB(message);}};}
}
最后,將它們放在一起:
public class GenericExceptionTest
{@Test(expected = ExceptionA.class)public void exceptionA_throw() throws ExceptionA{Option.option(null).getOrThrow(ExceptionA.factory(),"Some message pertinent to the situation");}@Testpublic void exceptionA_noThrow() throws ExceptionA{String s = Option.option("foo").getOrThrow(ExceptionA.factory(),"Some message pertinent to the situation");Assert.assertEquals("foo",s);}@Test(expected = ExceptionB.class)public void exceptionB_throw() throws ExceptionB{Option.option(null).getOrThrow(ExceptionB.factory(),"Some message pertinent to the situation");}@Testpublic void exceptionB_noThrow() throws ExceptionB{String s = Option.option("foo").getOrThrow(ExceptionB.factory(),"Some message pertinent to the situation");Assert.assertEquals("foo",s);}
}
如上以粗體突出顯示的那樣,需要注意的重要一點是方法簽名中聲明的異常是特定的–它不是共同的祖先(Exception或Throwable)。 這意味著您現在可以在任何地方的DAO層,服務層中使用“選項”,并在需要的地方和方式中拋出特定的異常。
下載源 :您可以從此處獲取源代碼和測試– Genex
邊注
編寫此書后產生的另一件有趣的事情是觀察到可以執行此操作:
public void foo()
{throw null;
}public void bar()
{try{foo();}catch (NullPointerException e){...}
}
不用說,這不是一個好主意。
參考: Objectify博客上的JCG合作伙伴 Steve Chaloner 推斷出Java中的異常 。
翻譯自: https://www.javacodegeeks.com/2013/01/inferred-exceptions-in-java.html