Is there any difference between these two loops? - java

Is there any difference performance-wise between the two code snippets below?
for(String project : auth.getProjects()) {
// Do something with 'project'
}
and
String[] projects = auth.getProjects();
for(String project : projects) {
// Do something with 'project'
}
For me, I think the second one is better, but it is longer. The first one is shorter, but I am not really sure if it is faster. I am not sure, but to me it seems like every time that loop is iterated, auth.getProjects is called. Is that not so?

Edit: #StephenC is right, the JLS is a much better place to find an answer for something of this nature. Here is a link to the enhanced for loop in the language specification. In there you will find that there are a few different types of for statements it generates but none of them would call the method more than 1 time.
Simple test shows that the method is only called once
public class TestA {
public String [] theStrings;
public TestA() {
theStrings = new String[] {"one","two", "three"};
for(String string : getTheStrings()) {
System.out.println(string);
}
}
public String[] getTheStrings() {
System.out.println("get the strings");
return theStrings;
}
public static void main(String [] args) {
new TestA();
}
}
Output:
get the strings
one
two
three
So essentially they are the same thing. The only thing that may be beneficial about the 2nd would be if you want to use the array outside the for loop.
Edit
You got me curious about how the java compiler handled this so using the code above I decompiled the class file and heres what the result is
public class TestA
{
public TestA()
{
String as[];
int j = (as = getTheStrings()).length;
for(int i = 0; i < j; i++)
{
String string = as[i];
System.out.println(string);
}
}
public String[] getTheStrings()
{
System.out.println("get the strings");
return theStrings;
}
public static void main(String args[])
{
new TestA();
}
public String theStrings[] = {
"one", "two", "three"
};
}
As you can see the compiler simply restructured your for loop into a standard loop! It also further proves that in fact they are exactly the same after the compiler gets through with it.

Assumng that by in you mean :, there is no difference in performance; they both do the same thing. Even in the first example, auth.getProjects() is executed only once; it can't be executed multiple times, since if it was, the for iteration would have to start over each time, which is not how it works.
I'd recommend using the version you find to be clearer.

There are a few more operations in the second example. Instead of referencing the array directly using the method, you are declaring a new reference variable, storing it in that new variable, then referencing the new variable.
You can check out the bytecode with ASM Bytecode Outline.
BUT, this is micro-optimization. If you need a new reference variable, then create one. If you don't need one, save the work and don't create a new one.

There is no difference.
According to the JLS 14.14.2, an enhanced for loop (for an array type) is equivalent to a regular for loop with the following pattern:
T[] #a = Expression;
L1: L2: ... Lm:
for (int #i = 0; #i < #a.length; #i++) {
{VariableModifier} TargetType Identifier = #a[#i];
Statement
}
If we substitute for your first example:
for(String project : auth.getProjects()) {
// Do something with 'project'
}
we get:
String[] $a = auth.getProjects();
for (int $i = 0; $i < $a.length; $i++) {
String project = $a[$i];
// Do something with 'project'
}
For your second example:
String[] projects = auth.getProjects();
for(String project : projects) {
// Do something with 'project'
}
we get:
String[] projects = auth.getProjects();
String[] $a = projects;
for (int $i = 0; $i < $a.length; $i++) {
String project = $a[$i];
// Do something with 'project'
}
The two versions of the code are clearly equivalent, and assuming that javac or the JIT is capable of optimizing away the redundant local variable $a, the two versions should perform the same.
Note that the local variable $a is only created once at the start of the loop in both cases.

The second one is better performance-wise, it is not creating a variable multiple times. Therefore, yes, auth.getProjects is being called every time.

Both are same as found above.
But do one thing use 1st approcah and after the for loop, de-reference the projects variable as-
projects = null;
Else, it will stay alive for the complete method life and will consume unnecessary memory.

Related

Local variable declaration in loop

When I ran the following code it gives me compile time error .
public class Test {
public static void main(String[] args) {
for (int i = 0; i < 100; i++)
Test2 obj = new Test2();// Compile time error- Multiple markers at this line
System.out.println(Test2.numCreated());
}
}
class Test2 {
private static long number= 0;
public static long numCreated() {
return number;
}
}
But when i put local variable declaration statement Test2 obj= new Test2() directly within a block every thing works fine.
Can someone explain me reason behind this or why Java developers did this ?
The compiler is very smart, if you ommit the { } then the obj object has no reason to be declared since is out of scope immediatly
remember ommiting the { } means ONLY the next line will belong to the for scope...
you mean for sure instead:
for (int i = 0; i < 100; i++){
Test2 obj = new Test2();
}
But what is scope? here more info
scope is the enclosed area where an object is visible, in this case the object obj is declared inside a for loop, that means you can only work with it inside the loop and it will be ready to be GC as soon as the loop is done...
As Stated by above answer you got the point of missing the braces {} of for loop
Note :If you remove braces, it will only read the first line of instruction. Any additional lines will not be read. If you have more than 1 line of instruction to be executed pls use curly brace - or else exception will be thrown.
If you won't put the braces { }, loop will only execute one statement after it. Since you are declaring obj in that particular line, it won't be of any use afterwards. So the compiler warns you in advance.
You must use { } if you want to execute multiple statements and make use of variables.
for (int i = 0; i < 100; i++){
Test2 obj = new Test2();
System.out.println(Test2.numCreated());
}
Now it will work properly because both statements belong to the loop and are inside the scope of the loop. After the loop is finished executing, the obj will be Garbage collected.
Note that this is not restricted to for loops. The problem is actually that the statement in your example is a "Local Variable Declaration Statement" (jls-14.4), and specifically the following line in the specification:
Every local variable declaration statement is immediately contained by a block.
Your example can be reduced to
if(true)
Test2 obj;
which also does not compile.
As soon as you add a block, it compiles fine:
if(true) {
Test2 obj;
}

