From 564576ff0986ecaa0c7f5bda3e2dacdb5106a5dd Mon Sep 17 00:00:00 2001 From: Bruno Borges Date: Wed, 26 Aug 2026 17:24:09 -0400 Subject: [PATCH] Add anonymous classes to lambdas pattern Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../anonymous-classes-to-lambdas.yaml | 49 +++++++++++++++++++ .../language/default-interface-methods.yaml | 2 +- content/tooling/junit6-with-jspecify.yaml | 2 +- proof/language/AnonymousClassesToLambdas.java | 16 ++++++ 4 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 content/language/anonymous-classes-to-lambdas.yaml create mode 100644 proof/language/AnonymousClassesToLambdas.java diff --git a/content/language/anonymous-classes-to-lambdas.yaml b/content/language/anonymous-classes-to-lambdas.yaml new file mode 100644 index 00000000..db631fea --- /dev/null +++ b/content/language/anonymous-classes-to-lambdas.yaml @@ -0,0 +1,49 @@ +--- +id: bbccea66-79bb-4bf9-80ea-e6bdd96a7bfc +slug: "anonymous-classes-to-lambdas" +title: "Anonymous classes to lambdas and method references" +category: "language" +difficulty: "beginner" +jdkVersion: "8" +oldLabel: "Anonymous class" +modernLabel: "Java 8+" +oldApproach: "Anonymous class" +modernApproach: "Method reference" +oldCode: |- + button.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent event) { + save(event); + } + }); +modernCode: |- + button.addActionListener(this::save); +summary: "Replace single-method anonymous classes with concise lambdas and method references." +explanation: "Functional interfaces can be implemented with lambdas or method references. This removes anonymous-class ceremony while preserving static typing and the same callback contract." +whyModernWins: +- icon: "⚡" + title: "Less boilerplate" + desc: "Removes the class declaration and override ceremony." +- icon: "👁" + title: "Better readability" + desc: "Keeps attention on the operation being performed." +- icon: "🔒" + title: "Still type-safe" + desc: "The compiler checks the target functional-interface signature." +support: + state: "available" + description: "Available since JDK 8 (March 2014)." +prev: "tooling/junit6-with-jspecify" +next: "language/default-interface-methods" +related: +- "language/default-interface-methods" +- "streams/predicate-not" +- "collections/collection-bulk-operations" +tags: +- functional +- interfaces +docs: +- title: "Lambda Expressions" + href: "https://dev.java/learn/lambdas/" +- title: "Method References" + href: "https://dev.java/learn/lambdas/method-references/" diff --git a/content/language/default-interface-methods.yaml b/content/language/default-interface-methods.yaml index 42d0bca5..6fa50073 100644 --- a/content/language/default-interface-methods.yaml +++ b/content/language/default-interface-methods.yaml @@ -55,7 +55,7 @@ whyModernWins: support: state: "available" description: "Available since JDK 8 (March 2014)." -prev: "tooling/junit6-with-jspecify" +prev: "language/anonymous-classes-to-lambdas" next: "language/markdown-javadoc-comments" related: - "language/private-interface-methods" diff --git a/content/tooling/junit6-with-jspecify.yaml b/content/tooling/junit6-with-jspecify.yaml index 53f2c815..53d9b049 100644 --- a/content/tooling/junit6-with-jspecify.yaml +++ b/content/tooling/junit6-with-jspecify.yaml @@ -88,7 +88,7 @@ support: state: "available" description: "Available since JUnit 6.0 (October 2025, requires Java 17+)" prev: "tooling/aot-class-preloading" -next: "language/default-interface-methods" +next: "language/anonymous-classes-to-lambdas" related: - "enterprise/spring-null-safety-jspecify" - "errors/helpful-npe" diff --git a/proof/language/AnonymousClassesToLambdas.java b/proof/language/AnonymousClassesToLambdas.java new file mode 100644 index 00000000..657dc76b --- /dev/null +++ b/proof/language/AnonymousClassesToLambdas.java @@ -0,0 +1,16 @@ +///usr/bin/env jbang "$0" "$@" ; exit $? +//JAVA 25+ +import java.awt.event.*; + +/// Proof: anonymous-classes-to-lambdas +/// Source: content/language/anonymous-classes-to-lambdas.yaml +void save(ActionEvent event) {} + +void main() { + Button button = new Button(); + button.addActionListener(this::save); +} + +class Button { + void addActionListener(ActionListener listener) {} +}