3

I am starting to learn how to develop with Optional in java8. It might be it is somwehere documented, but I have been using google with no accurate result.

I have different possible implementations for the orElseGet method, and I am not sure if java makes a better memory handling in some case, or if its pretty much the same.

Lets say I have a method in a class with an Optional defined:

class myClass {

  final static private Supplier<Object> MY_SUPPLIER = () -> new Object();

  private void myMethod1 () {
    Optional<Object> x; // somehow Initialized
    Object y = x.orElseGet(() -> new Object());
  }

  private void myMethod2 () {
    Optional<Object> x; // somehow Initialized
    Object y = x.orElseGet(MY_SUPPLIER);
  }
}

From my humble point of view, this second should have better memory management in java, since it's only declared once the Supplier, and it is always used the same.

1) is this true?

Now, let's go further, and imagine we need to supply different object depending on parameters.

class myClass2 {

  final static private Function<String, Supplier<AnyCustomClass>> MY_SUPPLIER_PROVIDER = (p) -> () -> new AnyCustomClass(p);

  private void myMethod1 (String arg) {
    Optional<AnyCustomClass> x; // somehow Initialized
    AnyCustomClass y = x.orElseGet(() -> new AnyCustomClass(arg));
  }

  private void myMethod2 (String arg) {
    Optional<AnyCustomClass> x; // somehow Initialized
    AnyCustomClass y = x.orElseGet(MY_SUPPLIER_PROVIDER.apply(arg));
  }
}

In this case, depending on the argument, each time it returns different supplier.

2) Does java have better memory management here also?

3) Do they somehow get "cached" for arg taking same value?

EDIT

By watching Does a lambda expression create an object on the heap every time it's executed? I understand that my first class behaviour is answered. Since there are no local variables, it will create a singleton (at least oracle jvm)

How ever, I do not feel like that answer provides accurate information to answer my 2) and 3)

Mayday
  • 4,680
  • 5
  • 24
  • 58
  • Possible duplicate of [Does a lambda expression create an object on the heap every time it's executed?](https://stackoverflow.com/questions/27524445/does-a-lambda-expression-create-an-object-on-the-heap-every-time-its-executed) – tsolakp Nov 06 '18 at 14:34
  • The linked answer does say that it is not well defined how different JVM will handle lambda caching. – tsolakp Nov 06 '18 at 14:56

1 Answers1

1

The difference between both methods is you're reusing the supplier, which will reuse objects thus save you some memory. The thing you need to be careful with here is possible threading issues. Since you're using the same memory you need to make sure different threads do not try to use the same object.

So to answer your questions:

1.) Yes, but you may have other issues.

2.) It the same as the first question? You're reusing a instance of the Function. This is'nt how you're supposed to be using Function in this context.

3.) It's 'cached' in that the instance of the function is reused.

In general I'd stay away from your second options, unless this is being called something like 1000 / second you're trading added complexity which is not going to translate into noticeable performance.

If you're interested in what the performance is going to look like write a unit test which calls this multiple times on different threads and monitor the run with the profiler.

Doctor Parameter
  • 1,202
  • 2
  • 15
  • 21
  • I´ve made that unit test (changing original methods to return the object inside the Optionals to avoid JIT optimizations. The performance is slightly better with the lambda, since myMethod2 adds one extra Function call to get the supplier. lambda: average= 51,069619; supplier: average= 73,730204 (nanoseconds) – EduSanCon Nov 06 '18 at 15:12
  • @littleLouito You can't seriously benchmark using unit tests or alike. There are too many JIT optimizations to handle them all properly. If you want to know how the code performs in "reality" (long running process on a server), then use [JMH](http://openjdk.java.net/projects/code-tools/jmh/). – maaartinus Nov 06 '18 at 21:10
  • @maaartinus I've used a Test to wrap the code, I could have done inside a main() method. I've repeated each method 1.000.000 times, with 50.000 times as warmup, measuring each invocation isolatedly. Feeding a consumer with the values returned from the methods so that the JIT doesn't avoid anything. I'm sure the tests lack of many things, but as an approach it could help – EduSanCon Nov 06 '18 at 22:08
  • 1
    @littleLouito What you did sounds right, but it mayn't be. For example, did your consumer really used the value and did something with it what can't be optimized away? If so, then it might have taken more time than what you wanted to measure. Can you be sure, you did it right? JMH's Blackhole does the job and it's pretty complicated. Anyway, I just wanted to make you aware of the problem (Java benchmarking being much harder than everyone expects) and the standard solution (JMH), that's all. – maaartinus Nov 07 '18 at 00:28
  • 2
    @maaartinus I know JMH and I've read about microbenchmarks. That's why I say my test wasn't probably well done. But it's what I could do in five minutes :) Thanks for your comments. I Like the way this conversation show how difficult is to perform well done microbenchmarks – EduSanCon Nov 07 '18 at 00:35
  • I havent used JMH, next time I need to do something like this, I'll look into it. – Doctor Parameter Nov 08 '18 at 19:37
  • Since the question has two code examples, each of them having two methods, it is very hard to understand, which you are referring to, when you say “second options”. A similar confusion arises when you provide just a number and a “yes” next to it, without an explanation of what “yes” is supposed to mean. Even worse, looking at the question with the same number, “yes” contradicts the rest of your answer, so most likely, even you lost track here. – Holger Dec 19 '18 at 11:13