Performance comparison for loops of List in java

本文涉及的产品
实时计算 Flink 版,1000CU*H 3个月
简介:

Introduce five loop ways for both ArrayList and LinkedList, the performance test comparing different ways, Analysis of performance results according to the source code of ArrayList and LinkedList, summarize conclusions.

Through this article you can learn (1) Five traversal methods and their performance of List (2) foreach and Iterator implementation (3) understand of ArrayList and LinkedList implementation.
Before reading this article I hope you have learned sequential storage of ArrayList and chain structure of LinkedList.

Related: Performance comparison of different ways to iterate over HashMap

1. Five loop ways for List
Here is a brief example of a variety of traversal (in case of ArrayList) , the respective advantages and disadvantages will be analyzed later in this conclusion is given .
(1) for each loop

Java

1

2

3

4

List<Integer> list = new ArrayList<Integer>();

for (Integer j : list) {

// use j

}

(2) obvious call iterator

Java

1

2

3

4

List<Integer> list = new ArrayList<Integer>();

for (Iterator<Integer> iterator = list.iterator(); iterator.hasNext();) {

iterator.next();

}

or

Java

1

2

3

4

5

List<Integer> list = new ArrayList<Integer>();

Iterator<Integer> iterator = list.iterator();

while (iterator.hasNext()) {

iterator.next();

}

(3) use get() with index increase, termination condition call size () function

Java

1

2

3

4

List<Integer> list = new ArrayList<Integer>();

for (int j = 0; j < list.size(); j++) {

list.get(j);

}

(4) use get() with index increase, termination condition use temp variablereplace size () function

Java

1

2

3

4

5

List<Integer> list = new ArrayList<Integer>();

int size = list.size();

for (int j = 0; j < size; j++) {

list.get(j);

}

(5) use get() with index decrease

Java

1

2

3

4

List<Integer> list = new ArrayList<Integer>();

for (int j = list.size() - 1; j >= 0; j--) {

list.get(j);

}

Before the test we can think about which performance is better of the five kinds of traversal above, based on the data structure of the List and understanding of Iterator .

2、Performance testing of five kinds of traversal above and contrast
The following is the source code of performance test, it will print time spent for different magnitude and different way of ArrayList and LinkedList loop.

ArrayList和LinkedList循环性能对比测试代码

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

package cn.trinea.java.test;

import java.text.DecimalFormat;

import java.util.ArrayList;

import java.util.Calendar;

import java.util.Iterator;

import java.util.LinkedList;

import java.util.List;

/**

* JavaLoopTest

*

* @author www.trinea.cn 2013-10-28

*/

