14

I had a question about reusability of lambda expression without code duplication. For example if I have a helper method I can easily code it as a static method and can refer to it from other classes without code duplication. How would this work in lambda expression ? Example: I have the following static method written

public class MyUtil {

    public static int doubleMe(int x) {
        return x * 2;
    }
}

I can reuse the same method without code duplication in multiple places across the project

public class A {

    public void someOtherCalculation() {
        MyUtil.doubleMe(5);
    }
}

public class B {

    public void myCalculation() {
        MyUtil.doubleMe(3);
    }
}

How would it work when it comes to a lambda function, write the function once and use the same at multiple class.

Function<Integer, Integer> doubleFunction = x -> x * 2;

In my example, where would I write the above lambda function and how would I reuse the same in class A and B ?

2
  • 4
    "Code reuse" is a false goal here. Code expressiveness is what's​ needed. What possible harm is there from using a lambda that doesn't "reuse" code, and what evidence do you have that it doesn't? Lambdas are for when many different functors can substitute in an algorithm. Would you write an explicit static method for all of them, and create a method reference for each just so you can say, "Look, Mommy, I'm using lambdas!"? Doesn't it make more sense just to use lambdas conventionally in such cases? What's the real engineering benefit you seek? Commented May 29, 2017 at 17:26
  • If you want to reuse a function, then define a class that implements the Function interface. An static method is not a function. Commented Dec 11, 2017 at 21:24

5 Answers 5

11

Where would I write the above lambda function

Since your function does not reference any fields, it is appropriate to put it in a static final field:

class Utility {
    public static final Function<Integer,Integer> doubleFunction = x -> x * 2;
}

how would I reuse the same in class A and B?

You would refer to it as Utility.doubleFunction, and pass it in the context where it is required:

callMethodWithLambda(Utility.doubleFunction);

Note that method references let you define a function, and use it as if it were lambda:

class Utility {
    public static Integer doubleFunction(Integer x) {
        return x*2;
    }
}
...
callMethodWithLambda(Utility::doubleFunction);

This approach is very flexible, because it lets you reuse the same code in multiple contexts as you find appropriate.

Sign up to request clarification or add additional context in comments.

Comments

4

Really, anonymous functions are for cases where code reuse isn't necessary.

Dumb example, but say you're using map to add two to every number in a list. If this is a common action that you may need all over the place, a static function that adds two to a number makes more sense than writing the same lambda everywhere.

If, however you have a single function that adds two to a list, it makes more sense to define the "add two" function locally as a lambda so you dont plug up your class with code that isn't needed anywhere else.

When writing Clojure, which makes extensive use of higher-order functions, it's pretty common for me to create local anonymous functions that tidy up the code in the "full" function that I'm writing. The vast majority of these anonymous functions would be non-sensical in the "global" scope (or class-scope); especially since they usually have closures over local variables, so they couldn't be global anyways.

1 Comment

I have always assumed this, but never read it anywhere. Very helpful.
2

With lambda expressions, you don't need to worry about reusability (in fact, most of the lambdas are not being re-used at all). If you want a Function pointer to point to this method the you can declare one like below:

Function<Integer, Integer> doubleFunction = MyUtil::doubleMe;

And pass it to any method or stream to apply/map, e.g.:

public static void consume(Function<Integer, Integer> consumer, int value){
    System.out.println(consumer.apply(value));
}

public static void main(String[] args) throws Exception{
    Function<Integer, Integer> doubleFunction = MyUtil::doubleMe;
    consume(doubleFunction, 5);
}

Comments

2

Different from other answers. I'd like to answer your question in TDD way.

IF your doubleMe is so simple as you have wrote, that is clrealy you should stop abusing method expression reference and just call it directly as a common method invocation.

IF your doubleMe is so complicated that you want to test doubleMe independent , you need to make implicit dependencies explicity by dependency injection to testing whether they can working together by their cummunication protocols. But java can't refer a method dierctly except you using reflection api Method/using a anonymous class that implements SAM interface which delegates request to a method before in jdk-8. What the happy thing is you can refer a method expression reference to a functional interface in jdk-8. so you can make implicit dependencies explicit by using functional interface, then I would like write some communication protocol test as below:

@Test
void applyingMultiplicationWhenCalculating???(){
    IntUnaryOperator multiplication = mock(IntUnaryOperator.class);
    B it = new B(multiplication);

    it.myCalculation();

    verify(multiplication).applyAsInt(3);
}

AND then your classes like as B applied dependency injection is more like as below:

public class B {
    IntUnaryOperator multiplication;

    public B(IntUnaryOperator multiplication){
          this.multiplication = multiplication;
    }

    public void myCalculation() {
          multiplication.applyAsInt(3);
    }
}

THEN you can reuse a method by refer a method expression reference to a functional interface as below:

A a = new A(MyUtil::doubleMe);
B b = new B(MyUtil::doubleMe);

Comments

0

You can do something like below.

class Fn {
  public static final Function<Integer, Integer> X2TIMES = x -> x *2;
}

class Test {
  public static void main (String[] args) {
    System.out.println(Fn.X2TIMES.apply(5));
  }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.