Performance and access method optimization

Often, I come across code in which the Getter method is repeatedly used / abused to get some value or pass it as a parameter of a method, for example:

public class Test { public void someMethod() { if(person.getName() != null && person.getName().equalsIgnoreCase("Einstein")) { method1(person.getName()); } method2(person.getName()); method3(person.getName()); method4(person.getName()); } } 

I usually code it as shown below:

 public class Test { public void someMethod() { String name = person.getName(); if(name != null && name.equalsIgnoreCase("Einstein")) { method1(name); } method2(name); method3(name); method4(name); } 

In my opinion, there is a significant advantage in memory / performance when assigning getter to a variable and using it, since Getters are Java methods and use stack frames. Is there really a significant coding advantage? }

+6
source share
6 answers

You have a profiled opinion of yours recently.

Performance:

Perhaps it was micro-optimization, with which in 1999-2001. there was something interesting in the version prior to 1.2 JVM, and even then I would have questioned it if some serious figures had not been shown otherwise.

Modern JIT implementations will tell you that today your opinion is inappropriate.

Modern compiler implementations make all kinds of optimizations that make you think of such things as a waste of time in Java. JIT just makes it an even more empty problem.

Logic:

In a parallel situation, your two code blocks are not logically equivalent if you want to see the changes, so a local copy will prevent this. Depending on what you want to do, one or other approaches can create very subtle non-deterministic errors that would be very difficult to fix in more complex code.

Especially if what was return was something mutable, unlike String , which is immutable. Then even a local copy could change, unless you made a deep clone, and very quickly it was not so fast.

Observe correctly , then measure and then optimize what is important if it does not make the code less maintainable.

The JVM will embed any calls to members of the final instances and delete the method call if there is nothing in the method call but return this.name; . He knows that there is no logic in the access method and he knows the final link, so that he knows that he can embed the value because it will not change.

To this end

 person.getName() != null && person.getName().equalsIgnoreCase("Einstein") 

expressed more correctly as

 person != null && "Einstein".equalsIgnoreCase(person.getName()) 

because there is no way to have a NullPointerException

Refactoring:

Modern IDE refactoring tools remove any arguments about the need to change the code in a bunch of places.

+16
source

There is no difference in performance. If there is, then it is trivially small.

More importantly, two code examples actually behave very differently in the presence of multiple threads.

Say that halfway someone is calling setName and changing the name. Now your code goes in a completely unexpected way! This actually became the main cause of several historical (even at the kernel level) security vulnerabilities.

Please note that I am not a supporter of blind copying of all the results that you get in local variables. I am just pointing out a potential trap.

+4
source

If your reasoning is that you are doing something in Java, it is because β€œit can work better,” you are doing it wrong. The JIT compiler optimizes the trivial case of public String getName(){return name;} . Instead, you should make decisions based on "this is the right way for OOP to do this"

From an OOP perspective, use only a getter. Then the subclass can override the method as necessary to do other bizarre things (for example, ignore the name "Einstein").

+2
source

This, of course, is much more readable if you put the value in a local variable, so you should do it, and not because it works better.

Another massive difference is that getName() has a side effect (which it should not have, but you cannot trust other classes blindly), or if you are working in a multi-threaded system. In the first case, the difference is obvious, in the second case, another thread can change the value getName() returns during the execution of your statement.

In both cases, you probably want to call getName() only once.

+1
source

I would agree in principle that preliminary optimization is evil, but I still prefer to use the second form. The main reason is that it is consistent with other cases than getters, where it would be foolish to repeat it, for example, an expensive operation:

 if(person.expensiveOp() != null && person.expensiveOp().equalsIgnoreCase("Einstein")) { method1(person.expensiveOp()); } method2(person.expensiveOp()); method3(person.expensiveOp()); method4(person.expensiveOp()); 

Also, with the syntax highlighting the IDE, I can highlight all the value values. Someone will answer that you can also highlight all the ways to use the method. But there may be several calls to the same method in different instances of the object (i.e. toString() )

0
source

I did some research on this topic, asking a question and found what I was looking for. The problem was that I did not use the correct terminology when formulating the question. ' Inline Expansion ' (Compiler Inlining) is what I was looking for. Here is a quote from the Wiki:

When calculating, a built-in extension or embedding is a manual or compiler optimization that replaces the function call site with the body called. This optimization can improve time and space at run time, at a possible cost to increase the final size of the program (i.e. binary file size).

I also found that this issue has already been discussed on this site:

1) Amplifiers and setters affect performance in C ++ / D / Java?

Here is a quote from the link above:

In Java, the JIT compiler will probably turn it on sooner or later. As far as I know, the JVM JIT compiler only optimizes heavily used code, so you can first see the overhead of the function while getter / setter was called quite often .

2) Embedding in Java

0
source

Source: https://habr.com/ru/post/909591/


All Articles