Java 8 -- anonymous classes and functional interfaces

Keywords: Java java8

1, Anonymous class

Anonymous classes in Java are classes without names. They are just syntax sugar to avoid template code declaring and instantiating a one-time class.

(1) It is an internal or local class without a name, and only one object is created for it.
(2) An anonymous class is an expression, which means that the class needs to be defined in another statement.
(3) Anonymous class expressions require the new operator, the name of the interface to implement or the class to extend, parentheses containing constructor parameters, and the class declaration body.
(4) It cannot have a constructor (use instance initializers as needed)
(5) Because anonymous classes are similar to native classes, they also support capturing variables (their behavior is similar to closure - a closure is a code block that can be referenced and passed by accessing closed scope variables).
(6) Only local variables of final or valid final can be accessed (this also applies to Lambdas - discussed later - and also conforms to the principle of functional programming. If we assume that only anonymous classes are used, the function can change the state as an alternative to a code block without any state)

For example, look at the following classes:

public class Anony {
  public void publicMethod() {
    Integer localVariable1 = 10;
    Integer localVariable2 = 10;
    Integer localVariable3 = 10;

    Map<String, Integer> map = new HashMap<String, Integer>() {
      {
        put("a", localVariable1);
        put("b", localVariable2);
        put("c", localVariable3);
      }
    };

    Thread t = new Thread(new Runnable() {
      public void run() {
        System.out.println(localVariable1);
      }
    });

    List<String> list = Arrays.asList("A", "B", "C");

    Collections.sort(list, new Comparator<String>() {
      public int compare(String p1, String p2) {
        return p1.compareTo(p2);
      }
    });
  }
}

Let's take a closer look and see what this class is compiled into. After compiling the Anony class (javac Anony.java) mentioned in the above example, the java compiler generates four class files. As I mentioned earlier, since an anonymous class is a syntax sugar, it is converted into appropriate code to run correctly. If we look at the compiled bytecode, we can easily see how it is compiled into classes and how variable capture / closure works:

javap -p Anony.class

public class com.java8exploration.Anony {
  public com.java8exploration.Anony();
  public void publicMethod();
}

javap –p Anony$1.class

Returning the code in Anony.java, you can see that we have referenced three local variables. If we see the compiled code, we can see that these variables are being generated into the Anony class. In addition, its constructor contains variables referenced as parameters, which is how the variable capture / close behavior works.

class com.java8exploration.Anony$1 extends java.util.HashMap<java.lang.String, java.lang.Integer> {
  final java.lang.Integer val$localVariable1;
  final java.lang.Integer val$localVariable2;
  final java.lang.Integer val$localVariable3;
  final com.java8exploration.Anony this$0;
  com.java8exploration.Anony$1(com.java8exploration.Anony, java.lang.Integer, java.lang.Integer, java.lang.Integer);
}

javap -p Anony$2.class

class com.java8exploration.Anony$2 implements java.lang.Runnable {
  final java.lang.Integer val$localVariable1;
  final com.java8exploration.Anony this$0;
  com.java8exploration.Anony$2(com.java8exploration.Anony, java.lang.Integer);
  public void run();
}

javap -p Anony$3.class

class com.java8exploration.Anony$3 implements java.util.Comparator<java.lang.String> {
  final com.java8exploration.Anony this$0;
  com.java8exploration.Anony$3(com.java8exploration.Anony);
  public int compare(java.lang.String, java.lang.String);
  public int compare(java.lang.Object, java.lang.Object);
}

2, Functional interface

Now let's look at functional interfaces in Java 8.

(1) A functional interface is an interface with only one abstract method in Java
(2) These interfaces are sometimes referred to as SAM (single abstract method) types
(3) Lambda expressions are only applicable to functional interfaces. This means that we can use lambda expressions (or method references) wherever we need a function interface.
(4) The functional interface is a key structure that allows Java as an object-oriented platform, supports functional programming (as a type wrapper for functions) and processes functions.
(5) There are already many interfaces (and other libraries with only one method) in the Java library, but because Java needs to incorporate the concept of functional programming into its object-oriented core, it needs to abstract the functional interface, which is just a method. In fact, it represents an executable function in a functional programming language. Therefore, Java 8 just formalizes this idea through this construct.
(6) The @ functional interface annotation is also provided to mark such interfaces so that the compiler can issue warnings / errors if there are any differences in the definition of functional interfaces.
(7) Because functional interfaces are a way to represent functions, Java provides many interfaces for representing different function types, which are hosted under the java.util.function package. Note that a functional interface can take generic parameters, and it supports defining the input / output type of any function
(8) Because primitive types cannot be generic type parameters, there is a version of the function interface for the most commonly used primitive types, such as double, int, long, and combinations of their parameters and return types.

There are many functional interfaces available in the java.util.function package. We can easily use them to represent our function types. However, if we do not find a functional interface to represent our own custom functions, we can also create our own functional interface.

Posted by MarcAndreTalbot on Sun, 07 Nov 2021 17:25:35 -0800