摆脱匿名类
我真的很喜歡編寫和閱讀lambda表達式-它們簡潔,富于表現力和時尚(來吧,這樣就沒關系了!)。 將此與匿名類進行比較。 這就是為什么我喜歡擺脫它們!
在過去的幾個月中,這種認識慢慢地實現了,昨天,我的潛意識對如何實現這一想法提出了質疑。 我將在這里展示它,并在嘗試后的幾周內發布后續信息。
總覽
為了確保每個人都知道我們在說什么,我將快速回顧一下匿名類。 然后,我將解釋為什么在確定他們的最后一個據點以及如何征服它之前要擺脫它們。
匿名類快速回顧
匿名類用于創建接口或抽象類的臨時實現,如下所示:
異端階級的例子
Runnable run = new Runnable() {@Overridepublic void run() {runThisThing(someArgument);} };確實確實創建了一個單獨的類(您將在包含該代碼的類旁邊找到它的.class文件),但是由于它沒有名稱,因此您猜到了它的名稱,它被稱為匿名類。 我對此的觀點始終是,這些課程應該確實很短。 一種,可能有兩種方法,有兩行。 凡是更長的東西,而且絕對是帶有狀態的東西,似乎都應該擁有自己的名稱和位置–在文件的底部作為嵌套類甚至是自己的名稱。 它總是使我無法讀取方法,該方法有時會創建10+行的who-knows-what實現,而該實現完全無關。 但是對于簡短的實現(如上面的示例),匿名類是最佳選擇。
發布時間由馬蒂亞諾塔下, CC-BY-NC-SA 2.0 。
那他們怎么了?
匿名類沒有什么錯 。 只是在使用lambda表達式和方法/構造函數引用大約一年后,它們似乎是如此笨拙。 我越習慣于簡單而準確地表達自己的行為,當面對匿名課堂的儀式和迷惑時,我就越被排斥。
只需將其與上面的示例進行比較:
異端階級的例子
Runnable run = () -> runThisThing(someArgument);在過去的幾個月中,我逐漸意識到自己不想再看到它們了,昨天我對如何擺脫(必須知道的)必要的剩余事件有了一個很好的想法。
擺脫匿名類
如上所述,我認為比一個或兩個方法的簡單實現更為復雜的所有事物通常都應以嵌套或獨立類的形式獲得自己的名稱和位置。
(順便說一句,我傾向于對覆蓋現有超類方法以更改其行為的類進行同樣的操作。這可能很短,但是如果您不知道現在已被覆蓋的原始代碼,發現差異并推導意圖通常很困難。在大多數情況下,給班級一個好名字可以解決這個問題。)
然后,當然有了Java 8,由于使用了lambda表達式,大量匿名類的用例就消失了。 這很棒! 它也是擺脫它們最后一個據點的工具:“具有幾乎所有功能的”接口以及具有一個或兩個抽象方法的抽象類的實現。
所以這是我的主意:
當遇到適合自己實現的接口或抽象類時,我們將創建一個功能實現 。 這是一個非抽象類,它將所有方法調用委托給在構造期間指定的功能接口。
例
我猜一個例子可以澄清這一點:
“幾乎功能”界面
public interface ValueListener<T> {void invalidated(T formerValue);void changed(T formerValue, T newValue);}由于這不是功能接口,因此不能使用lambda表達式創建實現。 相反,您可以在需要時創建一個匿名類:
創建一個匿名實現
ValueListener<String> anonymousListener = new ValueListener<String>() {@Overridepublic void invalidated(String formerValue) {valueInvalidated(formerValue);}@Overridepublic void changed(String formerValue, String newValue) {valueChanged(formerValue, newValue);} };相反,我們可以一次創建接口的功能實現:
功能實現
public class FunctionalValueListener<T> implements ValueListener<T> {private final Consumer<T> invalidated;private final BiConsumer<T, T> changed;public FunctionalValueListener(Consumer<T> invalidated,BiConsumer<T, T> changed) {this.invalidated = invalidated;this.changed = changed;}@Overridepublic void invalidated(T formerValue) {invalidated.accept(formerValue);}@Overridepublic void changed(T formerValue, T newValue) {changed.accept(formerValue, newValue);}}此類的實例可以更簡潔地創建,并且不會造成混淆:
實例化功能實現
ValueListener<String> functionalListener = new FunctionalValueListener<>(this::valueInvalidated,this::valueChanged);另一個例子
實際上觸發這個想法的是我在代碼庫中看到的許多Swing的AbstractAction匿名實現:
Action action = new AbstractAction() {@Overridepublic void actionPerformed(ActionEvent e) {performedAction(e);} };這尖叫著“ LAMBDA EXPRESSION!” 但是您不能在抽象類上使用它。 但是在創建只需要使用Consumer<ActionEvent>的功能實現之后,您可以這樣做,它看起來像這樣:
Action action = new FunctionalAction(this::performedAction);好多了吧?
跟進
我將嘗試幾個星期,并報告其工作原理。 我已經看到了一些問題(JDK提供的功能接口的多樣性和異常)以及至少一種改善此模式的方法。
但是我認為值得討論這種方法。 我也這么認為,為什么不分享呢?
您也會嘗試嗎? 想到更多問題還是需要改進? 也許您只是覺得這很愚蠢? 無論如何,無論您在哪里找到我,都請發表評論,寫帖子或ping我。
反射
我表示不喜歡匿名類的冗長和混淆。 長的那些永遠不應該放在首位(使它們嵌套類或自己的類),但是短的有時是最佳選擇。
通過短接口或抽象類的功能實現,我們可以改用lambda表達式,方法引用或構造函數引用,并從它們的簡潔性和可讀性中受益。
翻譯自: https://www.javacodegeeks.com/2015/04/getting-rid-of-anonymous-classes.html
總結
- 上一篇: iRocks 推出 K74M 机械键盘:
- 下一篇: 微软发布 Win11 Build 235