可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
say suppose I have class as :
public class Age {
private int age;
public int getAge() {
return this.age;
}
}
In my Main class I am calling the getAge()
method many times.
So I wanted to know is it advisable to call so many times or call once and assign it to some variable and use that variable.
Which is best and why?
回答1:
This is likely a situation where you are optimizing before you know you need to. The value is just an integer so it is not taking up a lot of memory if you store the value in multiple places. At the same time, it is a very simple method call that will not take much time to execute. Write it in a way that you feel is most readable. Then after you have a solid version of the code, you can use a profiling tool to see if there is a noticeable difference.
回答2:
Don't try to micro-optimize this, unless you find that it's truly a bottleneck while profiling. I'd use the getAge() accessor method, since it's most likely the most maintainable and obvious solution.
That being said, the two approaches are likely to perform exactly the same. At runtime, the JIT will most likely optimize away the getAge() call entirely, so it will be a single primitive access in both cases.
回答3:
There may be some performance overhead of calling the getAge()
method many many times, but I suggest you consider The Sad Tragedy of Micro-Optimization Theater.
回答4:
This is something that you, as the API writer, have to indicate to the caller.
In general, if you are simply returning a property, you can mark the call as a final (if you are not offering an actual interface). That should reduce the costs of calls since the compiler would be more likely to inline the function.
If the cost of calculating the property is expensive (E.g., a string lookup), document it in the JAvaDocs for that method, and indicate to the caller that they may want to obtain the value once and cache it.
回答5:
Don't bother. It's absolutely not worth micro-optimizing like this. Wait until you finish your code, then it runs too slowly, then get out a profiler and work on what the profiler tells you is the source of the problem.
Premature optimization is the root of all evil.
回答6:
Depending on how your application is designed, the two options might actually give different results! If the age instance you're using is shared and mutable, different places in your application might change its value in between your calls to getAge()
. In this case, it's a matter of correctness to decide which is the best option for your code, and it's up to you to decide. As the old adage says: "first make it right, then make it fast". And, as others have already mentioned, you probably won't need to worry about the "make it fast" part in this case.
A related example is when you're changing a collection while iterating through it. You have to iterate over a snapshot to not get a ConcurrentModificationException
.
回答7:
I'll try to say with code examples what the other answer already said.
In the case you presented the call for getAge() is very very simple, and the cost of calling it is almost nothing. Don't bother with it in this case.
But if your getAge was something fancy that do lots of calculations or access IO resources, like:
public int getAge() {
return slowService.calculateAgeByBirthDate(birthDate); // it takes 2 seconds to execute for every call
}
Then for sure it would be a good idea to cache de result and use it. Because if you call it 30 times your code will take 1 minute to complete.
回答8:
i think you will see no difference at runtime - assuming you do not create more than one Age class.
回答9:
For a simple case like this, I'd go for the one that looks best code-wise.
There are a few cases where it is advisable to call once and read the saved return value, such as in
for (int i = 0; i < list.size(); i++)
doSomethingThatDoesNotAffectSizeOfList();
since the compiler may have trouble figuring out if the body of the loop affects the size of the list. A properly implemented list should always be able to tell it's size easily, but in other examples (or when dealing with poorly implemented collections) it might be worse.
In general, if a method is computationally heavy, you could use memoization, which basically means that you cache already computed input / output values.
A memoized function "remembers" the results corresponding to some set of specific inputs. Subsequent calls with remembered inputs return the remembered result rather than recalculating it, thus eliminating the primary cost of a call with given parameters from all but the first call made to the function with those parameters.
This technique pushes the "save-the-return-value-for-efficiency" into the method itself, which eases the maintenance bla bla bla...
回答10:
The tricky part is understanding that modern JVM's do aggressive optimizations when compiling byte code based on the knowledge available at runtime.
If, for instance, a given method is not overridden in a subclass it can be treated exactly the same as a final method, allowing the JVM to inline a copy of its code in the calling method instead of explicitly doing a method call. (If conditions change, those classes are then simply considered new and hence recompiled later based on the new conditions).
This means that get/set for bean attibutes (where the values are simply stored and retreived, and not calculated) are very cheap and you should do the calls everytime and expect the JVM to detect the possible optimizations and apply them.
回答11:
You won't see much change in performance unless if you are doing many operations inside the getAge() method.
回答12:
In this case, I'd suggest don't look at performance, look at usability and code reuse. Your current implementation is the simplest of getters, one that returns an integer.
But what if somewhere down the line you store a person's birthdate and want to dynamically generate the age? If you simply call the property directly, you then are forced to refactor your code. However, altering getAge()'s internals, you can put the calculation in there, and you're done.
I'd really like programming languages to introduce a 'super-private' property / field modifier, one that basically says 'You can only access this property through its accessor'.