Các foreach
vòng lặp , bổ sung trong Java 5 (hay còn gọi là "tăng cường cho vòng lặp"), tương đương với sử dụng một java.util.Iterator
đường cú pháp của --it cho điều tương tự. Do đó, khi đọc từng phần tử, từng phần một và theo thứ tự, foreach
luôn luôn phải chọn một phần tử lặp, vì nó thuận tiện và ngắn gọn hơn.
cho mỗi
for(int i : intList) {
System.out.println("An element in the list: " + i);
}
Lặp lại
Iterator<Integer> intItr = intList.iterator();
while(intItr.hasNext()) {
System.out.println("An element in the list: " + intItr.next());
}
Có những tình huống mà bạn phải sử dụng Iterator
trực tiếp. Ví dụ: cố gắng xóa một phần tử trong khi sử dụng foreach
kết quả có thể (sẽ?) Trong a ConcurrentModificationException
.
foreach
vs for
.: Sự khác biệt cơ bản
Sự khác biệt thực tế duy nhất giữa for
và foreach
là, trong trường hợp các đối tượng có thể lập chỉ mục, bạn không có quyền truy cập vào chỉ mục. Một ví dụ khi for
vòng lặp cơ bản được yêu cầu:
for(int i = 0; i < array.length; i++) {
if(i < 5) {
// Do something special
} else {
// Do other stuff
}
}
Mặc dù bạn bằng tay có thể tạo ra một chỉ số riêng biệt int biến với foreach
,
int idx = -1;
for(int i : intArray) {
idx++;
...
}
không nên, vì phạm vi biến không lý tưởng và for
vòng lặp cơ bản chỉ đơn giản là định dạng chuẩn và dự kiến cho trường hợp sử dụng này.
foreach
vs for
: Hiệu suất
Khi truy cập vào bộ sưu tập, một foreach
là đáng kể nhanh hơn so với cơ bản for
truy cập mảng vòng lặp của. Tuy nhiên, khi truy cập mảng - ít nhất là với mảng nguyên thủy và mảng bao bọc - truy cập qua các chỉ mục nhanh hơn đáng kể.
Định thời gian cho sự khác biệt giữa truy cập iterator và chỉ mục cho các mảng int nguyên thủy
Các chỉ mục nhanh hơn 23- 40 phần trăm so với các trình vòng lặp khi truy cập int
hoặc Integer
mảng. Đây là đầu ra từ lớp thử nghiệm ở dưới cùng của bài đăng này, tính tổng các số trong một mảng nguyên thủy 100 phần tử (A là iterator, B là chỉ mục):
[C:\java_code\]java TimeIteratorVsIndexIntArray 1000000
Test A: 358,597,622 nanoseconds
Test B: 269,167,681 nanoseconds
B faster by 89,429,941 nanoseconds (24.438799231635727% faster)
[C:\java_code\]java TimeIteratorVsIndexIntArray 1000000
Test A: 377,461,823 nanoseconds
Test B: 278,694,271 nanoseconds
B faster by 98,767,552 nanoseconds (25.666236154695838% faster)
[C:\java_code\]java TimeIteratorVsIndexIntArray 1000000
Test A: 288,953,495 nanoseconds
Test B: 207,050,523 nanoseconds
B faster by 81,902,972 nanoseconds (27.844689860906513% faster)
[C:\java_code\]java TimeIteratorVsIndexIntArray 1000000
Test A: 375,373,765 nanoseconds
Test B: 283,813,875 nanoseconds
B faster by 91,559,890 nanoseconds (23.891659337194227% faster)
[C:\java_code\]java TimeIteratorVsIndexIntArray 1000000
Test A: 375,790,818 nanoseconds
Test B: 220,770,915 nanoseconds
B faster by 155,019,903 nanoseconds (40.75164734599769% faster)
[C:\java_code\]java TimeIteratorVsIndexIntArray 1000000
Test A: 326,373,762 nanoseconds
Test B: 202,555,566 nanoseconds
B faster by 123,818,196 nanoseconds (37.437545972215744% faster)
Tôi cũng đã chạy nó cho một Integer
mảng và các chỉ mục vẫn là người chiến thắng rõ ràng, nhưng chỉ nhanh hơn từ 18 đến 25%.
Đối với các bộ sưu tập, các trình vòng lặp nhanh hơn các chỉ mục
Đối với một List
số Integers
tuy nhiên,, vòng lặp là người chiến thắng rõ ràng. Chỉ cần thay đổi mảng int trong lớp thử nghiệm thành:
List<Integer> intList = Arrays.asList(new Integer[] {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});
Và thực hiện các thay đổi cần thiết cho chức năng kiểm tra ( int[]
đến List<Integer>
, length
đến size()
, v.v.):
[C:\java_code\]java TimeIteratorVsIndexIntegerList 1000000
Test A: 3,429,929,976 nanoseconds
Test B: 5,262,782,488 nanoseconds
A faster by 1,832,852,512 nanoseconds (34.326681820485675% faster)
[C:\java_code\]java TimeIteratorVsIndexIntegerList 1000000
Test A: 2,907,391,427 nanoseconds
Test B: 3,957,718,459 nanoseconds
A faster by 1,050,327,032 nanoseconds (26.038700083921256% faster)
[C:\java_code\]java TimeIteratorVsIndexIntegerList 1000000
Test A: 2,566,004,688 nanoseconds
Test B: 4,221,746,521 nanoseconds
A faster by 1,655,741,833 nanoseconds (38.71935684115413% faster)
[C:\java_code\]java TimeIteratorVsIndexIntegerList 1000000
Test A: 2,770,945,276 nanoseconds
Test B: 3,829,077,158 nanoseconds
A faster by 1,058,131,882 nanoseconds (27.134122749113843% faster)
[C:\java_code\]java TimeIteratorVsIndexIntegerList 1000000
Test A: 3,467,474,055 nanoseconds
Test B: 5,183,149,104 nanoseconds
A faster by 1,715,675,049 nanoseconds (32.60101667104192% faster)
[C:\java_code\]java TimeIteratorVsIndexIntList 1000000
Test A: 3,439,983,933 nanoseconds
Test B: 3,509,530,312 nanoseconds
A faster by 69,546,379 nanoseconds (1.4816434912159906% faster)
[C:\java_code\]java TimeIteratorVsIndexIntList 1000000
Test A: 3,451,101,466 nanoseconds
Test B: 5,057,979,210 nanoseconds
A faster by 1,606,877,744 nanoseconds (31.269164666060377% faster)
Trong một thử nghiệm, chúng gần như tương đương, nhưng với các bộ sưu tập, iterator thắng.
* Bài đăng này dựa trên hai câu trả lời tôi đã viết trên Stack Overflow:
Một số thông tin khác: Cái nào hiệu quả hơn, vòng lặp for-every hoặc iterator?
Lớp kiểm tra đầy đủ
Tôi đã tạo ra lớp so sánh-thời gian-thời gian cần làm này sau khi đọc câu hỏi này trên Stack Overflow:
import java.text.NumberFormat;
import java.util.Locale;
/**
<P>{@code java TimeIteratorVsIndexIntArray 1000000}</P>
@see <CODE><A HREF="/programming/180158/how-do-i-time-a-methods-execution-in-java">/programming/180158/how-do-i-time-a-methods-execution-in-java</A></CODE>
**/
public class TimeIteratorVsIndexIntArray {
public static final NumberFormat nf = NumberFormat.getNumberInstance(Locale.US);
public static final void main(String[] tryCount_inParamIdx0) {
int testCount;
// Get try-count from a command-line parameter
try {
testCount = Integer.parseInt(tryCount_inParamIdx0[0]);
}
catch(ArrayIndexOutOfBoundsException | NumberFormatException x) {
throw new IllegalArgumentException("Missing or invalid command line parameter: The number of testCount for each test. " + x);
}
//Test proper...START
int[] intArray = new int[] {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};
long lStart = System.nanoTime();
for(int i = 0; i < testCount; i++) {
testIterator(intArray);
}
long lADuration = outputGetNanoDuration("A", lStart);
lStart = System.nanoTime();
for(int i = 0; i < testCount; i++) {
testFor(intArray);
}
long lBDuration = outputGetNanoDuration("B", lStart);
outputGetABTestNanoDifference(lADuration, lBDuration, "A", "B");
}
private static final void testIterator(int[] int_array) {
int total = 0;
for(int i = 0; i < int_array.length; i++) {
total += int_array[i];
}
}
private static final void testFor(int[] int_array) {
int total = 0;
for(int i : int_array) {
total += i;
}
}
//Test proper...END
//Timer testing utilities...START
public static final long outputGetNanoDuration(String s_testName, long l_nanoStart) {
long lDuration = System.nanoTime() - l_nanoStart;
System.out.println("Test " + s_testName + ": " + nf.format(lDuration) + " nanoseconds");
return lDuration;
}
public static final long outputGetABTestNanoDifference(long l_aDuration, long l_bDuration, String s_aTestName, String s_bTestName) {
long lDiff = -1;
double dPct = -1.0;
String sFaster = null;
if(l_aDuration > l_bDuration) {
lDiff = l_aDuration - l_bDuration;
dPct = 100.00 - (l_bDuration * 100.0 / l_aDuration + 0.5);
sFaster = "B";
}
else {
lDiff = l_bDuration - l_aDuration;
dPct = 100.00 - (l_aDuration * 100.0 / l_bDuration + 0.5);
sFaster = "A";
}
System.out.println(sFaster + " faster by " + nf.format(lDiff) + " nanoseconds (" + dPct + "% faster)");
return lDiff;
}
//Timer testing utilities...END
}