Ba lý do không sử dụng forEach thay cho vòng lặp for cổ điển

adream

New Member
24/10/21
3
1
1
Ha noi, Viet nam
1. Cách viết forEach và for

Hãy xem xét đoạn code sau:

List<Integer> list = Arrays.asList(1, 2, 3);

// Kiểu cũ
for (Integer i : list)

System.out.println(i);

// "Kiểu mới"
list.forEach(System.out:: println);


2. Ba lý do không nên thay thế
  • Hiệu năng
Trong nhiều trường hợp, hiệu suất không quan trọng và bạn không nên thực hiện bất kỳ tối ưu hóa quá sớm nào. Nhưng trong theo một số nghiên cứu thì chi phí của Stream.forEach () so với một vòng lặp for thông thường là nhiều hơn 10% -20% hiệu năng của CPU. Việc sử dụng các vòng lặp riêng lẻ không quan trọng, nhưng nếu ứng dụng có sử dụng nhiều vòng lặp forEach thì sẽ làm tăng tải hệ thống đang kể.
  • Tính dễ đọc
Các bạn hãy tham khảo đoạn code sau:

List<Integer> list = Arrays.asList(1, 2, 3);

// Kiểu cũ
for (Integer i : list)

for (int j = 0; j < i; j++)
System.out.println(i * j);

// "Kiểu mới"
list.forEach(i -> {

IntStream.range(0, i).forEach(j -> {
System.out.println(i * j);
});
});

Cùng là vòng lặp để in ra kết quả như nhau nhưng cách viết theo kiểu cũ rõ ràng hơn nhiều so với kiểu mới.
  • Tính dễ bảo trì
Các bạn hãy xem ví dụ sau:

List<Integer> list = Arrays.asList(1, 2, 3);

// Kiểu cũ
for (Integer i : list)

for (int j = 0; j < i; j++)
System.out.println(i / j);

// "Kiểu mới"
list.forEach(i -> {

IntStream.range(0, i).forEach(j -> {
System.out.println(i / j);
});
});


Cả hai ví dụ đều đưa ra ngoại lệ (Exception) nhưng với kiểu cũ, ngoại lệ sẽ như sau:

Exception in thread "main" java.lang.ArithmeticException: / by zero
at Test.main(Test.java:13)


Còn với cách viết mới, ngoại lệ như sau:

Exception in thread "main" java.lang.ArithmeticException: / by zero
at Test.lambda$1(Test.java:18)
at java.util.stream.Streams$RangeIntSpliterator.forEachRemaining(Streams.java:110)
at java.util.stream.IntPipeline$Head.forEach(IntPipeline.java:557)
at Test.lambda$0(Test.java:17)
at java.util.Arrays$ArrayList.forEach(Arrays.java:3880)
at Test.main(Test.java:16)


Ngoại lệ cho trường hợp viết theo kiểu mới rõ ràng là phức tạp và gây rối hơn so với kiểu viết cũ.
Như vậy các bạn hãy cân nhắc khi sử dụng kiểu vòng lặp nào nhé. Tôi khẳng định rằng phương pháp tiếp cận “hiện đại” nên được sử dụng hết sức thận trọng, tức là chỉ khi bạn thực sự hưởng lợi từ việc lặp lại chức năng (ví dụ: khi xâu chuỗi một tập hợp các hoạt động qua map (), flatMap () và các hoạt động khác)
 
  • Like
Reactions: Joe

Joe

Thành viên VIP
21/1/13
3,022
1,335
113
Stream.forEach () so với một vòng lặp for thông thường là nhiều hơn 10% -20% hiệu năng của CPU
You should explain the problem more profound. Namely: the Stream.forEach() has always to be fetched and loaded (object Stream) before the method forEach() (which internally does nothing than to invoke a for-loop to execute the codes) can be started while the two for-loops are themselves the basic LANGUAGE elements (compiler) that execute the codes directly.
Java:
for (Integer i : list)
for (int j = 0; j < i; j++)
// more efficient:
for (int i = 0, mx = list.size(); i < mx; i++)
    for (int j = 0; j < i; j++)
For those who lack of the basic knowledge about compiler technology the newfangled form Stream.forEach() is attractive because it looks not only sophisticated, but it also makes them looking like the real "IT gurus" =))
And as you already experienced that the last on CPU is heavier than usual (10-20%). Meaning the performance becomes sluggish and it slows down the whole system. Only BAD programmers develop their app with such newfangled ways.
 
Sửa lần cuối: