HƯỚNG DẪN Stream or NOT Stream ?

Joe

Thành viên VIP
21/1/13
2,997
1,320
113
Hi

Shakespeare philosophized "To be or not to be..." as if he knew that his thought would be valid forever. And that is true. Modern Technology covers every aspect in our life and makes our life easier. Easier ? Well, it's the Shakespeare question "To be or NOT to be". Those who make the technology become wiser and wiser (and richer and richer). Those who use the technology their life becomes EASIER and EASIER (and dumber and dumber).

Why? Is it a contradiction? No. Technology is a knife with two sharpest edges. You can cut yourself with it. The more you depend on technology the dumber you will be. I have asked the forum Regular Expression or Not? and showed you how modern technology could cause more problems than making a life easier. If a computer becomes sluggish it is NOT that the computer is always obsoleted, BUT it is usually that the users (or programmers) don't know how to work with it. A car is used to transport. Less car = less jam. More car = more jam. Just look at the streets in Saigon or in Hanoi. Everyday there is somewhere in Hanoi or in Saigon the choked jammed streets for hours. The jam is not caused by the car (modern technology), but the people won't use the car correctly. Same to this phenomenon newbie-programmers jump headless into the newfangled Programming Techniques and cause the jams in their computer and on the (inter)net.

Working with Stream is similar with driving a car. Headless use causes worse effect than help. Regular Expression fools the programmers with less coding lines, but in reality it generates more than the wanna-be-modern programmers could believe. The same happens with Stream. Newbie-Programmers choke the computer with Stream. According to Jamie Zawinski's quote:
Some people, when confronted with a problem, think "I know, I'll use STREAM." Now they have TWO problems.
The TWO problems are:
  1. hard to detect hidden bugs
  2. slow due to overhead of Context Switches
Instead of using Stream wisely some programmers use Stream blindly as if Stream is the matter of success-or-failure in their professional life. And when problems arise they blame either the hardware is obsolete or JAVA is unmodern and then they try to switch the language: C# then PYTHON then KOTLIN and then back to JAVA...Funny, isn't it?

The following examples shows you the same solution. One with Stream coding and the other with "normal" coding.

Given:
Java:
String S = "aaHello bbobby AaHic aadDev aaException aff ggaa aaHeroh aaIsMe aAjNO";
Problem: looking for all words which begin with "aa" , turn them to uppercase and finally put them in column on a JTextArea

Solution with Stream
Java:
      JTextArea ta = new JTextArea();
      java.util.List<String> myList = Arrays.asList(S.split(" "));
      long t0 = System.nanoTime();
      Arrays.asList(myList
          .stream()
          .filter(s -> s.startsWith("aa"))
          .collect(Collectors.joining("\n")))
          .stream()
          .map(String::toUpperCase)
          .forEach(ta::append);
Solution with conventional for-loop
Java:
    JTextArea ta = new JTextArea();
    String[] array = S.split(" ");
    for (int i = 0; i < array.length; ++i) {
      if (array[i].startsWith("aa")) ta.append(array[i].toUpperCase()+"\n");
    }
The conventional codes are clearer, but less sophisticated than the Stream solution. But at the expense of a big JAM. The full codes:
Java:
import java.awt.*;
import java.util.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.stream.Collectors;
//
public class TestStream extends JFrame implements ActionListener {
  public TestStream(String S) {
    this.S = S;
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    but1 = new JButton("Stream");
    but1.addActionListener(this);
    but1.setBackground(Color.green);
    JButton but2 = new JButton("SelfMade");
    but2.addActionListener(this);
    but2.setBackground(Color.red);
    JPanel jp = new JPanel();
    jp.add(but1);
    jp.add(but2);
    ta = new JTextArea();
    ta.setBackground(Color.black);
    ta.setForeground(Color.white);
    JScrollPane js = new JScrollPane(ta);
    js.setAutoscrolls(true);
    add("North", jp);
    add("Center", js);
    setSize(550, 300);
    setVisible(true);
  }
  public void actionPerformed(ActionEvent e) {
    ta.append("\n");
    if (e.getSource() == but1) {
      java.util.List<String> myList = Arrays.asList(S.split(" "));
      long t0 = System.nanoTime();
      Arrays.asList(myList
          .stream()
          .filter(s -> s.startsWith("aa"))
          .collect(Collectors.joining("\n")))
          .stream()
          .map(String::toUpperCase)
          .forEach(ta::append);
      t0 = System.nanoTime() - t0;
      ta.append("\nStream Processing Time:"+((double)t0/1000)+" microSec.");
      return;
    }
    String[] array = S.split(" ");
    long t0 = System.nanoTime();
    for (int i = 0; i < array.length; ++i) {
      if (array[i].startsWith("aa")) ta.append(array[i].toUpperCase()+"\n");
    }
    t0 = System.nanoTime() - t0;
    ta.append("\nSelfMade Processing Time:"+((double)t0/1000)+" microSec.");
  }
  private String S;
  private JTextArea ta;
  private String fName;
  private JButton but1;
  public static void main(String... a) throws Exception {
    new TestStream(a.length == 0?
             "aaHello bbobby AaHic aadDev aaException aff ggaa aaHeroh aaIsMe aAjNO":a[0]);
  }
}
stream.png
25.7 milliSeconds versus 1.4 milliSeconds. A very big JAM of ~24 times.
And the bug?
The Newline in the last line AAISME is missed. And it's hard, very hard to remote this bug.

