Search icon
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletters
Free Learning
Arrow right icon
Java Coding Problems - Second Edition

You're reading from  Java Coding Problems - Second Edition

Product type Book
Published in Mar 2024
Publisher Packt
ISBN-13 9781837633944
Pages 798 pages
Edition 2nd Edition
Languages
Author (1):
Anghel Leonard Anghel Leonard
Profile icon Anghel Leonard

Table of Contents (16) Chapters

Preface Text Blocks, Locales, Numbers, and Math Objects, Immutability, Switch Expressions, and Pattern Matching Working with Date and Time Records and Record Patterns Arrays, Collections, and Data Structures Java I/O: Context-Specific Deserialization Filters Foreign (Function) Memory API Sealed and Hidden Classes Functional Style Programming – Extending APIs Concurrency – Virtual Threads and Structured Concurrency Concurrency ‒ Virtual Threads and Structured Concurrency: Diving Deeper Garbage Collectors and Dynamic CDS Archives Socket API and Simple Web Server Other Books You May Enjoy
Index

46. Adding nested classes in anonymous classes

In the previous problem, we had a brief overview of nested classes. As a quick reminder, an anonymous class (or, anonymous inner class) is like a local inner class without a name. Their purpose is to provide a more concise and expressive code. However, the code readability may be affected (look ugly), but it may be worth it if you can perform some specific task without having to do a full-blown class. For instance, an anonymous class is useful for altering the behavior of an existing method without spinning a new class. Java uses them typically for event handling and listeners (in GUI applications). Probably the most famous example of an anonymous class is this one from Java code:

button.addActionListener(new ActionListener() {
  public void actionPerformed(ActionEvent e) {
    ...
  }
}

Nevertheless, while local inner classes are actually class declarations, anonymous classes are expressions. To create an anonymous class, we have to extend an existing class or implement an interface, as shown in the following figure:

Figure 2.28.png

Figure 2.29: Anonymous class via class extension and interface implementation

Because they don’t have names, anonymous classes must be declared and instantiated in a single expression. The resulting instance can be assigned to a variable that can be referred to later. The standard syntax for expressions looks like calling a regular Java constructor having the class in a code block ending with a semi-colon (;). The presence of a semi-colon is a hint that an anonymous class is an expression that must be part of a statement.

Finally, anonymous classes cannot have explicit constructors, be abstract, have a single instance, implement multiple interfaces, or be extended.

Next, let’s tackle a few examples of nesting classes in anonymous classes. For instance, let’s consider the following interface of a printing service:

public interface Printer {
    public void print(String quality);
}

We use the Printer interface all over the place in our printing service, but we also want to have a helper method that is compact and simply tests our printer functions without requiring further actions or an extra class. We decided to hide this code in a static method named printerTest(), as follows:

public static void printerTest() {
  Printer printer = new Printer() {
  @Override
  public void print(String quality) {
    if ("best".equals(quality)) {
      Tools tools = new Tools();
      tools.enableLaserGuidance();
      tools.setHighResolution();
    }
    System.out.println("Printing photo-test ...");
  }
class Tools {
    private void enableLaserGuidance() {
      System.out.println("Adding laser guidance ...");
    }
    private void setHighResolution() {
      System.out.println("Set high resolution ...");
    }
  }
};

Testing the best quality print requires some extra settings wrapped in the inner Tools class. As you can see, the inner Tools class is nested in the anonymous class. Another approach consists of moving the Tools class inside the print() method. So, Tools becomes a local inner class as follows:

Printer printer = new Printer() {
  @Override
  public void print(String quality) {
    class Tools {
      private void enableLaserGuidance() {
        System.out.println("Adding laser guidance ...");
      }
      private void setHighResolution() {
        System.out.println("Set high resolution ...");
      }
    }
    if ("best".equals(quality)) {
      Tools tools = new Tools();
      tools.enableLaserGuidance();
      tools.setHighResolution();
    }
    System.out.println("Printing photo-test ...");
  }
};

The problem with this approach is that the Tools class cannot be used outside of print(). So, this strict encapsulation will restrict us from adding a new method (next to print()) that also needs the Tools class.

JDK 16+

But, remember from the previous problem that, starting with JDK 16, Java inner classes can have static members and static initializers. This means that we can drop the Tools class and rely on two static methods as follows:

Printer printer = new Printer() {
  @Override
  public void print(String quality) {
    if ("best".equals(quality)) {
      enableLaserGuidance();
      setHighResolution();
    }
    System.out.println("Printing your photos ...");
  }
  private static void enableLaserGuidance() {
    System.out.println("Adding laser guidance ...");
  }
  private static void setHighResolution() {
    System.out.println("Set high resolution ...");
  }
};

If you find it more convenient to pick up these helpers in a static class, then do it:

Printer printer = new Printer() {
  @Override
  public void print(String quality) {
    if ("best".equals(quality)) {
      Tools.enableLaserGuidance();
      Tools.setHighResolution();
    }
    System.out.println("Printing photo-test ...");
  }
  private final static class Tools {
    private static void enableLaserGuidance() {
      System.out.println("Adding laser guidance ...");
    }
    private static void setHighResolution() {
      System.out.println("Set high resolution ...");
    }
  }
};

You can practice these examples in the bundled code.

You have been reading a chapter from
Java Coding Problems - Second Edition
Published in: Mar 2024 Publisher: Packt ISBN-13: 9781837633944
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime}