1

I'm very new to lambda expressions, so please bear with me. Say I have an interface with a single abstract function:

public interface IAbsFunc {
    public abstract void absFunc(int x);
}

In this case, I can store a lambda expression in a variable:

public class Lambda {
    public static void main(String[] args) {
        IAbsFunc obj = (int x) -> System.out.println(x);
        obj.absFunc(3);
    }
}

If I'm understanding things right, this is like storing a method in a variable. However, this can already be done with java.lang.reflect:

public class Lambda {
    public static void main(String[] args) throws Exception {
        Method obj = PrintStream.class.getDeclaredMethod("println", int.class);
        obj.invoke(System.out, 3);
    }
}

Clearly I'm missing something here. In what situation would a lambda expression be preferable?

Pshemo
  • 122,468
  • 25
  • 185
  • 269
Nick
  • 158
  • 8
  • 1
    Isn’t the necessity to add `throws Exception` already saying everything? In the first case, the compiler can tell you that everything is right, i.e. the method exists, is accessible, has the correct arguments, and will not throw checked exceptions. And that’s with significantly less code. You can even simplify the lambda expression further, to `x -> System.out.println(x)`. Or even `System.out::println` though this is not exactly the same, but close enough for most practical cases. – Holger Aug 03 '20 at 12:21

2 Answers2

5

You should understand what the reflections API is for. It is made for you to do things that are not possible, or hard to do, with other language features.

An official documentation states one (and IMO the most important) use case:

Debuggers need to be able to examine private members on classes. Test harnesses can make use of reflection to systematically call a discoverable set APIs defined on a class, to insure a high level of code coverage in a test suite.

So using reflections can be very useful in testing where you want to have full access to the code you test. You get access to private methods and fields, you can change final fields and so on. The documentation states one big disadvantage:

Because reflection involves types that are dynamically resolved, certain Java virtual machine optimizations can not be performed. Consequently, reflective operations have slower performance than their non-reflective counterparts, and should be avoided in sections of code which are called frequently in performance-sensitive applications.

The flexibility comes with performance drawbacks. There are more use cases and disadvantages that you can find in the documentation I've linked.

Using a lambda here in your case is just what a lambda is supposed to be used for (besides other things). Using reflections here is just not what reflections are made for. You can, but you shouldn't.

akuzminykh
  • 4,522
  • 4
  • 15
  • 36
2

@akuzminykh explained why you should not use reflection well. However, you asked for the advantages of lambdas:

  • static type checking (as opposed to using a String literal, which is a very bad code smell)
  • speed (reflection is slow)
  • no need for handling ReflectiveOperationExceptions
  • the invoker of the lambda does not need to know the instance upon which the method should be executed (System.out), i.e. Method#invoke has 2 parameters and IAbsFunc#absFunc only one.
    • There does not need to be an object to call the method upon in the first place. You can put more than 1 statement in the lambda expression, but with reflection you would need to define another method just for wrapping 2 statements, very wordy.
  • can be used as a callback parameter in a method
  • you can use method references, so it could be IAbsFunc f = System.out::println;

You should read up on functional programming, it is a very useful concept. Lambdas also use a concept called closures, they remember the (effectively) final variables from the scope they were defined in.

Hawk
  • 2,042
  • 8
  • 16