123

Since Java8 has been recently released and its brand new lambda expressions looks to be really cool, I was wondering if this means the demise of the Anonymous classes that we were so used to.

I've been researching a bit about this and found some cool examples about how Lambda expressions will systematically replace those classes, such the Collection's sort method, which used to get an Anonymous instance of Comparator to perform the sort:

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

Now can be done using Lambdas:

Collections.sort(personList, (Person p1, Person p2) -> p1.firstName.compareTo(p2.firstName));

And looks surprisingly concise. So my question is, is there any reason to keep using those classes in Java8 instead of Lambdas?

EDIT

Same question but in the opposite direction, what are the benefits of using Lambdas instead of Anonymous classes, since Lambdas can only be used with single method interfaces, is this new feature only a shortcut only used in few cases or is it really useful?

Amin Abu-Taleb
  • 4,423
  • 6
  • 33
  • 50
  • 5
    Sure, for all those anonymous classes that provide methods with side effects. – tobias_k Mar 25 '14 at 14:44
  • 12
    Just for your info, you can also construct the comparator as: `Comparator.comparing(Person::getFirstName)`, if `getFirstName()` would be a method returning `firstName`. – skiwi Mar 25 '14 at 14:55
  • 1
    Or anonymous classes with multiple methods, or ... – Mark Rotteveel Mar 25 '14 at 15:26
  • 1
    I am tempted to vote for close as too broad, especially due to the additional questions after _**EDIT**_. – Mark Rotteveel Mar 25 '14 at 15:29
  • 1
    A nice in-depth article on this topic: https://www.infoq.com/articles/Java-8-Lambdas-A-Peek-Under-the-Hood – Ram Patra Dec 22 '16 at 14:35
  • Another Article which gives a detailed comparison on this topic can be found here: [Lamda vs Anonymous Inner Class](http://www.techbyapro.com/lambda-vs-anonymous-inner-class.html) – Abhishek Parikh Feb 16 '17 at 05:05
  • One more info. `Collections.sort(personList, (p1, p2) -> p1.firstName.compareTo(p2.firstName));` you can directly pass the object `p1` and `p2` directly, instead of `Person p1, Person p2`. It will work – Arvind Katte Nov 12 '17 at 18:06

9 Answers9

118

An anonymous inner class (AIC) can be used to create a subclass of an abstract class or a concrete class. An AIC can also provide a concrete implementation of an interface, including the addition of state (fields). An instance of an AIC can be referred to using this in its method bodies, so further methods can be called on it, its state can be mutated over time, etc. None of these apply to lambdas.

I'd guess that the majority of uses of AICs were to provide stateless implementations of single functions and so can be replaced with lambda expressions, but there are other uses of AICs for which lambdas cannot be used. AICs are here to stay.

UPDATE

Another difference between AICs and lambda expressions is that AICs introduce a new scope. That is, names are resolved from the AIC's superclasses and interfaces and can shadow names that occur in the lexically enclosing environment. For lambdas, all names are resolved lexically.

Naman
  • 27,789
  • 26
  • 218
  • 353
Stuart Marks
  • 127,867
  • 37
  • 205
  • 259
  • 3
    Lambdas can have state. In this regards, I see no difference between Lambdas and AIC. – nosid Mar 25 '14 at 18:35
  • 2
    @nosid AICs, like instances of any class, can hold state in fields, and this state is accessible to (and potentially mutable by) any method of the class. This state exists until the object is GC'd, i.e., it has indefinite extent, so it can persist across method calls. The only state with indefinite extent lambdas have is captured at the time the lambda is encountered; this state is immutable. Local variables within a lambda are mutable, but they exist only while a lambda invocation is in progress. – Stuart Marks Mar 26 '14 at 00:18
  • @StuartMarks: Captures variables in lambda expressions are (effective) _final_. However, the referenced objects are _mutable_. Regarding the implementation of _functional interfaces_ and _state_, you can do basically the same things with _lambda expressions_ that you can do with _anonymous inner classes_. For example: `IntSupplier makeCounter(int start) { int[] value = { start }; return () -> value[0]++; }`. If you are familiar with JavaScript, it's a common pattern to use captures to create statefull function objects. – nosid Mar 26 '14 at 08:07
  • 1
    @nosid Ah, the single-element array hack. Just don't try to use your counter from multiple threads. If you're going to allocate something on the heap and capture it in a lambda, you might as well use an AIC and add a field that you can mutate directly. Using a lambda this way can work, but why bother when you can use a real object? – Stuart Marks Mar 27 '14 at 00:29
  • 2
    AIC will create a file something like this, `A$1.class` but Lambda will not. Can I add this in Difference? – Asif Mushtaq Jun 11 '16 at 08:39
  • 4
    @UnKnown That's mainly an implementation concern; it doesn't affect how one programs with AICs vs lambdas, which is what this question is mostly about. Note that a lambda expression does generate a class with a name like `LambdaClass$$Lambda$1/1078694789`. However, this class is generated on-the-fly by the lambda metafactory, not by `javac`, so there is no corresponding `.class` file. Again, however, this is an implementation concern. – Stuart Marks Jun 13 '16 at 05:08
66

Lambdas though a great feature, will only work with SAM types. That is, interfaces with only a single abstract method. It would fail as soon as your interface contains more than 1 abstract method. That is where anonymous classes will be useful.

So, no we cannot just ignore anonymous classes. And just FYI, your sort() method can be more simplified, by skipping the type declaration for p1 and p2:

Collections.sort(personList, (p1, p2) -> p1.firstName.compareTo(p2.firstName));

You can also use method reference here. Either you add a compareByFirstName() method in Person class, and use:

Collections.sort(personList, Person::compareByFirstName);

or, add a getter for firstName, directly get the Comparator from Comparator.comparing() method:

Collections.sort(personList, Comparator.comparing(Person::getFirstName));
Rohit Jain
  • 209,639
  • 45
  • 409
  • 525
  • 5
    I knew, but I prefer the long one in terms of readability, because otherwise it could be confusing to find out where these variables come from. – Amin Abu-Taleb Mar 25 '14 at 14:49
  • @AminAbu-Taleb Why would it be confusing. That is a valid Lambda syntax. The types is anyways inferred. Anyways, it's a personal choice. You can give types explicit. No issues. – Rohit Jain Mar 25 '14 at 14:50
  • 1
    There is another subtle difference between lambdas and anonymous classes: Anonymous classes can be directly annotated with the new [Java 8 Type Annotations](http://docs.oracle.com/javase/tutorial/java/annotations/type_annotations.html), as e.g. `new @MyTypeAnnotation SomeInterface(){};`. This is not possible for lambda expressions. For details, see my question here: [Annotating the functional interface of a Lambda Expression](http://stackoverflow.com/questions/22375891/annotating-the-functional-interface-of-a-lambda-expression). – Balder Mar 25 '14 at 15:19
41

Lambda performance with Anonymous classes

When application is launched each class file must be loaded and verified.

Anonymous classes are processed by compiler as a new subtype for the given class or interface, so there will be generated a new class file for each.

Lambdas are different at bytecode generation, they are more efficient, used invokedynamic instruction that comes with JDK7.

For Lambdas this instruction is used to delay translate lambda expression in bytecode untill runtime. (instruction will be invoked for the first time only)

As result Lambda expression will becomes a static method(created at runtime). (There is a small difference with stateles and statefull cases, they are resolved via generated method arguments)

Dmitriy Kuzkin
  • 459
  • 4
  • 4
  • 1
    Each lambda also needs a new class, but it is generated at runtime, so in this sense, lambdas are not more efficient than anonymous classes. Lambdas are created via `invokedynamic` which is generally slower than `invokespecial` used to create new instances of anonymous classes. So, in this sense lambdas are slower too (however, JVM can optimize `invokedynamic` calls most of the time). – ZhekaKozlov May 02 '17 at 04:17
  • 3
    @AndreiTomashpolskiy 1. Please be polite. 2. Read this comment by a compiler engineer: https://habrahabr.ru/post/313350/comments/#comment_9885460 – ZhekaKozlov Jun 03 '17 at 03:49
  • @ZhekaKozlov, you don't need to be a compiler engineer to read JRE source code and use javap/debugger. What you're missing is that generation of a wrapper class for a lambda method is done entirely in-memory and costs next to nothing, while instantiating an AIC involves resolving and loading the corresponding class resource (which means I/O system call). Hence, `invokedynamic` with ad-hoc class generation is blazing fast compared to compiled anonymous classes. – Andrei Tomashpolskiy Jun 05 '17 at 12:56
  • @AndreiTomashpolskiy I/O is not necessarily slow – ZhekaKozlov Jun 05 '17 at 13:22
18

There are following differences:

1) Syntax

Lambda expressions looks neat as compared to Anonymous Inner Class (AIC)

public static void main(String[] args) {
    Runnable r = new Runnable() {
        @Override
        public void run() {
            System.out.println("in run");
        }
    };

    Thread t = new Thread(r);
    t.start(); 
}

//syntax of lambda expression 
public static void main(String[] args) {
    Runnable r = ()->{System.out.println("in run");};
    Thread t = new Thread(r);
    t.start();
}

2)Scope

An anonymous inner class is a class, which means that it has scope for variable defined inside the inner class.

Whereas,lambda expression is not a scope of its own, but is part of the enclosing scope.

Similar rule applies for super and this keyword when using inside anonymous inner class and lambda expression. In case of anonymous inner class this keyword refers to local scope and super keyword refers to the anonymous class’s super class. While in case of lambda expression this keyword refers to the object of the enclosing type and super will refer to the enclosing class’s super class.

//AIC
    public static void main(String[] args) {
        final int cnt = 0; 
        Runnable r = new Runnable() {
            @Override
            public void run() {
                int cnt = 5;    
                System.out.println("in run" + cnt);
            }
        };

        Thread t = new Thread(r);
        t.start();
    }

//Lambda
    public static void main(String[] args) {
        final int cnt = 0; 
        Runnable r = ()->{
            int cnt = 5; //compilation error
            System.out.println("in run"+cnt);};
        Thread t = new Thread(r);
        t.start();
    }

3) Performance

At runtime anonymous inner classes require class loading, memory allocation and object initialization and invocation of a non-static method while lambda expression is pure compile time activity and don’t incur extra cost during runtime. So performance of lambda expression is better as compare to anonymous inner classes.**

**I do realize that this point is not entirely true . Please refer following question for details. Lambda vs anonymous inner class performance: reducing the load on the ClassLoader?

atom217
  • 971
  • 1
  • 14
  • 26
3

Lambda's in java 8 was introduced for functional programming. Where you can avoid boilerplate code. I came across this interesting article on lambda's.

http://radar.oreilly.com/2014/04/whats-new-in-java-8-lambdas.html

It's advisable to use lambda functions for simple logics. If implementing complex logic using lambdas will be a overhead in debugging the code in case of issue.

Tim
  • 1,321
  • 1
  • 22
  • 47
1
+----------------------------------+----------------------------------------------------------+---------------------------------------------+
|                                  |                                       Lambdas            |              Anonymous classes              |
+----------------------------------+----------------------------------------------------------+---------------------------------------------+
| Definition                       | An anonymous method that can be created without belonging| An inner class without a name.              |
|                                  | to any class                                             |                                             |
+----------------------------------+----------------------------------------------------------+---------------------------------------------+
| Scope of variables of main class | Available                                                | Not available                               |
| (this and super keywords also)   |                                                          |                                             |
+----------------------------------+----------------------------------------------------------+---------------------------------------------+
| Lines of codes                   | Reduced the lines of code. It’s a short form of          | Have more lines of code compared to lambdas |
|                                  | anonymous class.                                         |                                             |
+----------------------------------+----------------------------------------------------------+---------------------------------------------+
| Criteria for creating            | Needs to be Functional Interface, ie interface with      | Can use interfaces(including Functional     |
|                                  | only one abstract method. Example : Runnable Interface   | interfaces) and abstract classes to create. |
+----------------------------------+----------------------------------------------------------+---------------------------------------------+
| Example:                         | Runnable r = ()->{System.out.println("Hello World");};   | Runnable r = new Runnable() {               |
|                                  |                                                          |         @Override                           |
|                                  |                                                          |         public void run() {                 |
|                                  |                                                          |          System.out.println("Hello World"); |
|                                  |                                                          |                                        }    |
|                                  |                                                          |     };                                      |
+----------------------------------+----------------------------------------------------------+---------------------------------------------+
Joby Wilson Mathews
  • 10,528
  • 6
  • 54
  • 53
0
  • lambda syntax does not require to write the obvious code that java can infer.
  • By using invoke dynamic, lambda are not converted back to the anonymous classes during compile time (Java do not have to go through creating objects, just care about signature of the method, can bind to method without creating object
  • lambda put more emphasis on what we want to do instead what we have to do before we can do it
MagGGG
  • 19,198
  • 2
  • 29
  • 30
0

Anonymous class are there to stay because lambda is good for functions with single abstract methods but for all other cases anonymous inner classes are your saviour.

spidy
  • 539
  • 1
  • 6
  • 7
0

Lambdas Expression covers only a very specific case of the Anonymous Inner classes. You can consider like Anonymous Inner classes is the superset of Lambdas Expression

Lambdas Expression ⊂ Anonymous Inner classes

There are some scenario in which Anno. inner class can be replaced by Lambda Expression:

  1. If the the inner classes to be implemented is a functional Interface (having only one abstract method)

ex:

Interface A{
 public void m1();
 public void m2();
}

Interface B{
 public void m();
}

Class Temp{
 public static void main(String[] args){
  // Anonymous inner class implementation
  A a = new A()
  {
   public void m1(){
    //
   }
   public void m2(){
    //
   }
  };
  a.m1(); or a.m2();
 
  // Here B is a functional Interface so we can replace the anonymous class to Lambda Expression
  B b = () => { ... }
  b.m();
  
 }
}

Apart from that there are some differences on the compiling style of both. For the Lambda Expression compiler do not generate any another class but it generates for the Anon. Inner class

akhil singhal
  • 111
  • 1
  • 7