java looping - declaration of a Class outside / inside the loop [duplicate] - java

This question already has answers here:
Closed 12 years ago.
Possible Duplicates:
Which loop has better performance? Why?
Which is optimal ?
Efficiency of Java code with primitive types
when looping, for instance:
for ( int j = 0; j < 1000; j++) {}; and I need to instantiate 1000 objects, how does it differ when I declare the object inside the loop from declaring it outside the loop ??
for ( int j = 0; j < 1000; j++) {Object obj; obj =}
vs
Object obj;
for ( int j = 0; j < 1000; j++) {obj =}
It's obvious that the object is accessible either only from the loop scope or from the scope that is surrounding it. But I don't understand the performance question, garbage collection etc.
What is the best practice ? Thank you

The first form is better. Limiting the scope of a variable makes it easier for readers to understand where and how it is used.
Performance-wise, there are some small advantages to limited scope as well, which you can read about in another answer. But these concerns are secondary to code comprehension.

There's no difference. The compiler will optimize them to the very same place.

I've tested the issue on my machine the difference was about 2-4ms over 10000 instances, I tested all kind of stuff, like if you instantiate and assign value:
int i=0;
in compare with:
int i;
i=0;
here is the code I used for testing, of course I changed it for testing, and there is an initial balancing effect before the machine reaches optimization, you can see that in the clear once you test:
package initializer;
public final class EfficiencyTests {
private static class Stoper {
private long initTime;
private long executionDuration;
public Stoper() {
// TODO Auto-generated constructor stub
}
private void start() {
initTime = System.nanoTime();
}
private void stop() {
executionDuration = System.nanoTime() - initTime;
}
#Override
public String toString() {
return executionDuration + " nanos";
}
}
private static Stoper stoper = new Stoper();
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
theCycleOfAForLoop(100000);
theCycleOfAForLoopWithACallToSize(100000);
howLongDoesItTakeToSetValueToAVariable(100000);
howLongDoesItTakeToDefineAVariable(100000);
System.out.println("\n");
}
}
private static void theCycleOfAForLoop(int loops) {
stoper.start();
for (int i = 0; i < loops; i++);
stoper.stop();
System.out.println("The average duration of 10 cycles of an empty 'for' loop over " + loops + " iterations is: " + stoper.executionDuration * 10 / loops);
}
private static void theCycleOfAForLoopWithACallToSize(int loops) {
ArrayList<Object> objects=new ArrayList<Object>();
for (int i = 0; i < loops; i++)
objects.add(new Object());
stoper.start();
for (int i = 0; i < objects.size(); i++);
stoper.stop();
System.out.println("The average duration of 10 cycles of an empty 'for' loop with call to size over " + loops + " iterations is: " + stoper.executionDuration * 10 / loops);
}
private static void howLongDoesItTakeToSetValueToAVariable(int loops) {
int value = 0;
stoper.start();
for (int i = 0; i < loops; i++) {
value = 2;
}
stoper.stop();
System.out.println("The average duration of 10 cycles of setting a variable to a constant over " + loops + " iterations is: " + stoper.executionDuration * 10 / loops);
}
private static void howLongDoesItTakeToDefineAVariable(int loops) {
stoper.start();
for (int i = 0; i < loops; i++) {
int value = 0;
}
stoper.stop();
System.out.println("The average duration of 10 cycles of initializing and setting a variable to a constant over " + loops + " iterations is: " + stoper.executionDuration * 10 / loops);
}
private static void runAForLoopOnAnArrayOfObjects() {
// TODO Auto-generated method stub
}}
you can derive how long one takes if you reduce the time of the other... (if you understand what I mean)
hope this save you some time.
thing you need to understand is that I tested this things to optimize my paint update loop of my platform and it helped.
Adam.

Related

ThreadLocalRandom with shared static Random instance performance comparing test