public class JavaLoopTest {

public static void main(String[] args) {

System.out.print("compare loop performance of ArrayList");

loopListCompare(getArrayLists(10000, 100000, 1000000, 9000000));

System.out.print("\r\n\r\ncompare loop performance of LinkedList");

loopListCompare(getLinkedLists(100, 1000, 10000, 100000));

}

public static List<Integer>[] getArrayLists(int... sizeArray) {

List<Integer>[] listArray = new ArrayList[sizeArray.length];

for (int i = 0; i < listArray.length; i++) {

int size = sizeArray[i];

List<Integer> list = new ArrayList<Integer>();

for (int j = 0; j < size; j++) {

list.add(j);

}

listArray[i] = list;

}

return listArray;

}

public static List<Integer>[] getLinkedLists(int... sizeArray) {

List<Integer>[] listArray = new LinkedList[sizeArray.length];

for (int i = 0; i < listArray.length; i++) {

int size = sizeArray[i];

List<Integer> list = new LinkedList<Integer>();

for (int j = 0; j < size; j++) {

list.add(j);

}

listArray[i] = list;

}

return listArray;

}

public static void loopListCompare(List<Integer>... listArray) {

printHeader(listArray);

long startTime, endTime;

// Type 1

for (int i = 0; i < listArray.length; i++) {

List<Integer> list = listArray[i];

startTime = Calendar.getInstance().getTimeInMillis();

for (Integer j : list) {

// use j

}

endTime = Calendar.getInstance().getTimeInMillis();

printCostTime(i, listArray.length, "for each", endTime - startTime);

}

// Type 2

for (int i = 0; i < listArray.length; i++) {

List<Integer> list = listArray[i];

startTime = Calendar.getInstance().getTimeInMillis();

// Iterator<Integer> iterator = list.iterator();

// while(iterator.hasNext()) {

// iterator.next();

// }

for (Iterator<Integer> iterator = list.iterator(); iterator.hasNext();) {

iterator.next();

}

endTime = Calendar.getInstance().getTimeInMillis();

printCostTime(i, listArray.length, "for iterator", endTime - startTime);

}

// Type 3

for (int i = 0; i < listArray.length; i++) {

List<Integer> list = listArray[i];

startTime = Calendar.getInstance().getTimeInMillis();

for (int j = 0; j < list.size(); j++) {

list.get(j);

}

endTime = Calendar.getInstance().getTimeInMillis();

printCostTime(i, listArray.length, "for list.size()", endTime - startTime);

}

// Type 4

for (int i = 0; i < listArray.length; i++) {

List<Integer> list = listArray[i];

startTime = Calendar.getInstance().getTimeInMillis();

int size = list.size();

for (int j = 0; j < size; j++) {

list.get(j);

}

endTime = Calendar.getInstance().getTimeInMillis();

printCostTime(i, listArray.length, "for size = list.size()", endTime - startTime);

}

// Type 5

for (int i = 0; i < listArray.length; i++) {

List<Integer> list = listArray[i];

startTime = Calendar.getInstance().getTimeInMillis();

for (int j = list.size() - 1; j >= 0; j--) {

list.get(j);

}

endTime = Calendar.getInstance().getTimeInMillis();

printCostTime(i, listArray.length, "for j--", endTime - startTime);

}

}

static int FIRST_COLUMN_LENGTH = 23, OTHER_COLUMN_LENGTH = 12, TOTAL_COLUMN_LENGTH = 71;

static final DecimalFormat COMMA_FORMAT = new DecimalFormat("#,###");

public static void printHeader(List<Integer>... listArray) {

printRowDivider();

for (int i = 0; i < listArray.length; i++) {

if (i == 0) {

StringBuilder sb = new StringBuilder().append("list size");

while (sb.length() < FIRST_COLUMN_LENGTH) {

sb.append(" ");

}

System.out.print(sb);

}

StringBuilder sb = new StringBuilder().append("| ").append(COMMA_FORMAT.format(listArray[i].size()));

while (sb.length() < OTHER_COLUMN_LENGTH) {

sb.append(" ");

}

System.out.print(sb);

}

TOTAL_COLUMN_LENGTH = FIRST_COLUMN_LENGTH + OTHER_COLUMN_LENGTH * listArray.length;

printRowDivider();

}

public static void printRowDivider() {

System.out.println();

StringBuilder sb = new StringBuilder();

while (sb.length() < TOTAL_COLUMN_LENGTH) {

sb.append("-");

}

System.out.println(sb);

}

public static void printCostTime(int i, int size, String caseName, long costTime) {

if (i == 0) {

StringBuilder sb = new StringBuilder().append(caseName);

while (sb.length() < FIRST_COLUMN_LENGTH) {

sb.append(" ");

}

System.out.print(sb);

}

StringBuilder sb = new StringBuilder().append("| ").append(costTime).append(" ms");

while (sb.length() < OTHER_COLUMN_LENGTH) {

sb.append(" ");

}

System.out.print(sb);

if (i == size - 1) {

printRowDivider();

}

}

}

PS: If you run the code with exception in thread “main” java.lang.OutOfMemoryError: Java heap space, reduce the size of list in main function.

getArrayLists fuction is used to return Arraylist of different size, getLinkedLists fuction is used to return LinkedList of different size。
loopListCompare function will loop list array use loop ways above.
Function begin with print are used to help print。

Test environment is is Windows7 32bits, 3.2G dual core cpu, 4G memory, Java 7, Eclipse -Xms512m -Xmx512m
Final test results are as follows :

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

compare loop performance of ArrayList

-----------------------------------------------------------------------

list size | 10,000 | 100,000 | 1,000,000 | 10,000,000

-----------------------------------------------------------------------

for each | 1 ms | 3 ms | 14 ms | 152 ms

-----------------------------------------------------------------------

for iterator | 0 ms | 1 ms | 12 ms | 114 ms

-----------------------------------------------------------------------

for list.size() | 1 ms | 1 ms | 13 ms | 128 ms

-----------------------------------------------------------------------

for size = list.size() | 0 ms | 0 ms | 6 ms | 62 ms

-----------------------------------------------------------------------

for j-- | 0 ms | 1 ms | 6 ms | 63 ms

-----------------------------------------------------------------------

compare loop performance of LinkedList

-----------------------------------------------------------------------

list size | 100 | 1,000 | 10,000 | 100,000

-----------------------------------------------------------------------

for each | 0 ms | 1 ms | 1 ms | 2 ms

-----------------------------------------------------------------------

for iterator | 0 ms | 0 ms | 0 ms | 2 ms

-----------------------------------------------------------------------

for list.size() | 0 ms | 1 ms | 73 ms | 7972 ms

-----------------------------------------------------------------------

for size = list.size() | 0 ms | 0 ms | 67 ms | 8216 ms

-----------------------------------------------------------------------

for j-- | 0 ms | 1 ms | 67 ms | 8277 ms

-----------------------------------------------------------------------

The first table show the compare results for the ArrayList, second table shows the compare result of LinkedList.

Row represents time spent for different size of list with same loop way, Column represents time spent for different loop way with same list.

PS: As for the first loop time will be a little more time consuming, result for loop way use for each is a little deviation.You can change the order of different loop way in the test code, you will find time-consuming with loop way use for each is close to loop way use for iterator.

3、Analysis performance test results
(1) foreach
foreach is a loop structure, introduced in Java SE5.0, for (Integer j: list) should be readed as for each int in list.
for (Integer j : list) almost equivalent to

Java

1

2

3

4

Iterator<Integer> iterator = list.iterator();

while(iterator.hasNext()) {

Integer j = iterator.next();

}

The following analysis will classified obvious call iterator and for each as loop way of Iterator, the other three are classified as loop way of get.

We have found that one of the major benefits of foreach, the simple line to achieve a four-line features, that make the code simple and beautiful, the other big advantage is relative to loop way of get, foreach no need to care about index out of bound, so you will not go wrong. Effective-Java recommended use foreach instead of index loop, we will verify this statement.

class which can use foreach must implement the Iterable interface, Java’s Collection inherit from interfaces already, List implements Collection. The Iterable interface contains only one function, source code is as follows:

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

package java.lang;

import java.util.Iterator;

/**

* Implementing this interface allows an object to be the target of

* the "foreach" statement.

*

* @param <T> the type of elements returned by the iterator

*

* @since 1.5

*/

public interface Iterable<T> {

/**

* Returns an iterator over a set of elements of type T.

*

* @return an Iterator.

*/

Iterator<T> iterator();

}

iterator () is used to return an Iterator. from implementation of foreach we can see , it will call this function to get Iterator, and then get the next element through the next() function of Iterator, hasNext() determine whether there are more elements. Iterator source as follows:

Java

1

2

3

4

5

6

7

public interface Iterator<E> {

boolean hasNext();

E next();

void remove();

}

(2) Analysis performance test results of ArrayList

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

compare loop performance of ArrayList

-----------------------------------------------------------------------

list size | 10,000 | 100,000 | 1,000,000 | 10,000,000

-----------------------------------------------------------------------

for each | 1 ms | 3 ms | 14 ms | 152 ms

-----------------------------------------------------------------------

for iterator | 0 ms | 1 ms | 12 ms | 114 ms

-----------------------------------------------------------------------

for list.size() | 1 ms | 1 ms | 13 ms | 128 ms

-----------------------------------------------------------------------

for size = list.size() | 0 ms | 0 ms | 6 ms | 62 ms

-----------------------------------------------------------------------

for j-- | 0 ms | 1 ms | 6 ms | 63 ms

-----------------------------------------------------------------------

PS: As for the first loop time will be a little more time consuming, result for loop way use for each is a little deviation.You can change the order of different loop way in the test code, you will find time-consuming with loop way use for each is close to loop way use for iterator.

From the above we can see that :

a. the time-consuming is about same when size of arrayList size is one hundred thousand or less.
b. when size of arrayList size is bigger than one hundred thousand, loop use Iterator cost more time than loop use get, but just abount 50ms. use temp variable is better than list.size() function.

Java

1

2

3

4

int size = list.size();

for (int j = 0; j < size; j++) {

list.get(j);

}

following are implements of Iterator and get() function in ArrayList

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

private class Itr implements Iterator<E> {

int cursor; // index of next element to return

int lastRet = -1; // index of last element returned; -1 if no such

int expectedModCount = modCount;

public boolean hasNext() {

return cursor != size;

}

@SuppressWarnings("unchecked")

public E next() {

checkForComodification();

int i = cursor;

if (i >= size)

throw new NoSuchElementException();

Object[] elementData = ArrayList.this.elementData;

if (i >= elementData.length)

throw new ConcurrentModificationException();

cursor = i + 1;

return (E) elementData[lastRet = i];

}

……

}

public E get(int index) {

rangeCheck(index);

return elementData(index);

}

As you see above, both get() function of ArrayList and next() function of Iterator use index to get element directly, just a few more judgments in next().

c. We can see cost 50ms more even when size of ArrayList is 10,000,000. The time-consuming is about same when size of arrayList size is one hundred thousand or less, and it’s more commmon this situation, so we can choose foreach consider about the advantage of foreach.

(3) Analysis performance test results of LinkedList

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

compare loop performance of LinkedList

-----------------------------------------------------------------------

list size | 100 | 1,000 | 10,000 | 100,000

-----------------------------------------------------------------------

for each | 0 ms | 1 ms | 1 ms | 2 ms

-----------------------------------------------------------------------

for iterator | 0 ms | 0 ms | 0 ms | 2 ms

-----------------------------------------------------------------------

for list.size() | 0 ms | 1 ms | 73 ms | 7972 ms

-----------------------------------------------------------------------

for size = list.size() | 0 ms | 0 ms | 67 ms | 8216 ms

-----------------------------------------------------------------------

for j-- | 0 ms | 1 ms | 67 ms | 8277 ms

-----------------------------------------------------------------------

PS: As for the first loop time will be a little more time consuming, result for loop way use for each is a little deviation.You can change the order of different loop way in the test code, you will find time-consuming with loop way use for each is close to loop way use for iterator.

From the above we can see that :
a. loop way by get() is slower than loop wary by Iterator almost 100 times when size of LinkedList is close to 10,000. loop way by get() is about 8 seconds when size of LinkedList is 100,000.
following are implements of Iterator and get() function in LinkedList:

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

private class ListItr implements ListIterator<E> {

private Node<E> lastReturned = null;

private Node<E> next;

private int nextIndex;

private int expectedModCount = modCount;

ListItr(int index) {

// assert isPositionIndex(index);

next = (index == size) ? null : node(index);

nextIndex = index;

}

public boolean hasNext() {

return nextIndex < size;

}

public E next() {

checkForComodification();

if (!hasNext())

throw new NoSuchElementException();

lastReturned = next;

next = next.next;

nextIndex++;

return lastReturned.item;

}

……

}

public E get(int index) {

checkElementIndex(index);

return node(index).item;

}

/**

* Returns the (non-null) Node at the specified element index.

*/

Node<E> node(int index) {

// assert isElementIndex(index);

if (index < (size >> 1)) {

Node<E> x = first;

for (int i = 0; i < index; i++)

x = x.next;

return x;

} else {

Node<E> x = last;

for (int i = size - 1; i > index; i--)

x = x.prev;

return x;

}

}

As we can see above, the next() function get element by next pointer of last element, the time complexity of traversing use Iterator is O(n). but get() get element from the first index every time, find an element of time complexity is O(n), the time complexity of traversing use get() reached O(n2).

So loop LinkedList recommend using foreach, avoid using get().

(4) Compare performance test results of ArrayList and LinkedList
Through the above results we can see. time-comsuming is almost same for ArrayList and LinkedList when loop by foreach, but the time complexity of get() for LinkedList is O(n), and just O(1) for ArrayList, and ArrayList cost less memory, so we recommended using ArrayList first when choose List.

4、Summarize Conclusions
Through the analysis above, we can basically summarize:

(1) Whether ArrayList or LinkedList, loop it recommended foreach. avoid loop LinkedList by get() especially when size is big.
(2) Preferred using ArrayList when choose List. We can use LinkedList For situations there are more operations of insert and delete.
(3) There is situation we need the index of List when loop, this time we should consider use get() or foreach and count++ according necceary. If LinkedList, recommended use foreach and count++.

相关实践学习
基于Hologres+Flink搭建GitHub实时数据大屏
通过使用Flink、Hologres构建实时数仓,并通过Hologres对接BI分析工具(以DataV为例),实现海量数据实时分析.
实时计算 Flink 实战课程
如何使用实时计算 Flink 搞定数据处理难题?实时计算 Flink 极客训练营产品、技术专家齐上阵,从开源 Flink功能介绍到实时计算 Flink 优势详解,现场实操,5天即可上手! 欢迎开通实时计算 Flink 版: https://cn.aliyun.com/product/bigdata/sc Flink Forward Asia 介绍: Flink Forward 是由 Apache 官方授权,Apache Flink Community China 支持的会议,通过参会不仅可以了解到 Flink 社区的最新动态和发展计划,还可以了解到国内外一线大厂围绕 Flink 生态的生产实践经验,是 Flink 开发者和使用者不可错过的盛会。 去年经过品牌升级后的 Flink Forward Asia 吸引了超过2000人线下参与,一举成为国内最大的 Apache 顶级项目会议。结合2020年的特殊情况,Flink Forward Asia 2020 将在12月26日以线上峰会的形式与大家见面。
目录
相关文章
|
安全 Java
java线程之List集合并发安全问题及解决方案
java线程之List集合并发安全问题及解决方案
1313 1
|
运维 关系型数据库 Java
PolarDB产品使用问题之使用List或Range分区表时,Java代码是否需要进行改动
PolarDB产品使用合集涵盖了从创建与管理、数据管理、性能优化与诊断、安全与合规到生态与集成、运维与支持等全方位的功能和服务,旨在帮助企业轻松构建高可用、高性能且易于管理的数据库环境,满足不同业务场景的需求。用户可以通过阿里云控制台、API、SDK等方式便捷地使用这些功能,实现数据库的高效运维与持续优化。
|
Java API Apache
怎么在在 Java 中对List进行分区
本文介绍了如何将列表拆分为给定大小的子列表。尽管标准Java集合API未直接支持此功能,但Guava和Apache Commons Collections提供了相关API。
373 1
|
存储 安全 Java
详解Java中集合的List接口实现的ArrayList方法 | Set接口实现的HashSet方法
详解Java中集合的List接口实现的ArrayList方法 | Set接口实现的HashSet方法
270 3
|
Java API
使用 Java 来实现两个 List 的差集操作
使用 Java 来实现两个 List 的差集操作
1041 3
|
安全 Java 索引
Java List:从入门到精通,一篇文章就够了!
【6月更文挑战第17天】Java List是有序元素集合,支持索引访问、添加、删除和修改。从ArrayList、LinkedList到Vector,各种实现满足不同场景需求。使用add()添加元素,get()获取,set()修改,remove()删除。遍历可用for-each或Iterator,subList()创建子集。注意线程安全,可选synchronizedList()、Vector或CopyOnWriteArrayList。理解List的基本操作和特性,能提升编程效率。
277 1
|
存储 Java 索引
告别Java集合小白!一文读懂List的精髓
【6月更文挑战第17天】Java中的List接口作为有序集合,允许存储和操作有序元素,支持重复值。ArrayList和LinkedList是常见实现类:ArrayList基于数组,适合快速访问但插入删除慢;LinkedList基于链表,插入删除快但访问慢。了解其核心概念、方法及泛型使用,能提升编程效率和代码质量。示例代码展示了添加和访问元素。通过深入学习,可以更好地掌握List的高级用法。
191 1
|
存储 Java 索引
Java List接口实现原理与性能评估
Java List接口实现原理与性能评估
|
存储 缓存 安全
Java List操作详解及常用方法
Java List操作详解及常用方法
|
存储 Java 索引
Java List接口实现原理与性能评估
Java List接口实现原理与性能评估

热门文章

最新文章