So. The question is
WHY JAVA GIVES A LOT OF EFFORD TO INCLUDE SUCH THE NEWFANGLED FEATURES?
The answer is: When such a Stream loop is started it always takes a lot of time. BUT: when the codes are already in Cache (and won't be moved out by Garbage-Collector) the Stream works
perfectly fast. Especially if the task can be executed parallelly. You could click repeatedly both buttons you will see the wonder of Stream. In essence: Stream is ONLY useful for the case that the solution is REUSED often, very often...Not for once and forget.
 
Sửa lần cuối:

ngtheanh.dev

New Member
25/12/20
6
1
3
Hà Nội
Arrays.asList(myList .stream() .filter(s -> s.startsWith("aa")) .collect(Collectors.joining("\n"))) .stream() .map(String::toUpperCase) .forEach(ta::append);
Tôi có thử viết lại như này và thấy kết quả của stream đã tốt hơn

Java:
Stream.of(myList
        .stream()
        .filter(s -> s.startsWith("aa"))
        .collect(Collectors.joining("\n")))
        .map(String::toUpperCase)
        .forEach(ta::append);
 
  • Like
Reactions: Joe

ngtheanh.dev

New Member
25/12/20
6
1
3
Hà Nội
IDE usually caches the standard API codes (stream, string, etc.) to reduce the (Class) loading time.
Secondly, JVM also caches the API codes when they are repeatedly reused
Okay tôi sẽ thử chạy chương trình bằng command và so sánh kết quả được không? Hi vọng tôi sẽ tìm được điều gì đó mới mẻ.
Theo tôi nghĩ thì vấn đề ở đây là cách chúng ta đang sử dụng Stream như thế nào cho đúng hơn là so sánh công nghệ. Nếu không hy vọng bạn có thể giải thích tại sao nó chậm hơn (theo tôi thấy thì do sử dụng quá nhiều function của Stream không hợp lý cũng là 1 lý do nhưng có thể khắc phục)
 

Joe

Thành viên VIP
21/1/13
2,997
1,320
113
So. The question is WHY JAVA GIVES A LOT OF EFFORD TO INCLUDE SUCH THE NEWFANGLED FEATURES?
The answer is: When such a Stream loop is started it always takes a lot of time. BUT: when the codes are already in Cache (and won't be moved out by Garbage-Collector) the Stream works
perfectly fast. Especially if the task can be executed parallelly. You could click repeatedly both buttons you will see the wonder of Stream. In essence: Stream is ONLY useful for the case that the solution is REUSED often, very often...Not for once and forget.
Nếu không hy vọng bạn có thể giải thích tại sao nó chậm hơn
You could confer THIS. It's, of course, in English and I hope your English is efficient enough to understand the article.
 
Sửa lần cuối:

Joe

Thành viên VIP
21/1/13
2,997
1,320
113
...and what did guru Jamie Zawinski talk about the newfangled programming ? He said:
Why should someone have to retrain themselves to use a new application that does the same basic thing as the old application, just because something as trivial as the operating system changed out from under them?
The old way with a loop works in most cases faster and easier to detect hidden bugs.