In our project for one task we used static Random instance for random numbers generation goal. After Java 7 release new ThreadLocalRandom class appeared for generating random numbers.
From spec:
When applicable, use of ThreadLocalRandom rather than shared Random objects in concurrent programs will typically encounter much less overhead and contention. Use of ThreadLocalRandom is particularly appropriate when multiple tasks (for example, each a ForkJoinTask) use random numbers in parallel in thread pools.
and also:
When all usages are of this form, it is never possible to accidently share a ThreadLocalRandom across multiple threads.
So I've made my little test:
public class ThreadLocalRandomTest {
private static final int THREAD_COUNT = 100;
private static final int GENERATED_NUMBER_COUNT = 1000;
private static final int INT_RIGHT_BORDER = 5000;
private static final int EXPERIMENTS_COUNT = 5000;
public static void main(String[] args) throws InterruptedException {
System.out.println("Number of threads: " + THREAD_COUNT);
System.out.println("Length of generated numbers chain for each thread: " + GENERATED_NUMBER_COUNT);
System.out.println("Right border integer: " + INT_RIGHT_BORDER);
System.out.println("Count of experiments: " + EXPERIMENTS_COUNT);
int repeats = 0;
int workingTime = 0;
long startTime = 0;
long endTime = 0;
for (int i = 0; i < EXPERIMENTS_COUNT; i++) {
startTime = System.currentTimeMillis();
repeats += calculateRepeatsForSharedRandom();
endTime = System.currentTimeMillis();
workingTime += endTime - startTime;
}
System.out.println("Average repeats for shared Random instance: " + repeats / EXPERIMENTS_COUNT
+ ". Average working time: " + workingTime / EXPERIMENTS_COUNT + " ms.");
repeats = 0;
workingTime = 0;
for (int i = 0; i < EXPERIMENTS_COUNT; i++) {
startTime = System.currentTimeMillis();
repeats += calculateRepeatsForTheadLocalRandom();
endTime = System.currentTimeMillis();
workingTime += endTime - startTime;
}
System.out.println("Average repeats for ThreadLocalRandom: " + repeats / EXPERIMENTS_COUNT
+ ". Average working time: " + workingTime / EXPERIMENTS_COUNT + " ms.");
}
private static int calculateRepeatsForSharedRandom() throws InterruptedException {
final Random rand = new Random();
final Map<Integer, Integer> counts = new HashMap<>();
for (int i = 0; i < THREAD_COUNT; i++) {
Thread thread = new Thread() {
#Override
public void run() {
for (int j = 0; j < GENERATED_NUMBER_COUNT; j++) {
int random = rand.nextInt(INT_RIGHT_BORDER);
if (!counts.containsKey(random)) {
counts.put(random, 0);
}
counts.put(random, counts.get(random) + 1);
}
}
};
thread.start();
thread.join();
}
int repeats = 0;
for (Integer value : counts.values()) {
if (value > 1) {
repeats += value;
}
}
return repeats;
}
private static int calculateRepeatsForTheadLocalRandom() throws InterruptedException {
final Map<Integer, Integer> counts = new HashMap<>();
for (int i = 0; i < THREAD_COUNT; i++) {
Thread thread = new Thread() {
#Override
public void run() {
for (int j = 0; j < GENERATED_NUMBER_COUNT; j++) {
int random = ThreadLocalRandom.current().nextInt(INT_RIGHT_BORDER);
if (!counts.containsKey(random)) {
counts.put(random, 0);
}
counts.put(random, counts.get(random) + 1);
}
}
};
thread.start();
thread.join();
}
int repeats = 0;
for (Integer value : counts.values()) {
if (value > 1) {
repeats += value;
}
}
return repeats;
}
}
I've also added test for non-shared Random and got next results:
Number of threads: 100
Length of generated numbers chain for each thread: 100
Right border integer: 5000
Count of experiments: 10000
Average repeats for non-shared Random instance: 8646. Average working time: 13 ms.
Average repeats for shared Random instance: 8646. Average working time: 13 ms.
Average repeats for ThreadLocalRandom: 8646. Average working time: 13 ms.
To me it's little strange, as I expected at least speed increasing when using ThreadLocalRandom comparing to shared Random instance, but see no difference at all.
Can someone explain why it works that way, maybe I haven't done testing properly. Thank you!
You're not running anything in parallel because you're waiting for each thread to finish immediately after starting it. You need a waiting loop outside the loop that starts the threads:
List<Thread> threads = new ArrayList<Thread>();
for (int i = 0; i < THREAD_COUNT; i++) {
Thread thread = new Thread() {
#Override
public void run() {
for (int j = 0; j < GENERATED_NUMBER_COUNT; j++) {
int random = rand.nextInt(INT_RIGHT_BORDER);
if (!counts.containsKey(random)) {
counts.put(random, 0);
}
counts.put(random, counts.get(random) + 1);
}
}
};
threads.add(thread);
thread.start();
}
for (Thread thread: threads) {
thread.join();
}
Your testing code is flawed for one. The bane of benchmarkers everywhere.
thread.start();
thread.join();
why not save LOCs and write
thread.run();
the outcome is the same.
EDIT: If you don't realize the outcome from the above, it means that you're running single threaded tests, there's no multithreading going on.
Maybe it would be easier to just have a look at what actually happens. Here is the source for ThreadLocal.get() which is also called for the ThreadLocalRandom.current().
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
return setInitialValue();
}
Where ThreadLocalMap is a specialized HashMap-like implementation with optimizations.
So what basically happens is that ThreadLocal holds a map Thread->Object - or in this case Thread->Random - which is then looked up and either returned or created. As this is nothing 'magical', the timing will be equal to a HashMap-lookup + the initial creation overhead of the actual Object to be returned. Since a HashMap lookup (in this optimized case) is linear, the cost for a lookup is k, where k is the calculation cost of the hash function.
So you can make some assumptions:
ThreadLocal will be faster than creating the object each time in each Runnable, unless the creation cost is much smaller than k. So looking up Random is a good thing, putting an int inside might not be so smart.
ThreadLocal will be better than using your own HashMap, as such a generic implementation can be assumed to be equal to k or worse.
ThreadLocal will be slower than using any lookup with a cost < k. Example: store everything in an array first, then do myRandoms[threadID].
But then this assumes that you know which threads will be processing your work in the first place, so this isn't a real candidate for ThreadLocal anyways.

why running time less when it number bigger

I wrote a progrmame to test whether the try catch block affect of the running time or not.
Code as follow shows
public class ExceptionTest {
public static void main(String[] args) {
System.out.println("Loop\t\tNormal(nano second)\t\tException(nano second)");
int[] arr = new int[] { 1, 500, 2500, 12500, 62500, 312500, 16562500 };
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i] + "," + NormalCase(arr[i]) + ","
+ ExceptionCase(arr[i]));
}
}
public static long NormalCase(int times) {
long firstTime=System.nanoTime();
for (int i = 0; i < times; i++) {
int a = i + 1;
int b = 2;
a = a / b;
}
return System.nanoTime()-firstTime;
}
public static long ExceptionCase(int times) {
long firstTime =System.nanoTime();
for (int i = 0; i < times; i++) {
try {
int a = i + 1;
int b = 0;
a = a / b;
} catch (Exception ex) {
}
}
return System.nanoTime()-firstTime;
}
}
the result shows bellow:
I wonder why less time when turns to 62500 and biger numbers?is It overflow ? seems not.
You are not testing the computational cost of the try/catch block. You are really testing the cost of exception handling. A fair test would be making b= 2 ; also in ExceptionCase. I don't know what extremely wrong conclusions you will draw if you think you are testing only try/catch. I'm frankly alarmed.
The reason why timing changes so much is that you are executing the functions so many times that the JVM decided to compile and optimize them. Enclose your loop into an outer one
for(int e= 0 ; e < 17 ; e++ ) {
for(int i= 0 ; i < arr.length ; i++) {
System.out.println(arr[i] + "," + NormalCase(arr[i]) + "," + ExceptionCase(arr[i]));
}
}
and you will see more stable results by the end of the run.
I also think that in the case NormalCase the optimizer is "realizing" that the for is not really doing anything and just skipping it (for an execution time of 0). For some reason (probably the side effect of exceptions), it's not doing the same with ExceptionCase. To solve this bias, compute something inside the loop and return it.
I don't want to change your code too much, so I'll use a trick to return a second value:
public static long NormalCase(int times,int[] result) {
long firstTime=System.nanoTime();
int computation= 0 ;
for(int i= 0; i < times; i++ ) {
int a= i + 1 ;
int b= 2 ;
a= a / b ;
computation+= a ;
}
result[0]= computation ;
return System.nanoTime()-firstTime;
}
You can call this with NormalCase(arr[i],result), preceded by declaration int[] result= new int[1] ;. Modify ExceptionCase in the same way, and output result[0] to avoid any other optimization. You will probably need one result variable for each function.

How to decide that a method must be synchronized

In this code taken from this test thread code a thread calls two methods addToTotal() and countPrimes() but only the former is marked synchronized.
What prevents interleaving when countPrimes() is being executed. Aren't the variables used by countPrimes() like i, min, max, count also shared resources. And what about isPrime() which is called by countPrimes() ?
public class ThreadTest2 {
private static final int START = 3000000;
private static int total;
synchronized private static void addToTotal(int x) {
total = total + x;
System.out.println(total + " primes found so far.");
}
private static class CountPrimesThread extends Thread {
int count = 0;
int min, max;
public CountPrimesThread(int min, int max) {
this.min = min;
this.max = max;
}
public void run() {
count = countPrimes(min,max);
System.out.println("There are " + count +
" primes between " + min + " and " + max);
addToTotal(count);
}
}
private static void countPrimesWithThreads(int numberOfThreads) {
int increment = START/numberOfThreads;
System.out.println("\nCounting primes between " + (START+1) + " and "
+ (2*START) + " using " + numberOfThreads + " threads...\n");
long startTime = System.currentTimeMillis();
CountPrimesThread[] worker = new CountPrimesThread[numberOfThreads];
for (int i = 0; i < numberOfThreads; i++)
worker[i] = new CountPrimesThread(START+i*increment+1, START+(i+1)*increment );
total = 0;
for (int i = 0; i < numberOfThreads; i++)
worker[i].start();
for (int i = 0; i < numberOfThreads; i++) {
while (worker[i].isAlive()) {
try {
worker[i].join();
} catch (InterruptedException e) {
}
}
}
long elapsedTime = System.currentTimeMillis() - startTime;
System.out.println("\nThe number of primes is " + total + ".");
System.out.println("\nTotal elapsed time: " + (elapsedTime/1000.0) + " seconds.\n");
}
public static void main(String[] args) {
int processors = Runtime.getRuntime().availableProcessors();
if (processors == 1)
System.out.println("Your computer has only 1 available processor.\n");
else
System.out.println("Your computer has " + processors + " available processors.\n");
int numberOfThreads = 0;
while (numberOfThreads < 1 || numberOfThreads > 5) {
System.out.print("How many threads do you want to use (from 1 to 5) ? ");
numberOfThreads = TextIO.getlnInt();
if (numberOfThreads < 1 || numberOfThreads > 5)
System.out.println("Please enter 1, 2, 3, 4, or 5 !");
}
countPrimesWithThreads(numberOfThreads);
}
private static int countPrimes(int min, int max) {
int count = 0;
for (int i = min; i <= max; i++)
if (isPrime(i))
count++;
return count;
}
private static boolean isPrime(int x) {
int top = (int)Math.sqrt(x);
for (int i = 2; i <= top; i++)
if ( x % i == 0 )
return false;
return true;
}
}
countPrimes does not need synchronization because it does not access any shared variable (it only works with the arguments and local variables). So there is nothing to synchronize.
On the other hand, the total variable is updated from several threads and the access needs to be synchronized to ensure correctness.
What prevents interleaving when countPrimes() is being executed?
Nothing. We don't need to prevent it (see below). And since we don't need to, preventing interleaving would be a bad thing because it would reduce parallelism.
Aren't the variables used by countPrimes() like i, min, max,count` also shared resources?
No. They are local to the current thread; i.e. to the thread whose run() method call is in progress. Nothing else shares them.
And what about isPrime() which is called by countPrimes()?
Same deal. It is only using local variables, so no synchronization is necessary.
The synchronized keyword simply acquires the monitor for some object. If another thread already has the monitor it will have to wait for that thread to finish before it can acquire it and proceed. Any piece of code that synchronizes on a common object will not be able to run concurrently since only one thread can acquire the monitor on that object at any given time. In the case of methods the monitor used is implicit. For non-static methods it's the instance it was called on, for static methods it's the Class for the type it's called on.
That's one possible reason but it hardly constitutes an accurate indication of when to use the keyword.
To answer the question I would say you use synchronized whenever you don't want two threads concurrently executing a critical section based upon a common monitor. The situations in which you would need this are many and riddled with far too many gotchas and exceptions to explain fully.
You can't prevent access to an entire class with synchronized. You can make every method synchronized, but still that's not quite the same thing. Plus, it only prevents other threads from accessing the critical section when synchronized on the same monitor.

