5

I have been using Java 8 from last couple of months and trying to get my head around lambdas. I have a quite bit understanding about concert. But struggling with custom functional interface execution as lambda call.

If I create java Bifuctional interface implementation

BiFunction<t1,t2,R> trade = (t1, t2) -> {
  // calling another method for merger
  return t1,t2;
};

Can I call it as lambda just like below?

(a, b)-> trade: 

Or do I have to create execute method?

private int execute(BiFunction<t1,t2,R> trade, int a, int b){ 
    return trade.apply(a, b)
}

Here is an example of code that calls the lambda:

BiFunction<t1,t2,R> trade = (t1, t2) -> {
                                         // calling another method for merger return t1+t2;
                                        };

public static void main(String[] args) {
  execute(trade , 1, 2);
}

private int execute(BiFunction<t1,t2,R> trade, int a, int b) {
  return trade.apply(a, b);
}

I am curious why compiler can not understand this

public static void main(String[] args) { int i= (1,2) -> trade; }
user2672165
  • 2,986
  • 19
  • 27
Maddy
  • 73
  • 1
  • 5
  • 5
    A lambda expression is not something you _call_. – Sotirios Delimanolis Jun 18 '15 at 16:25
  • do you know any better and generic way to call them other than creating execute method for each of them? – Maddy Jun 18 '15 at 16:31
  • 1
    @Maddy can you give an example of code where you need to "call" the lambda? – assylias Jun 18 '15 at 16:37
  • BiFunction trade = (t1, t2) -> { // calling another method for merger return t1+t2; }; public static void main(String[] args) { execute(trade , 1, 2): } private int execute(BiFunction trade, int a, int b){ return trade.apply(a, b) } I am curious why compiler can not understand this public static void main(String[] args) { int i= (1,2) -> trade ; } – Maddy Jun 18 '15 at 16:48
  • 1
    @Maddy It's better to edit your question than complete it in the comments - I have done it for you. – assylias Jun 18 '15 at 21:20
  • 1
    In your example, you can write: `int i = trade.apply(1, 2);` which is not that different from `int i = (1, 2) -> trade;` – assylias Jun 18 '15 at 21:22
  • @assylias thanks!! compiler recognizes int i = trade.apply(1, 2); but not int i = (1, 2) -> trade;. that mean i have declare lambda and assign it to one of those functionalIterfaces (in this case BiFunction) and then call apply method. it seem like some boilerplate code everywhere. not a big fan of it. :( – Maddy Jun 19 '15 at 14:55
  • Any time you declare a method which can accept a lambda, you have to call it. The magic is all on the calling side - the side receiving the lambda is much more basic. The compiler translates the simple lambda into an interface that the receiving code can invoke an operation on. – absmiths Jan 17 '19 at 21:44

2 Answers2

7

You use lambda like this

public static void main(String[] args) {
    BiFunction<Integer, Integer, Integer> add = (x, y) -> {
        return x + y;
    };
    System.out.println(add.apply(1, 2));
}
Filip Bulovic
  • 1,776
  • 15
  • 10
  • thanks filip. this is what i am eventually doing. calling apply method. i think i am curious if i can do public static void main(String[] args) { BiFunction add = (x, y) -> { return x + y; }; int i = (1,2) -> add); System.out.println(i); } May be i am very optimistic.. – Maddy Jun 18 '15 at 16:53
  • @Maddy no, that makes no sense. Call `add.apply(1, 2)`. – Louis Wasserman Jun 18 '15 at 18:14
  • @LouisWasserman didn't notice that `(1, 2)->add` compiler will refuse to deal with expression – Filip Bulovic Jun 18 '15 at 18:22
  • Well, yeah. It makes no sense at all. That's not how the syntax works. – Louis Wasserman Jun 18 '15 at 18:22
6

If you're a long time Java coder, the new lambda stuff can be confusing -- it was(is?) for me. Lambdas are a contextual construct that the compiler interprets based on the context where it is used, just like a lot of other scripting languages. For most cases, you never need to create your own sub-types because the compiler does it for you based on where you are using them. Objectively, we think, "Yeah, I know. Duh." But it's tough making your brain change thought patterns. That's one of the big hurdles I think a lot of developers need to overcome.

I can see how we want to think, "Gee, I want my own BiConsumer that concatenates two Strings and adds them to a List." So you generate your class file in your favorite IDE and get

public static class StringConcat implements BiConsumer<String,String>{
    private List<String> values = new ArrayList<>();

    @Override
    public void accept(String s, String s2) {
        values.add(s,s2);
    }
}

And when you go to try and find a good use for it you can't really seem to find one. That's because there isn't any need to create one.

I've been hard-pressed to find a situation where I need to create my own class that implements any of the java.util.function stuff. Not saying there aren't cases, I just haven't found too many.

It boils down to recognizing when you have something that takes a type that has a single abstract method, like Comparable.compare(T t1, T t2) or Runnable.run(). In these cases, you simply in-line the lambda construct.

So using the functionality of my StringConcat, given a Map<String,String> map

    // I just passed it a new BiConsumer!
    map.forEach((k,v)-> list.add(k+v));


EDIT: After your comments and re-reading your question, I think you still have a bit of a mental block. It looks as though you want to declare a lambda, instantiate it and call it in three distinct steps. That sort of defeats the purpose. When you use lambdas, you do the first two steps when you create the lambda inline with something that takes it.
//                      declare AND instantiate
stringList.stream().map(string -> Integer.parseInt(string))...

This is saying, "for every string in the list, apply this function, Integer.parseInt(string)." Notice you don't ever call apply(). That's done within the map method. This avoids the need to do what you are doing with creating an instance and separately trying to call it.

Lambdas are not a magic bullet. In most cases, you still need to have separate methods with distinct statements. Maybe the functionality you want doesn't play well with lambdas.

MadConan
  • 3,749
  • 1
  • 16
  • 27
  • thanks for the thought sharing and i think i am straggling with same. i would also like to listen you thought about. calling legacy method in lambdas. so let us say i have method m in a class. public void test(int i1 , int i2){ retr – Maddy Jun 18 '15 at 18:29
  • If I understand you, this is very easy. Simply call the method within the lambda. `Mything thing = new Mything(); (Map) map.forEach((i1,i2) -> thing.test(i1,i2));` – MadConan Jun 18 '15 at 18:47
  • thats what exactly what i meant and i understand thats way it work with foreach becoz forEach input parameter is Consumer super T>. But now i want to call this method from mything class in between my code block.. public void newMethod() {some code before; int r=thing.test (as lambda not traditional method call); – Maddy Jun 18 '15 at 18:57
  • Added more info. Hope it helps. – MadConan Jun 18 '15 at 20:31