I have a question that i have been pondering for a while. Take for instance this particular piece of class
class A{
private static ArrayList<String> listOne;
public Static ArrayList<String> getList()
{
return this.listOne
}
}
Let say i have class B that possess a method to read the details with listOne. To Look through the arraylist, i would need to first get the size of the list in order for my code to know when the arraylist ends. There are 2 ways in which i can do so, one being
int listSize = A.getList().size()
for(int count =0; count < listSize; count++)
{
// code to read through arraylist
}
or i can achieve the same thing with
for(int count=0; count < A.getList().size(); count++)
{
// code to read through arraylist
}
In terms of memory and efficiency, which method is better? Furthermore let says i am reading through a very large array recursively. For simplicity purposes, lets assume that recursively reading through this array would a stack overflow exception. In this situation, would the first method theoretically cause a stack overflow to happen earlier then the second method seeing that each recursive call's stack frame has to keep the state of the variable "listSize"?
Have a look at the result of javap -verbose:
0: invokestatic #2 // Method A.getList:()Ljava/util/ArrayList;
3: invokevirtual #3 // Method java/util/ArrayList.size:()I
6: istore_1
7: iconst_0
8: istore_2
9: iload_2
10: iload_1
11: if_icmpge 27
14: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
17: iload_2
18: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
21: iinc 2, 1
24: goto 9
27: iconst_0
28: istore_2
29: iload_2
30: invokestatic #2 // Method A.getList:()Ljava/util/ArrayList;
33: invokevirtual #3 // Method java/util/ArrayList.size:()I
36: if_icmpge 52
39: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
42: iload_2
43: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
46: iinc 2, 1
49: goto 29
52: return
First case is:
9: iload_2
10: iload_1
11: if_icmpge 27
14: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
17: iload_2
18: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
21: iinc 2, 1
24: goto 9
And the second one:
29: iload_2
30: invokestatic #2 // Method A.getList:()Ljava/util/ArrayList;
33: invokevirtual #3 // Method java/util/ArrayList.size:()I
36: if_icmpge 52
39: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
42: iload_2
43: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
46: iinc 2, 1
49: goto 29
As you can see, it will get the list and its size during each loop iteration.
But, this might be optimized by JIT, so the result is not obvious from just the compiled bytecode.
Created from:
import java.io.*;
import java.util.*;
public class Z {
public static void main(String[] args) throws Exception {
int listSize = A.getList().size();
for(int count =0; count < listSize; count++) {
System.out.println(count);
}
for(int count =0; count < A.getList().size(); count++) {
System.out.println(count);
}
}
}
class A{
private static ArrayList<String> listOne = new ArrayList<>(Arrays.asList("1", "2", "3"));
public static ArrayList<String> getList()
{
return listOne;
}
}
Both the loop are same. Second one is better coding as it reduces line of code.
Since you mentioned that your need is to traverse the list it is much better to use the enhanced (for-each) for loop.
What are the Advantages of Enhanced for loop and Iterator in Java?
why is enhanced for loop efficient than normal for loop
Regarding which of the method is more efficient, I think they won't have any noticeable differences. And depending on the JVM, like Germann has said, the compiler will even optimize this. So just don't worry about this negligible difference.
I personally will use the second method since it has fewer lines of code and I'm lazy...
However, why not use neither?
There's a super cool alternative, and its name is... JON CENA The enhanced for loop.
Let's compare it with a normal for loop:
Normal:
for (int i = 0 ; i < A.getList().size() ; i++ {
}
Enhanced:
for (String item : A.getList()) {
// Instead of using A.getList().get(i) to access the items, just use "item"!
}
Look how nice it is!
The major difference between these two for loops is that
The normal for loop is just a kind of a while loop with initialization and incrementation.
The enhanced for loop calls .iterator().hasNext() and .iterator().next() to loop.
You need to know the size of the list to use a normal for loop
Your list just needs to implement Iterable and probably Iterator to use an enhanced for loop. No size is needed.
An enhanced for loop has the following limitations:
You can't loop through two arrays at the same time
It's better to use a normal for loop if you want to know the index of the list, since calling indexOf a lot of times is not very efficient.
Related
This question already has answers here:
Declaring variables inside or outside of a loop
(20 answers)
Closed 5 years ago.
First 2 examples:
1)
MyClass myClass;
for (int i=0; i<arrayList.size(); i++) {
myClass = arrayList.get(i);
...
}
2)
for (int i=0; i<arrayList.size(); i++) {
MyClass myClass = arrayList.get(i);
...
}
In the first example the reference variable myClass is created only once. But what about in the second example, is it created only once, or once for each iteration? My thought is perhaps the compiler optimizes this, I don't know.
I tried to answer this question by coding an example, but couldn't figure it out. How can it be proven via code?
Note: I realize example 2 is better style since myClass isn't known outside of the for loop, and it's scope is kept to a minimum. I also have searched here but haven't found a definitive answer to this exact question (usually it's a question of "which is preferred?".) I also assume that if the myClass reference is created each iteration it isn't a big performance issue.
Edit: Again, I am not asking which is better coding style. Also, I wonder if it can be deduced/proven via code. I tried to generate and compare the bytecode, but I am not familiar with bytecode and what was generated was not an exact match.
When you declare a variable, you don't "create" anything. Variables are just a convenient name to help you remember where you put some result, and allow you to control where that result can be used, and associate some type information with that result; but once you compile the code, they no longer exist.
Compare the bytecode (*):
void outside(int i, List<?> list) {
Object obj;
for (i = 0; i < list.size(); i++) {
obj = list.get(i);
}
}
void inside(int i, List<?> list) {
for (i = 0; i < list.size(); i++) {
Object obj = list.get(i);
}
}
Decompiles to:
void outside(int, java.util.List<?>);
Code:
0: iconst_0
1: istore_1
2: iload_1
3: aload_2
4: invokeinterface #2, 1 // InterfaceMethod java/util/List.size:()I
9: if_icmpge 26
12: aload_2
13: iload_1
14: invokeinterface #3, 2 // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
19: astore_3
20: iinc 1, 1
23: goto 2
26: return
void inside(int, java.util.List<?>);
Code:
0: iconst_0
1: istore_1
2: iload_1
3: aload_2
4: invokeinterface #2, 1 // InterfaceMethod java/util/List.size:()I
9: if_icmpge 26
12: aload_2
13: iload_1
14: invokeinterface #3, 2 // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
19: astore_3
20: iinc 1, 1
23: goto 2
26: return
The two are identical. Use the one which is most readable.
(*) I've declared the loop variable i as a parameter, in order to avoid any differences in the generated bytecode caused by the Object being declared before or after i. The only difference this makes to the bytecode is in the aload_N/iload_N/astore_N/istore_N instructions - the N is different because the variables are stored in different "slots". This is not a significant difference.
ArrayList<String> strings = new ArrayList<String>(){{
add("a");
add("b");
add("c");
add("d");
}};
int size = strings.size();
This is the part that I want to know which one to use and why.
for(int i = 0; i < size; i++){
String temp_string = strings.get(i);
someMethod(temp_string);
}
or
for(int i = 0; i < size; i++){
someMethod(strings.get(i));
}
Does it make any performance difference? Does the temp_string points to the String saved in the arraylist part of memory or does it allocate another space in memory in each loop to save the temp_string?
I would be surprised if it made any difference, not only because creating a temporary reference on the stack and then copying it to the function call parameter costs very little, but mostly because no serious compiler would miss the obvious optimization.
Still, you cannot be sure without testing.
It may help to walk through what is going on in both cases to see what kind of difference you should expect:
In the case with a temporary variable, you obtain an object reference, store it in a temporary variable, pass it on to someMethod, and then let the temporary variable go out of scope
In the case without a temporary variable, you obtain ab object reference, and pass it on to someMethod directly.
From this you should conclude right away that if there is any difference, the advantage would be on the side of the implementation that does fewer things, i.e. the implementation without a temporary variable.
There are situations when making a temporary variable would help you improve performance. Here is one example, based on your code snippet:
for(int i = 0; i < size; i++){
String temp_string = strings.get(i);
for (int j = 0 ; j != 10000 ; j++) {
someMethod(temp_string, 2*j+1);
}
}
This snippet reuses the results of strings.get(i) ten thousand times, so when someMethod is really fast, you might see a little difference. This is not a guaranteed win, however: you need to profile to see if the change makes a difference or not.
Another change that may make a difference with fast someMethod implementations and long strings lists is a foreach loop:
for(String s : strings){
someMethod(s);
}
This is applicable when you do not need to use the index inside the loop. The code may be a little faster, because internally it avoids an index check in the array list.
First off, I believe in the second algorithm you meant strings.get(i) not temp_string.get(i) because temp_string isn't declared.
Now to the point, the first algorithm takes a couple of clock cycles longer. Notice you have all the same calls PLUS an assignment operation. This will be negligible in most situations but in a high performance environment it could be costly.
The scope of temp_string is identical in both cases, that is, limited to the for loop. The generated byte code is almost identical.
public void foo1(List<String> list) {
for (int i=0; i<list.size(); i++) {
String str = list.get(i);
someMethod(str);
}
}
public void foo2(List<String> list) {
for (int i=0; i<list.size(); i++) {
someMethod(list.get(i));
}
}
public void foo1(java.util.List);
Code:
0: iconst_0
1: istore_2
2: iload_2
3: aload_1
4: invokeinterface #2, 1; //InterfaceMethod java/util/List.size:()I
9: if_icmpge 34
12: aload_1
13: iload_2
14: invokeinterface #3, 2; //InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
19: checkcast #4; //class java/lang/String
22: astore_3
23: aload_0
24: aload_3
25: invokevirtual #5; //Method someMethod:(Ljava/lang/String;)V
28: iinc 2, 1
31: goto 2
34: return
public void foo2(java.util.List);
Code:
0: iconst_0
1: istore_2
2: iload_2
3: aload_1
4: invokeinterface #2, 1; //InterfaceMethod java/util/List.size:()I
9: if_icmpge 32
12: aload_0
13: aload_1
14: iload_2
15: invokeinterface #3, 2; //InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
20: checkcast #4; //class java/lang/String
23: invokevirtual #5; //Method someMethod:(Ljava/lang/String;)V
26: iinc 2, 1
29: goto 2
32: return
The only difference with the first loop (assigning to a String, then passing the String to the method) is an extra astore_3 and aload_3. This should be easy for the JVM to optimize out.
Also note that the second loop (no extra variable assignment) is easier to read.
I'm going to make some investigations about dividing large arrays/matrix computations among multiple threads. But I need to know the relative time complexity of Java basic operations.
For instance:
int a = 23498234;
int b = -34234;
int[] array = new int[10000];
int c = a + b; // 1
int c = array[234]; // 2
String 1 (summary of two integers) is 10+ times faster than string 2 (memory access)
or (i & 1) == 0 is 10+ faster than i % 2 == 0.
Question: Can you supppose time relations between next operations:
+, * and / operands (suppose on Integer type)
memory access
starting new thread
For performance timing, there are many confounding factors. Rather than try to get exact timings, it's better to understand what's going on and measure what you can.
The time utility will give you detailed stats on an executable, but keep in mind you're timing the JVM which is running the code, not just your code.
You might try the javap disassembler too -- ultimately you'll want to know how your individual operations break down into java bytecode, and the amount of time it takes to execute certain key bits.
Example source code:
public class T {
public static void main(String [] args) {
int x=2;
int y=3;
int z=x+y;
System.out.println(""+x);
}
}
Compiled, then disassembled:
$ javap -c T
Compiled from "T.java"
public class T {
public T();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_2
1: istore_1
2: iconst_3
3: istore_2
4: iload_1
5: iload_2
6: iadd
7: istore_3
8: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
11: new #3 // class java/lang/StringBuilder
14: dup
15: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
18: ldc #5 // String
20: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
23: iload_1
24: invokevirtual #7 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
27: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
30: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
33: return
}
Look at code #6 - that's where the actual addition is happening.
One thing you need to establish is how the operations you're interested in turn into bytecode.
Within the JVM itself, you can use System.getCurrentTimeMillis() as a way of timing, but it won't give you sub-ms resolution. You can also use System.nanoTime(); to get higher precision time, (in the sense that it's sub-ms resolution) but it's less accurate.
I'm having a problem initializing array of HashSet
int N = 100;
HashSet<Integer> []array = new HashSet[N];
for (HashSet<Integer> set:array){
set = new HashSet<Integer>();
}
But the array contains only null. (Also error when HashSet []array = .... )
But when running with:
for(int i = 0; i < N; i++){
array[i] = new HashSet<Integer>();
}
All is well.
Why does the first code isn't working? Is it my mistake?
Thank you
You never actually assign initialized instances to elements of the array. Instead you iterate over the elements of the array with a variable that gets assigned to a new object in your loop, then is never used. In a case like this the enhanced for...each syntax is not appropriate, use the traditional for loop instead.
two 'for' is different in Java, look the java code & bytecode ..
Example:
public class T{
public static void main(String[] args){
String[] data = new String[10];
System.out.print("");
for(String str:data){
str="1";
}
System.out.print("");
for(int i=0;i<data.length;i++){
data[i]="1";
}
}
}
$>javac -classpath . T.java
$>javap -c T
Compiled from "T.java"
public class T extends java.lang.Object{
public T();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: bipush 10
2: anewarray #2; //class java/lang/String
5: astore_1
6: getstatic #3; //Field java/lang/System.out:Ljava/io/PrintStream;
9: ldc #4; //String
11: invokevirtual #5; //Method java/io/PrintStream.print:(Ljava/lang/String;)V
14: aload_1
15: astore_2
16: aload_2
17: arraylength
18: istore_3
19: iconst_0
20: istore 4
22: iload 4
24: iload_3
25: if_icmpge 44
28: aload_2
29: iload 4
31: aaload
32: astore 5
34: ldc #6; //String 1
36: astore 5
38: iinc 4, 1
41: goto 22
44: getstatic #3; //Field java/lang/System.out:Ljava/io/PrintStream;
47: ldc #4; //String
49: invokevirtual #5; //Method java/io/PrintStream.print:(Ljava/lang/String;)V
52: iconst_0
53: istore_2
54: iload_2
55: aload_1
56: arraylength
57: if_icmpge 71
60: aload_1
61: iload_2
62: ldc #6; //String 1
64: aastore
65: iinc 2, 1
68: goto 54
71: return
}
from line 25--44 and line 57--71:
aload : Retrieves an object reference from a local variable and pushes it onto the operand stack.
aaload : Retrieves an object reference from an array of objects and places it on the stack.
astore : Take object or reference store to local variable.
aastore : Take reference type value store to array.
so,first can't store array , didn't using initializing array.
An enhanced for loop, does not use the actual instances in the array( and as well, collection), but rather copies them in the loop control variable.
This should not be a problem with non-null values, since they point to the same object. Problems arise, if the values are null, and re-assigning values to the control variable, would not change the actual value. So in this case, always use regular for loops.
The same would be true, to arrays of primitive types, since coping them, and changing the copied variable, will not affect the original variable.
Simply use new Set[n] instead of new HashSet[n] , to get it working
Set<Integer>[] list = new Set[n];
for(int i=0;i<n;i++)
list[i] = new HashSet<>();
You need to create an array that contains HashSet
so, you need to initialize the array and then initialize the HashSet
which I have provided in the below code
int N = 100;
Set<Integer>[] array = new Set[n];
for(int i = 0; i < n; i++) {
array[i] = new HashSet<Integer>();
}
String[] strs = new String[] { "1", "2", ... , "6" };
for (String s : strs) {
System.out.println(s);
}
This is a question about java internals.
In the above code sample, how does the foreach loop figure out how long the array is? Are arrays actually objects internally or is it using stuff like sizeof that is inaccessible to front end programmers?
I have a feeling I'm just missing something stupid, but I figure it could also be cool. :-)
I compiled the following code:
public class ArrayIterator
{
public static void main(String[] argv)
{
String[] strs = new String[] { "1", "2", "3", "4", "5" };
enhancedPrint(strs);
normalPrint(strs);
}
public static void enhancedPrint( String[] strs )
{
for (String s : strs)
{
System.out.println(s);
}
}
public static void normalPrint( String[] strs )
{
String[] localArray = strs;
int len = localArray.length;
for (int i = 0; i < len; i++)
{
String s = localArray[i];
System.out.println(s);
}
}
}
This is the disassembled (javap -c ArrayIterator) bytecode for the iterating functions:
The enhanced print:
public static void enhancedPrint(java.lang.String[]);
Code:
0: aload_0
1: astore_1
2: aload_1
3: arraylength
4: istore_2
5: iconst_0
6: istore_3
7: iload_3
8: iload_2
9: if_icmpge 31
12: aload_1
13: iload_3
14: aaload
15: astore 4
17: getstatic #10; //Field java/lang/System.out:Ljava/io/PrintStream;
20: aload 4
22: invokevirtual #11; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
25: iinc 3, 1
28: goto 7
31: return
A normal for loop:
public static void normalPrint(java.lang.String[]);
Code:
0: aload_0
1: astore_1
2: aload_1
3: arraylength
4: istore_2
5: iconst_0
6: istore_3
7: iload_3
8: iload_2
9: if_icmpge 31
12: aload_1
13: iload_3
14: aaload
15: astore 4
17: getstatic #10; //Field java/lang/System.out:Ljava/io/PrintStream;
20: aload 4
22: invokevirtual #11; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
25: iinc 3, 1
28: goto 7
31: return
As you can see, in both cases, the compiler is loading the arrays length (strs.length) and looping against it. We see that the enhanced for-each loop, in the case of an Array is syntactic sugar for looping against the array's length (rather than in an Object's case where it uses an Iterator).
I have edited the 'normal' for loop such that it is much less idiomatic, but that it has the same bytecode as the enhanced for loop. For all intents and purposes, the normal for loop version is what the compiler generates when it compiles the enhanced for each loop.
Yes, there is something akin to the C++ sizeof operator -- it's the length instance variable (which gives the number of elements in the array, not the size in bytes.) The length field is always a public member of the array, so it is accessible to Java programmers.
And yes, arrays are objects, and not just internally.
(More broadly, the for loop syntax works as described in the question that org.life.java linked to; but that isn't quite what you were asking.)
Yes, arrays are objects with a "length" field. Java Language Specification: http://java.sun.com/docs/books/jls/third_edition/html/arrays.html#64347