[Java]Arrays and Collections test, unexpected outcome?

There are probably hundreds of questions about Java Collections vs. arrays, but this is something I really didn't expect.
I am developing a server for my game, and to communicate between the client and server you need to send packets (obviously), so I did some tests which Collection (or array) I could use best to handle them, HashMap, ArrayList and a PacketHandler array. And the outcome is very unexpected to me, because the ArrayList wins.
The packet handling structure is just like dictionary usage (index to PacketHandler), and because an array is the most primitive form of dictionary use I thought that would easily perform better than an ArrayList. Could someone explain me why this is?
My test
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;
public class Main {
/**
* Packet handler interface.
*/
private interface PacketHandler {
void handle();
}
/**
* A dummy packet handler.
*/
private class DummyPacketHandler implements PacketHandler {
#Override
public void handle() { }
}
public Main() {
Random r = new Random();
PacketHandler[] handlers = new PacketHandler[256];
HashMap<Integer, PacketHandler> m = new HashMap<Integer, PacketHandler>();
ArrayList<PacketHandler> list = new ArrayList<PacketHandler>();
// packet handler initialization
for (int i = 0; i < 255; i++) {
DummyPacketHandler p = new DummyPacketHandler();
handlers[i] = p;
m.put(new Integer(i), p);
list.add(p);
}
// array
long time = System.currentTimeMillis();
for (int i = 0; i < 10000000; i++)
handlers[r.nextInt(255)].handle();
System.out.println((System.currentTimeMillis() - time));
// hashmap
time = System.currentTimeMillis();
for (int i = 0; i < 10000000; i++)
m.get(new Integer(r.nextInt(255))).handle();
System.out.println((System.currentTimeMillis() - time));
// arraylist
time = System.currentTimeMillis();
for (int i = 0; i < 10000000; i++)
list.get(r.nextInt(255)).handle();
System.out.println((System.currentTimeMillis() - time));
}
public static void main(String[] args) {
new Main();
}
}
I think the problem is quite solved, thanks everybody
The shorter answer is that ArrayList is slightly more optimised the first time, but is still slower in the long run.
How and when the JVM optimise the code before its completely warmed up isn't always obvious and can change between version and based on your command line options.
What is really interesting is what you get when you repeat the test. The reason that makes a difference here is that the code is compiled in stages in the background as you want to have tests where the code is already as fast as it will get right from the start.
There are a few things you can do to make your benchmark more reproducaeable.
generate your random numbers in advance, they are not part of your test but can slow you down.
place each loop in a separate method. The first loop triggers the whole method to be compiled for better or worse.
repeat the test 5 to 10 times and ignore the first one.
Using System.nanoTime() instead of currentTimeMillis() It may not make any difference here but is a good habit to get into.
Use autoboxing where you can so it uses the integer cache or Integer.valueOf(n) which does the same thing. new Integer(n) will always create an object.
make sure your inner loop does something otherwise its quite likely the JIT will optimise it away to nothing. ;)
.
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;
public class Main {
/**
* Packet handler interface.
*/
private interface PacketHandler {
void handle();
}
/**
* A dummy packet handler.
*/
static class DummyPacketHandler implements PacketHandler {
#Override
public void handle() {
}
}
public static void main(String[] args) {
Random r = new Random();
PacketHandler[] handlers = new PacketHandler[256];
HashMap<Integer, PacketHandler> m = new HashMap<Integer, PacketHandler>();
ArrayList<PacketHandler> list = new ArrayList<PacketHandler>();
// packet handler initialization
for (int i = 0; i < 256; i++) {
DummyPacketHandler p = new DummyPacketHandler();
handlers[i] = p;
m.put(new Integer(i), p);
list.add(p);
}
int runs = 10000000;
int[] handlerToUse = new int[runs];
for (int i = 0; i < runs; i++)
handlerToUse[i] = r.nextInt(256);
for (int i = 0; i < 5; i++) {
testArray(handlers, runs, handlerToUse);
testHashMap(m, runs, handlerToUse);
testArrayList(list, runs, handlerToUse);
System.out.println();
}
}
private static void testArray(PacketHandler[] handlers, int runs, int[] handlerToUse) {
// array
long time = System.nanoTime();
for (int i = 0; i < runs; i++)
handlers[handlerToUse[i]].handle();
System.out.print((System.nanoTime() - time)/1e6+" ");
}
private static void testHashMap(HashMap<Integer, PacketHandler> m, int runs, int[] handlerToUse) {
// hashmap
long time = System.nanoTime();
for (int i = 0; i < runs; i++)
m.get(handlerToUse[i]).handle();
System.out.print((System.nanoTime() - time)/1e6+" ");
}
private static void testArrayList(ArrayList<PacketHandler> list, int runs, int[] handlerToUse) {
// arraylist
long time = System.nanoTime();
for (int i = 0; i < runs; i++)
list.get(handlerToUse[i]).handle();
System.out.print((System.nanoTime() - time)/1e6+" ");
}
}
prints for array HashMap ArrayList
24.62537 263.185092 24.19565
28.997305 206.956117 23.437585
19.422327 224.894738 21.191718
14.154433 194.014725 16.927638
13.897081 163.383876 16.678818
After the code warms up, the array is marginally faster.
There are at least a few problems with your benchmark:
you run your tests directly in main, meaning that when you main method gets compiled, the JIT compiler has not had time to optimise all the code because it has not run it yet
the map method creates a new integer each time, which is not fair: use m.get(r.nextInt(255)).handle(); to allow the Integer cache to be used
you need to run your test several times before you can draw conclusions
you are not using the result of what you do in your loops and the JIT is therefore allowed to simply ignore them
monitor GC as it might always run at the same time and bias the results of one of your loop and add a System.gc() call between each loop.
But before doing all that, read this post ;-)
After tweaking your code a bit, I get these results:
Array: 116
Map: 139
List: 117
So array and list are close to identical once compiled and map is slightly slower.
Code:
public class Main {
/**
* Packet handler interface.
*/
private interface PacketHandler {
int handle();
}
/**
* A dummy packet handler.
*/
private class DummyPacketHandler implements PacketHandler {
#Override
public int handle() {
return 123;
}
}
public Main() {
Random r = new Random();
PacketHandler[] handlers = new PacketHandler[256];
HashMap<Integer, PacketHandler> m = new HashMap<Integer, PacketHandler>();
ArrayList<PacketHandler> list = new ArrayList<PacketHandler>();
// packet handler initialization
for (int i = 0; i < 255; i++) {
DummyPacketHandler p = new DummyPacketHandler();
handlers[i] = p;
m.put(new Integer(i), p);
list.add(p);
}
long sum = 0;
runArray(handlers, r, 20000);
runMap(m, r, 20000);
runList(list, r, 20000);
// array
long time = System.nanoTime();
sum += runArray(handlers, r, 10000000);
System.out.println("Array: " + (System.nanoTime() - time) / 1000000);
// hashmap
time = System.nanoTime();
sum += runMap(m, r, 10000000);
System.out.println("Map: " + (System.nanoTime() - time) / 1000000);
// arraylist
time = System.nanoTime();
sum += runList(list, r, 10000000);
System.out.println("List: " + (System.nanoTime() - time) / 1000000);
System.out.println(sum);
}
public static void main(String[] args) {
new Main();
}
private long runArray(PacketHandler[] handlers, Random r, int loops) {
long sum = 0;
for (int i = 0; i < loops; i++)
sum += handlers[r.nextInt(255)].handle();
return sum;
}
private long runMap(HashMap<Integer, PacketHandler> m, Random r, int loops) {
long sum = 0;
for (int i = 0; i < loops; i++)
sum += m.get(new Integer(r.nextInt(255))).handle();
return sum;
}
private long runList(List<PacketHandler> list, Random r, int loops) {
long sum = 0;
for (int i = 0; i < loops; i++)
sum += list.get(r.nextInt(255)).handle();
return sum;
}
}