Multiple if statements having incorrect output [duplicate]

This question already has answers here:
Multiple if statements with single else statement
(2 answers)
Closed 6 years ago.
I want to fill the acts array with values of some enum. While iterating I want to input commands from console, but my if statements don't find any match and I always get the output "Incorrect".
My code:
Action[] acts = new Action[n];
for(int i = 0; i < n; i++) {
System.out.println("Enter act: ");
Scanner in1 = new Scanner(System.in);
String s = in1.next();
acts[i] = new Action();
if (s.equals("rotate_forw"))
acts[i].type = ActionType.RotF;
if (s.equals("rotate_back"))
acts[i].type = ActionType.RotB;
if (s.equals("shift_forw"))
acts[i].type = ActionType.ShiftF;
if (s.equals("shift_back"))
acts[i].type = ActionType.ShiftB;
else
System.out.println("Incorrect");
}
Your else clause applies only to the last if statement, so you get the "Incorrect" output whenever s.equals("shift_back") is false.
Your statements should be replaced with a single if-else-if...-else statement, so that "Incorrect" is only printed if all the conditions are false :
Action[] acts = new Action[n];
for(int i = 0; i < n; i++) {
if (s.equals("rotate_forw"))
acts[i].type = ActionType.RotF;
else if (s.equals("rotate_back"))
acts[i].type = ActionType.RotB;
else if (s.equals("shift_forw"))
acts[i].type = ActionType.ShiftF;
else if (s.equals("shift_back"))
acts[i].type = ActionType.ShiftB;
else
System.out.println("Incorrect");
}
You should also consider what you want to assign to acts[i].type when the input is incorrect. Perhaps you should throw an exception in this case.
While #Eran's answer is correct, I'd like to suggest a different approach that encapsulates the enum with the translation from the external coding. Consider this:
public class EnumDemo
{
public static enum ActionType
{
Incorrect(""),
RotF("rotate_forw"),
RotB("rotate_back"),
ShiftF("shift_forw"),
ShiftB("shift_back");
private String code;
private ActionType(String code)
{
this.code = code;
}
public static ActionType fromString(String code)
{
return Arrays.stream(ActionType.values())
.filter(v->v.code.equals(code))
.findFirst()
.orElse(ActionType.Incorrect);
}
}
public static void main(String[] args)
{
String[] testData = {
"rotate_forw",
"rotate_back",
"shift_forw",
"shift_back",
"junk",
null };
Arrays.stream(testData)
.forEach(t->System.out.printf("\"%s\" -> ActionType.%s\n", t, ActionType.fromString(t)));
}
}
This uses the fact that enum constants can have associated data. I've added an instance variable code to hold the external encoding of each enum value. Then I added a static fromString(String code) method to the enum that looks up the provided code in the list of values. For 4 possibilities a simple linear search, equivalent to your if-then-else cascade, works fine. If there were dozens or more I'd set up a Map<String,ActionType> to handle the conversion.
The search using streams bears some explanation.
First create a Stream of enum values
Filter it to contain only enum values whose code matches the desired code (there should be only one)
Pick off the first entry, which comes back in a Optional. If nothing was found (i.e. the code is invalid) the Optional will be empty.
Use the orElse method to return the value if it exists or ActionType.Incorrect if not.
At first glance this might look inefficient since one expects that the filter() predicate has to scan the entire stream even if the desired element occurs early. This is a really nifty feature of Streams -- all intermediate streams are "lazy", so the filter won't iterate over the entire list if it finds the desired entry early. See this question for details.
Output:
"rotate_forw" -> ActionType.RotF
"rotate_back" -> ActionType.RotB
"shift_forw" -> ActionType.ShiftF
"shift_back" -> ActionType.ShiftB
"junk" -> ActionType.Incorrect
"null" -> ActionType.Incorrect
The last testcase shows the code is null-safe.
The biggest advantage is that the mapping is in the same place as the enum itself, so you won't have to hunt for the code when you add or remove an enum value. Also you can't forget to define the mapping since it's required by the enum's constructor.

