Short answer
If you want "best performance", the shorter time in iteration: Use "for loop" for small matrix, for bigger cases you can consider use "parallel streams"
.. long answer
I created a test to measure the average time of execution one of three options.
"For loop:"
for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { doSomething(numOfVertices[i][j]); } }
"IntStream.range:"
IntStream.range(0, size) .forEach(i -> (IntStream.range(0, size)) .forEach(j -> { doSomething(numOfVertices[i][j]); }));
"IntStream.range parallel:"
IntStream.range(0, size).parallel() .forEach(i -> (IntStream.range(0, size)) .forEach(j -> { doSomething(numOfVertices[i][j]); }));
This section was removed as I could not simpulate it's time cost:
if (adjMatrix[i][j] != 0) { graph.addEdge(i, j, adjMatrix[i][j]); }
Below is the whole test code that perform measurement for different matrix. It runs every case 10000 times and gives the average time. Here are the results for run on my computer. For small matrix (form 1 x 1 to 100 x 100) for loop is the best option. When matrix is big (more than 500 x 500) using "IntStream.range parallel" is faster. "IntStream.range" is always worse than "For loop" for every case.
Size: 1 IntStream.range parallel: 0.002300 IntStream.range: 0.002200 For loop: 0.000000 Size: 5 IntStream.range parallel: 0.023000 IntStream.range: 0.000500 For loop: 0.000000 Size: 10 IntStream.range parallel: 0.025800 IntStream.range: 0.000300 For loop: 0.000100 Size: 50 IntStream.range parallel: 0.042200 IntStream.range: 0.004300 For loop: 0.000900 Size: 100 IntStream.range parallel: 0.035000 IntStream.range: 0.006000 For loop: 0.004300 Size: 500 IntStream.range parallel: 0.060200 IntStream.range: 0.102000 For loop: 0.079600 Size: 1000 IntStream.range parallel: 0.122000 IntStream.range: 0.379800 For loop: 0.347400
public static void main(String[] args) { Arrays.asList(1, 5, 10, 50, 100, 500, 1000).forEach( size -> { System.out.println("Size: " + size); Integer[][] numOfVertices = createArray(size); Map<String, Runnable> toRun = Map.of( "For loop:", () -> { for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { doSomething(numOfVertices[i][j]); } } }, "IntStream.range:", () -> { IntStream.range(0, size) .forEach(i -> (IntStream.range(0, size)) .forEach(j -> { doSomething(numOfVertices[i][j]); })); }, "IntStream.range parallel:", () -> { IntStream.range(0, size).parallel() .forEach(i -> (IntStream.range(0, size)) .forEach(j -> { doSomething(numOfVertices[i][j]); })); } ); int howManyTimes = 10000; Map<String, Double> map = new HashMap<>(); toRun.entrySet().forEach(e -> { double time = (((double)IntStream.range(0, howManyTimes).mapToObj( (x) -> executionTime(e.getValue())) .reduce(Long::sum).get()) / howManyTimes); map.put(e.getKey(), time); }); map.entrySet().forEach(e -> { System.out.println(String.format("%25s %f", e.getKey(), e.getValue())); }); } ); } private static Integer[][] createArray(int size) { Integer[][] val = new Integer[size][size]; IntStream.range(0, size).forEach( i -> IntStream.range(0,size).forEach( j -> val[i][j] = (int)(Math.random() * 100) ) ); return val; } private static int doSomething(int val) { return val * val; } private static long executionTime(Runnable execThis) { long startTime = System.currentTimeMillis(); execThis.run(); long endTime = System.currentTimeMillis(); return (endTime-startTime); }
graphobject can allow parallel updates without using a lock. I suspect this is not the case unless your graph data structure is quite carefully designed with this requirement in mind.numOfVerticestonumOfVertices - 1when turning to stream? Second, isgraph.addEdge(…)thread safe? Did you test without.parallel()?