Java performance of redesigning nested loops into methods

Someone asked me about this and after reading some big O stuff I still can't figure out which of the 2 designs is faster.
If I have this kind of nested loop in one method
public void someMethod(){
for (a=0;a<10;a++){
for (b=0;b<10;b++){
for (c=0;c<10;c++){
for (d=0;d<10;d++){
}
}
}
}
}
and I decided to redesign the method and place the 2 inner for loops to another method something like this
public void someMethod(){
for (a=0;a<10;a++){
for (b=0;b<10;b++){
2loopsMethod();
}
}
}
public void 2loopsMethod(){
for (c=0;c<10;c++){
for (d=0;d<10;d++){
}
}
}
My question is will the redesigned method be alot faster that the original code since I placed it in another method or will it make no difference?
It should make no difference. You still have four levels of nested loops, so delegating part of the work to a method call will not be faster.
(Technically the added overhead of the method call will make the second example slightly slower, but if your code is doing anything significant at all I'd be surprised if you can even measure the difference.)
Big O complexity is the same. I think the first version is faster because you don't have the a*b method calls. And in theory method calls take extra time.
The redesigned method is a just a little little bit slower in your case because method invocation takes additional time (unlikely e.g. to C++ inline functions). You'll definitely see the difference if you increase the number of loop iterations.
Due to compiler optimizations on methods, second example is preffered:
public class Try1 {
static int sum;
public static void main(String[] args) {
long startTime, endTime;
while(true)
{
sum = 0;
startTime = System.nanoTime();
for (int i = 0; i < 2000; i++) {
for (int j = 0; j < 1000; j++) {
sum = sum + i;
}
}
endTime = System.nanoTime();
System.out.println("no method took:" + (endTime -startTime) );
sum = 0;
startTime = System.nanoTime();
for (int i = 0; i < 2000; i++) {
func(i);
}
endTime = System.nanoTime();
System.out.println("with method took:" + (endTime -startTime) );
}
}
private static final void func(int i) {
for (int j = 0; j < 1000; j++) {
sum = sum + i;
}
}
}
end the results:
no method took:3077459
with method took:2418027
no method took:5535578
with method took:76014
no method took:3857167
with method took:88844
no method took:3758701
with method took:89165
no method took:3761588
with method took:88844

Categories

Resources