Dynamic calling of JBehave steps from inside Java

In Java I have a String object that has the text that I wish to be matched and executed by JBehave as a step. How can this be done? Can it be done?
What I am really trying to do is to have a wrapper JBehave step that instruments another arbitrary JBehave step. It does a few things before and after calling on the "inner" step.
So lets say that I already have the following
When I say Hello World
and
#When("I say $text")
public void iSay(final String text)
{
System.out.println(text);
}
I want to be able to do the following :
When I repeat 4 times I say Hello World
it will call :
#When("I repeat $count times $subStepString")
public void repeat(final int repeatCount, final String subStepString)
{
// prep code here
for (int i = 0; i < repeatCount; i++)
{
howDoIdoThisBitHere(subStepString);
}
// post process code here
}
The part that says howDoIdoThisBitHere(...) should end up having JBehave match the value of subStepString as if it was encountered in the case above. This way I can use this method to call other arbitrary things.
I'm not sure this is a great idea since the step classes shouldn't have any dependency on the core configuration (StepMatchers, Runners etc.), but is this solution kind of what you're looking for?
#When("I repeat $count times $subStepString")
public void repeat(final int repeatCount, final String subStepString)
{
// prep code here
for (int i = 0; i < repeatCount; i++)
{
StoryParser sp = configuration().storyParser();
Story s = sp.parseStory(subStepString);
StoryRunner e = configuredEmbedder().storyRunner();
e.run(configuration(), configuredEmbedder().candidateSteps(), s);
}
}

Why does a String need to be initialized even if the assignment will happen later?

I get the "The local variable string may not have been initialized" error with the following code. The code itself doesn't make sense it was written just for the sake of exercise.
public class StringExercise
{
public static void main(String[] args)
{
String string; // initializing here fixes the issue
for (int i = 0; i < 10; ++i)
{
if( (i % 4) == 2 )
{
string = "Number: " + i;
}
}
System.out.println(string); // this is marked as wrong by Eclipse
}
}
To get it working it is sufficient to initialize String as expressed in the comment above.
My question is why is it needed? The method println will never be given null and initialization will happen the first time the condition in the loop returns true. Am I doing something wrong or is it just Java being overcautious over programmer's errors? If the latter, how is it justified from the theoretical point of view?
My question is why is it needed?
Because even though your code is "logically" written so that string will indeed be initialized in the loop, the compiler doesn't know it. All it sees is:
for (loop; elements; here)
if (someCondition)
string = something;
In short: a compiler will not check the logic of your code; it it only smart enough as to check for syntax errors, but after that, the bytecode generation itself is "dumb".
And as Java requires that all variables be initialized before use, you get this compiler error.
The compiler can't guarantee that string = "Number: " + i; will be executed within your for and if.

Game optimisation in java concerning ArrayList<Object> elements casting to another variable inside for loop

Is this usage of elements of an ArrayList:
for(int i=0; i<array_list.size(); i++){
Object obj = array_list.get(i);
//do **lots** of stuff with **obj**
}
faster than this one:
for(int i=0; i<array_list.size(); i++){
//do **lots** of stuff with **array_list.get(i)**;
}
It depends on how many times array_list.get(i) is called in the second code. If it is called only once, there is no difference between both methods.
If it's invoked multiple times, saving the value in a variable may be more efficient (it depends on the compiler and the JIT optimizations).
Sample scenario where the first method may be more efficient, compiled using Oracle JDK's javac compiler, assuming the list contains String objects:
for(int i=0; i<array_list.size(); i++){
String obj = array_list.get(i);
System.out.println(obj);
if(!obj.isEmpty()) {
String o = obj.substring(1);
System.out.println(o + obj);
}
}
In this case, obj is saved as a local variable and loaded whenever it is used.
for(int i=0; i<array_list.size(); i++){
System.out.println(array_list.get(i));
if(!array_list.get(i).isEmpty()) {
String o = array_list.get(i).substring(1);
System.out.println(o + array_list.get(i));
}
}
In this case, multiple invokation for List.get are observed in the bytecode.
The performance difference between getting once and a local variable is almost always neglible. But... if you insist on doing it the hardcore way, this is the fast way to go:
ArrayList<Object> array_list = ...
// cache list.size() in variable!
for (int i=0, e=array_list.size(); i < e; ++i) {
// get object only once into local variable
Object object = array_list.get(i);
// do things with object
}
It caches the lists size into a local variable e, to avoid invoking array_list.size() at each loop iteration, as well as each element in the loop to avoid get(index) calls. Be aware that whatever you actually do with the objects in the loop will most likely be by orders of magnitude more expensive than the loop itself.
Therefore, prefer code readability and simply use the advanced for loop syntax:
ArrayList<Object> array_list = ...
for (Object object : array_list) {
// do things with object
}
No hassles, short and clear. Thats worth far more than a few saved clock cycles in most cases.

Categories

Resources