Efficiency of method call in for loop condition - java

I am writing a game engine, in which a set of objects held in a ArrayList are iterated over using a for loop. Obviously, efficiency is rather important, and so I was wondering about the efficiency of the loop.
for (String extension : assetLoader.getSupportedExtensions()) {
// do stuff with the extension here
}
Where getSupportedExtension() returns an ArrayList of Strings. What I'm wondering is if the method is called every time the loop iterates over a new extension. If so, would it be more efficient to do something like:
ArrayList<String> supportedExtensions = ((IAssetLoader<?>) loader).getSupportedExtensions();
for (String extension : supportedExtensions) {
// stuff
}
? Thanks in advance.

By specification, the idiom
for (String extension : assetLoader.getSupportedExtensions()) {
...
}
expands into
for (Iterator<String> it = assetLoader.getSupportedExtensions().iterator(); it.hasNext();)
{
String extension = it.next();
...
}
Therefore the call you ask about occurs only once, at loop init time. It is the iterator object whose methods are being called repeatedly.
However, if you are honestly interested about the performance of your application, then you should make sure you're focusing on the big wins and not small potatoes like this. It is almost impossible to make a getter call stand out as a bottleneck in any piece of code. This goes double for applications running on HotSpot, which will inline that getter call and turn it into a direct field access.

No, the method assetLoader.getSupportedExtensions() is called only once before the first iteration of the loop, and is used to create an Iterator<String> used by the enhanced for loop.
The two snippets will have the same performance.

Direct cost.
Since, as people said before, the following
for (String extension : assetLoader.getSupportedExtensions()) {
//stuff
}
transforms into
for (Iterator<String> it = assetLoader.getSupportedExtensions().iterator(); it.hasNext();) {
String extension = it.next();
//stuf
}
getSupportedExtensions() is called once and both of your code snippets have the same performance cost, but not the best performance possible to go through the List, because of...
Indirect cost
Which is the cost of instantiation and utilization of new short-living object + cost of method next(). Method iterator() prepares an instance of Iterator. So, it is need to spend time to instantiate the object and then (when that object becomes unreachable) to GC it. The total indirect cost isn't so much (about 10 instructions to allocate memory for new object + a few instructions of constructor + about 5 lines of ArrayList.Itr.next() + removing of the object from Eden on minor GC), but I personally prefer indexing (or even plain arrays):
ArrayList<String> supportedExtensions = ((IAssetLoader<?>) loader).getSupportedExtensions();
for (int i = 0; i < supportedExtensions.size(); i++) {
String extension = supportedExtensions.get(i);
// stuff
}
over iterating when I have to iterate through the list frequently in the main path of my application. Some other examples of standard java code with hidden cost are some String methods (substring(), trim() etc.), NIO Selectors, boxing/unboxing of primitives to store them in Collections etc.

Related

High performance impact of assigning an iterator's return value in Java?

I have an implementation of Iterable<T> (a variation of a quadtree structure), which I plan to use in a setting where performance with large data sets is critical, so I have been conducting a few tests, with a couple million random entries, running them repeatedly. I experienced an oddity with the following code segment:
long start = System.currentTimeMillis();
for (int i = 0; i < 100; i++) {
Iterator<A> iter = it.iterator();
while (iter.hasNext()) {
iter.next();
}
}
long end = System.currentTimeMillis();
System.out.println("Total time: " + (end - start));
I always got a time between 4000 and 5000 milliseconds. However, when I changed the while loop to this:
A a = null;
while (iter.hasNext()) {
a = iter.next();
}
the time jumps up -- not just slightly, but all the way up to 15 to 16 seconds, with complete consistency. Now this already does not seem dependent on the implementation of next(), but upon further investigation, I found that it even happens with a simple ArrayList, so I'll post compilable code for that instead:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Test {
static class A {}
public static void main(String[] args) {
List<A> list = new ArrayList<>();
// Add a lot of entries
for (int i = 0; i < 10000000; i++) {
list.add(new A());
}
// Test it
A a = null;
Iterator<A> iter = null;
long start = System.currentTimeMillis();
for (int i = 0; i < 100; i++) {
iter = list.iterator();
while (iter.hasNext()) {
iter.next();
// Or:
// a = iter.next();
}
}
long end = System.currentTimeMillis();
System.out.println("Total time: " + (end - start));
}
}
The result: an even more unbelievable 30-fold difference. And it happens deterministically, every time.
What possible reason could there be for this? I don't see how a single assignment to an already allocated variable could be anything other than negligible, especially considering that so much else is happening inside iter.next(). My only guess is that the System.currentTimeMillis() calls are somehow not executed at the proper time, but as for how this is affected by the change, I have no idea.
But even that doesn't quite fit, because the time it takes is noticably much, much longer, especially if I further increase the number of times the for loop runs. The garbage collector also should not have anything more to do, as far as I see, since no wasteful, temporary allocations should be happening. It also apparently is the assignment of the return value that's critical, since just doing something else in addition to iter.next(), like increasing an int variable each time, does not have the same adverse effect on execution time.
EDIT: It has been brought to my attention by multiple people that the particular benchmark in my post suffers from many issues that can compromise its results' trustworthiness. I will leave it here for posterity though, or possibly update it later to make it better. That having been said, the phenomenon's most likely cause has been identified in the accepted answer, and I confirmed that eliminating the typecast solved the issue, so despite the benchmark's shortcomings the observation above appears to not have been just a side-effect of those.
I think that a lot of the discrepancies you are seeing will be down to the way that you are benchmarking. I see no sign that you have attempted to deal with JVM warmup effects, or to isolate the GC and memory allocation effects. Or even the effects of memory cache sizes.
But I think I know what might be going on anyway.
The difference between
while (iter.hasNext()) {
iter.next();
}
and
A a = null;
while (iter.hasNext()) {
a = iter.next();
}
is (obviously!) the assignment. But the assignment also has a hidden type cast to check that the value returned by next() is really an A. (Hint: generic type erasure ...)
But how could the type casts make that much time?
Well, my theory is that this is a combination of the cost of the typecast itself, and a memory cache / locality effect.
In the first example, the iteration is reading references sequentially from a large array. That is a relatively cache friendly thing to do ... since the array will be a single contiguous block in memory, and the hardware is liable to fetch multiple words into the cache in a single operation. (Indeed, the JIT might even issue cache prefetch instructions ... to avoid pipeline stalls. (That's a guess ...))
In the second example, between reading each reference, the CPU will also be doing a typecast. The typecast involves retrieving a class identifier from each A instance's header, and then testing to see if it is the correct one.
Retrieving the identifier from the object header is a memory fetch from a different part of memory each time. The objects may start out contiguous in memory, but even so the spacing is liable to be multiple words apart. The cache will be far less effective. And even the fact that both the array and the objects are passing through the same cache will be significant.
Testing the class identifier may be non-trivial. If A is class not an interface and it has no subclasses, then the runtime should be able to do the equivalent of an == test. Otherwise, the test will be more complicated and more expensive.
A second possible explanation is related to code inlining. If the Iterator::next() call is small enough to be inlined, then the JIT compiler's peep-hole optimizer may be able to deduce that some or all of the next code is redundant in the assignment-less version of the code. However, I doubt that it could deduce next() is entirely redundant because of the concurrent modification checks. Eliminating those checks would change the code behavior in edge cases and would be an invalid optimization.
In short, it is not difficult to see how the addition of an assignment and the associated hidden typecase could have a significant performance impact, especially on a large data structure.

Why do we need to avoid mutations while coding? What is a mutation?

Why is the second code (the one with the stream) a better solution than the first?
First :
public static void main(String [] args) {
List<Integer> values = Arrays.asList(1,2,3,4,5,6);
int total = 0;
for(int e : values) {
total += e * 2;
}
Second :
System.out.println(total);
System.out.println(
values.stream()
.map(e-> e*2)
.reduce(0, (c, e)-> c + e));
Mutation is changing an object and is one common side effect in programming languages.
A method that has a functional contract will always return the same value to the same arguments and have no other side effects (like storing file, printing, reading). Thus even if you mutate temporary values inside your function it's still pure from the outside. By putting your first example in a function demonstrates it:
public static int squareSum(const List<Integer> values)
{
int total = 0;
for(int e : values) {
total += e * 2; // mutates a local variable
}
return total;
}
A purely functional method doesn't even update local variables. If you put the second version in a function it would be pure:
public static int squareSum(const List<Integer> values)
{
return values.stream()
.map(e-> e*2)
.reduce(0, (c, e)-> c + e);
}
For a person that knows other languages that has long been preferring a functional style map and reduce with lambda is very natural. Both versions are easy to read and easy to test, which is the most important part.
Java has functional classes. java.lang.String is one of them.
Mutation is changing the state of an object, either the list or some custom object.
Your particular code does not cause a mutation of the list either way, so there's no practical benefit here of using lambdas instead of plain old iteration. And, blame me, but I would use the iteration approach in this case.
Some approaches say that whenever you need to modify an object/collection, you need to return a new object/collection with the modified data instead of changing the original one. This is good for collection for example when you concurrently access a collection and it's being changed from another thread.
Of course this could lead to memory leaks, so there are some algorithms for managing memory and mutability for collection i.e. only the changed nodes are stored in another place in memory.
While Royal Bg is right you're not mutating your data in either case, it's not true that there's no advantage to the second version. The second version can be heavily multithreaded without ambiguity.
Since we're not expecting to iterate the list we can put the operations into a heavily multi-threaded context and solve it on a gpu. In the latter one each data point in the collection is multiplied by 2. Then reduced (which means every element is added together), which can be done by a reduction.
There are a number of potential advantages to the latter code not seen in the former. And while neither code element actually mutates, in the second one we are given the very clear contract that the items cannot mutate while that is happening. So we know that it doesn't matter if we iterate the list forwards, backwards, or apply it multithreaded etc. The implementation details can be filled in later. But, only if we know mutation can't happen and streams simply don't allow them.

for(Something s : something.getList())

I have quick question
Does it matter if I use clause this way :
for(Object obj : something.b.c.d.getList(){
...
}
or this
List list = something.b.c.d.getList();
for(Object obj : list){
...
}
I'm wondering if one is faster than other
The main difference is stylistic. The semantics are pretty much the same. The only significant semantic difference is that, in the second example, the list reference is named and can be accessed both inside and after the loop:
List list = something.b.c.d.getList();
for(Object obj : list){
if (list.contains(...)) { // inefficient, used purely as an illustration
...
}
}
int n = list.size();
The above cannot be achieved in the first example without evaluating something.b.c.d.getList() again.
If you are concerned that the first example repeatedly evaluates something.b.c.d.getList(), that's certainly not the case. Both of your examples evaluate the expression exactly once.
There's likely no difference in performance, but performance overall would depend on how expensive it is to access those fields (i.e. lazy loading from a framework). Accessing the fields would only happen once, regardless of whichever style you chose to use for this loop.
Both approaches are acceptable if both items are something that can be used in the enhanced-for statement.
I wouldn't concern myself with optimizations like this unless a profiler designated this particular area of your code as a trouble spot.

Enhanced for loop

I often come across cases where I want to use an enchanced for-loop for some Collection or array that I get from some object.
e.g.
items = basket.getItems();
for (int item : items) {
// Do something
}
Another way to do that is:
for (int item : basket.getItems()) {
// Do something
}
The second one is more compact and improves readability in my opinion, especially when the item variable won't be used anywhere else.
I would like to know whether the getter in the for statement has any impact in performance. Will it be optimized to something similar to the 1st one? Or will it access the getter every time? Of course the getItems() might do something quite slow (e.g. network access, etc)
Question is similar to some others, but is referring to the getter of the collection/array itself and not the size of it. However, it may be the same case in the end.
The getItems() method will be called only once in both cases. There is no difference between the two, apart from one using an extra local variable which you could use somewhere else.
As you can read in JLS 14.14.2, the enhanced for loop is translated roughly to this traditional for loop:
for (I #i = Expression.iterator(); #i.hasNext(); ) {
TargetType Identifier = (TargetType) #i.next();
Statement
}
#i is an automatically generated identifier that is distinct from any other identifiers (automatically generated or otherwise) that are in scope (ยง6.3) at the point where the enhanced for statement occurs.
From here it's clear that Expression is evaluted only once.
As you can see on the following code sample, on the enhanced for, the initialization of the collection on which to iterate is done only once. So, the second choice is more compact, and does not impact performance.
package test;
public class Main {
static class Basket {
int[] items = { 1, 2, 3 };
public int[] getItems() {
System.out.println("in getItems()");
return items;
}
}
public static void main(String[] args) {
Basket basket = new Basket();
for (int item : basket.getItems()) {
System.out.println(item);
}
}
}
Yes second one improves readability of code.
if you are getting the objects from network and then iterating over it in a for loop then I think yes it has performance impact because you are making network access every time and that is inefficient also as for a small/single object doing network access is not recommended. instead of that get it once from network access store it locally and iterate over it
thus 1st option is performance optimized in network access case
if your object is local then any method will do. there wont be much performance difference.
I don't think it will call getter every time. If it does it will get new list every time and Loop wont break. You can test this by putting simple Sysout inside getter method. Performance will be same in these two cases.

Java - Difference between for loop terminating expression

I'm just curious: Is there a difference on speed and performance between this two loops implementation? Assume that size() method returns the length of the array,collection, or object that handles a group of elements (actually it's from XOM api).
Implementation 1:
int size = someArray.size();
for (int i = 0; i < size; i++) {
// do stuff here
}
Implementation 2:
for (int i = 0; i < someArray.size(); i++) {
// do stuff here
}
From a performance point of view, there is little difference. This is because a loop can be optimized so that the size() lookup is inlined, resulting in very little performance difference.
The main difference is if the size changes while looping. The first case will try to iterate a fixed number of times. In the second case, the number of iterations will depend on the final size().
The 1st snippet is bound to execute faster since it calls size() once only. The 2nd snippet calls size() N times. Depending on the impl. it might pose significant penalty, esp. if the compiler finds hard to inline the method and/or the size() method doesn't just return non-volatile variable, etc.
I'd have rewritten it like for(int i=0, s=someCollection.size(); i<s; i++)
Note: arrays don't have size() method.
Yes, there is a difference. In the first loop, the size() method is only called once. In the second one, it's called at each iteration.
If the iteration modifies the size of the collection (which is very very uncommon), the second one is needed. In most cases, you should prefer the first one, but limit the scope of the size variable :
for (int i = 0, size = someArray.size(); i < size; i++) {
// ...
}
But most of the time, you should prefer the foreach syntax anyway :
for (Foo foo : collection) {
// ...
}
which will iterate over the array or collection efficiently, even for a LinkedList for example, where indexed access is not optimal.
Don't worry about it, JVM optimization is very aggressive these days.
Use the 2nd form, for it's more readable, and most likely as fast. Premature optimization yada yada.
And when you do need to improve speed, always profile first, don't guess.
It is extremely unlikely that caching size() in a local variable could benefit your app noticeably. If it does, you must be doing simple operations over a huge dataset. You shouldn't use ArrayList at all in that case.
Maybe it is worth to note that this construct:
for (String s : getStringsList()) {
//...
}
invokes getStringsList() only once and then operates on iterator behind the scenes. So it is safe to perform lengthy operations or change some state inside getStringsList().
Always avoid anything that can be done outside of the loop like method calls, assigning values to variables, or testing for conditions.
Method calls are more costly than the equivalent code without the call, and by repeating method calls again and again, you just add overhead to your application.
Move any method calls out of the loop, even if this requires rewriting of the code.
Benefits :-
Unless the compiler optimizes it, the loop condition will be calculated for each iteration over the loop.
If the condition value is not going to change, the code will execute faster if the method call is moved out of the loop.
Note :-
If the method returns a value that will not change during the loop, then store its value in a temporary variable before the loop.
Hence its value is stored in a temporary variable size outside the loop, and then used as the loop termination condition.

Categories