1

(credits: example from OCP Java 17 certification guide by Boyarsky and Selikoff)

To learn lambdas better, I put a breakpoint in the code (IntelliJ IDE) and started stepping through it.

Function<Integer, Integer> before = x -> x + 1;
Function<Integer, Integer> after = x -> x * 2;
Function<Integer, Integer> combinedf = after.compose(before);
System.out.println(combinedf.apply(3));

I was surprised to find that the value for x has already been assigned.

1

When I step to the next line, it is again evaluated before the call to combinedf.apply()

I don't understand why.

2

I thought it might be due to compiler optimization and tried to fool it by not hardcoding the '3'.

Scanner scanner = new Scanner(System.in);
Function<Integer, Integer> before = x -> x + 1;
Function<Integer, Integer> after = x -> x * 2;
Function<Integer, Integer> combinedf = after.compose(before);
System.out.println(combinedf.apply(scanner.nextInt()));

But I get the same result.

3

I followed @wuhoyt's suggestion and set breakpoint to All. I also split out the code. Now it shows as expected. I do not understand why the breakpoint must be set to All for it to work as expected.

Scanner scanner = new Scanner(System.in);
Function<Integer, Integer> before = x -> x + 1;
Function<Integer, Integer> after = x -> x * 2;
Function<Integer, Integer> combinedf = after.compose(before);
Integer intput = scanner.nextInt();
Integer result = combinedf.apply(intput);
System.out.println(result);
Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
likejudo
  • 3,396
  • 6
  • 52
  • 107
  • I'm not seeing the stack trace because you cut it off the image, but my guess is that you are actually breaking at the lambda code, not at the code that is defining it. So you are actually stepping into lambda execution. – Jack Aug 21 '22 at 23:02
  • @Jack oops!, I did not realize that. I have now replaced the last screenshot which now shows the stack trace. thanks – likejudo Aug 22 '22 at 01:58
  • @Jack The highlight is on the second line. – likejudo Aug 22 '22 at 02:18

1 Answers1

4

You can set 2 breakpoint on code where you create the function object.

Function<Integer, Integer> before = x -> x + 1;

when I try to put breakpoint on this line, it tells me where I want to put, it give me 3 options

  1. Line
  2. x -> x+1
  3. All

I select "All", and I put another breakpoint on line

System.out.println(combinedf.apply(3));

And the debugging process goes from

Function<Integer, Integer> before = x -> x + 1;   // create a function object
System.out.println(combinedf.apply(3));  // calling the apply method of the object
x -> x + 1        // actual execution body of the function, this is where you put your break point, so the value of x is 3

In another word


Function<Integer, Integer> before = x -> x + 1; 
// is equals
Function<Integer, Integer> before = new Function<Integer, Integer>() {
    @Override
    public Integer apply(Integer integer) {
        return integer + 1;  // this is where somehow you put breakpoint, probably find out how this happened, 
    }
};

I am using IDEA2021 Community, it give me 3 option when I click left area of the line to put breakpoint

UPDATE

Why must I select "All" for breakpoint?

I guess you are asking why there are two places, and what are the differences?

Probably because laziness-init concept in functional programming. At first, the body won`t be executed, and when you finally call apply method(terminal operation), the body will be execute. Thus you can chain these functions or do other cool stuff with lambda expressions. There are at least two steps so you get two places to set breakpoint.

I found another answer here which is very good, be sure to check it out

https://stackoverflow.com/a/24542150/16702058

Hi computer
  • 946
  • 4
  • 8
  • 19
  • thanks for your reply. I selected the lambda breakpoint. x -> x+1 and then I stepped through it – likejudo Aug 22 '22 at 01:53
  • Thanks. I updated the question. Why must I select "All" for breakpoint? – likejudo Aug 22 '22 at 02:15
  • 1
    @likejudo You have to select "Line" or "All". When you select "x -> x + 1" then the breakpoint is in the `Function`'s **implementation** (i.e., in the implicit `apply` method). Note that "All" means _both_ "Line" and "x -> x + 1". – Slaw Aug 22 '22 at 04:05
  • @Slaw if I select the lambda as breakpoint, it goes to the line to when the lambda is actually executed in the implementation? – likejudo Aug 24 '22 at 19:29