1. 程式人生 > >JAVA8給我帶了什麽——流(入門)

JAVA8給我帶了什麽——流(入門)

.so 如何 code com 一個數 眼睛 表現 rsquo urn

JAVA8有一個新功能——流。筆者簡單的看一下流。然後默默的閉上眼睛。感嘆一聲:這不是.NET裏面的Linq嗎?如果你們當中有誰做過.NET程序員的話,對於流的學習其實幫助是很大的。但是要明白你現在是在學JAVA的流。雖然他們的概念是有一點像。可是這也只是對你在理解流上面有一定的幫助。因為JAVA實現的方式卻完成不一樣子(不入流程序員的個人理解)。

好吧。那麽流是什麽呢?如果用書裏面的方式解釋的話,筆者可能也看不懂。做過開發的人員一般都會知道一些SQL語句吧,SELECT語句這個功能。相信大家一定都熟悉吧——SELECT是對數據庫的數據進行操作。同樣子JAVA也有數據啊。比如集合、數組。那麽為什麽JAVA不可能實現一套代碼式的數據操作。如果這樣子不知道大家會不會明白呢?(當然這不是官方,是不入流的程序員這樣了理解的)

SQL語句裏面有什麽——SELECT、FORM、WHERE、ORDER BY、GROUP BY。這些都是對數據庫裏面數據操作的常規動作。JAVA8的流呢? 即然是流。那麽說明必須把對應的數據變成一個流才行。關鍵方法stream()就是這個作用。 舉例子來說明吧。筆者有一組字符數組,筆者相要查找出有含有 r 的字符。

 1 package com.aomi;
 2 
 3 import java.util.Arrays;
 4 import java.util.List;
 5 
 6 public class Main {
 7 
 8     public
static void main(String[] args) { 9 // TODO Auto-generated method stub 10 11 List<String> datas = Arrays.asList("red", "green", "bule"); 12 13 datas 14 .stream() 15 .filter(s -> s.contains("r")) 16 .forEach(s -> System.out.println(s));
17 } 18 19 }

運行結果:

技術分享圖片

讓我們想想如果是以前的話,要什麽樣子去實現呢?

 1 package com.aomi;
 2 
 3 import java.util.ArrayList;
 4 import java.util.Arrays;
 5 import java.util.List;
 6 
 7 public class Main {
 8 
 9     public static void main(String[] args) {
10         // TODO Auto-generated method stub
11 
12         List<String> datas = Arrays.asList("red", "green", "bule");
13 
14 //        datas
15 //        .stream()
16 //        .filter(s -> s.contains("r"))
17 //        .forEach(s -> System.out.println(s));
18 
19         List<String> vDatas = new ArrayList<>();
20 
21         for (String str : datas) {
22             if (str.contains("r")) {
23                 vDatas.add(str);
24             }
25         }
26 
27         for (String str : vDatas) {
28             System.out.println(str);
29         }
30 
31     }
32 
33 }

相對以前來講很直觀表現代碼的意思。同時代碼量又小很多。

  • filter:用於過濾數據的,從下面的代碼就可以明白,返回一個boolean型類的結果。
Stream<T> filter(Predicate<? super T> predicate);
  • forEach:循環遍歷回來的結果集合。代碼看完就知道什麽樣子用了。
 void forEach(Consumer<? super T> action);

JAVA的代很多都是很人性化的,所以只要從名字就可以明白他大概的功能了。

好了,筆者突然有一個想法——想要把時面的‘r’字符變成‘o’字符。

 1 package com.aomi;
 2 
 3 import java.util.Arrays;
 4 import java.util.List;
 5 
 6 public class Main {
 7 
 8     public static void main(String[] args) {
 9         // TODO Auto-generated method stub
10 
11         List<String> datas = Arrays.asList("red", "green", "bule");
12 
13         datas.stream()
14         .map(s -> s.replace(‘r‘, ‘o‘))
15         .forEach(s -> System.out.println(s));
16 
17     }
18 
19 }

筆者去掉了filter方法,用了map。運行結果:

技術分享圖片

  • map:相當於SQL中的 SELECT關鍵字有一點像。用於把結果變成你希望的樣子。看一下代碼
 <R> Stream<R> map(Function<? super T, ? extends R> mapper);

是一個function的函數式接口。函數描述符:T -> R。
顯示這樣子的例子有一點簡單。在實際的開發過程中我們往往都是一大波數據對象。這樣子筆者定義一個學生類。

package com.aomi;

public class Student {
    private String name;
    private int Sex;
    private String phone;
    private int score;
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getSex() {
        return Sex;
    }
    public void setSex(int sex) {
        Sex = sex;
    }
    public String getPhone() {
        return phone;
    }
    public void setPhone(String phone) {
        this.phone = phone;
    }
    public int getScore() {
        return score;
    }
    public void setScore(int score) {
        this.score = score;
    }
    
    
}

在來寫一個數據源吧。

 1 package com.aomi;
 2 
 3 import java.util.ArrayList;
 4 import java.util.Arrays;
 5 import java.util.List;
 6 
 7 public class Main {
 8 
 9     public static List<Student> getSources()
10     {
11         List<Student> students =new ArrayList<>();
12         
13         Student stu1 = new Student();
14         
15         stu1.setName("lucy");
16         stu1.setSex(0);
17         stu1.setPhone("13700227892");
18         stu1.setScore(9);
19         
20         Student stu2 = new Student();
21         stu2.setName("lin");
22         stu2.setSex(1);
23         stu2.setPhone("15700227122");
24         stu2.setScore(9);
25         
26         Student stu3 = new Student();
27         stu3.setName("lili");
28         stu3.setSex(0);
29         stu3.setPhone("18500227892");
30         stu3.setScore(8);
31         
32         Student stu4 = new Student();
33         
34         stu4.setName("dark");
35         stu4.setSex(1);
36         stu4.setPhone("16700555892");
37         stu4.setScore(6);
38         
39         
40         students.add(stu1);
41         students.add(stu2);
42         students.add(stu3);
43         students.add(stu4);
44         
45         return students;
46     }
47 
48 }

筆者定義了四個學生。這樣子時候筆者想看看學分(Score)大於6同學的名字有哪一些。從上面代碼我們可以看到除了第四個同學drak之後,其他都是合格的。 讓我們看一下代碼

 1 package com.aomi;
 2 
 3 import java.util.ArrayList;
 4 import java.util.List;
 5 import static java.util.stream.Collectors.toList;
 6 
 7 public class Main {
 8 
 9     public static void main(String[] args) {
10         // TODO Auto-generated method stub
11 
12         List<Student> stus = getSources();
13 
14         List<String> names = stus.stream()
15                 .filter(stu -> stu.getScore() > 6)
16                 .map(stu -> stu.getName())
17                 .collect(toList());
18 
19         for (String name : names) {
20             System.out.println(name);
21         }
22 
23     }
24 
25     public static List<Student> getSources() {
26         List<Student> students = new ArrayList<>();
27 
28         Student stu1 = new Student();
29 
30         stu1.setName("lucy");
31         stu1.setSex(0);
32         stu1.setPhone("13700227892");
33         stu1.setScore(9);
34 
35         Student stu2 = new Student();
36         stu2.setName("lin");
37         stu2.setSex(1);
38         stu2.setPhone("15700227122");
39         stu2.setScore(9);
40 
41         Student stu3 = new Student();
42         stu3.setName("lili");
43         stu3.setSex(0);
44         stu3.setPhone("18500227892");
45         stu3.setScore(8);
46 
47         Student stu4 = new Student();
48 
49         stu4.setName("dark");
50         stu4.setSex(1);
51         stu4.setPhone("16700555892");
52         stu4.setScore(6);
53 
54         students.add(stu1);
55         students.add(stu2);
56         students.add(stu3);
57         students.add(stu4);
58 
59         return students;
60     }
61 
62 }

運行結果:

技術分享圖片

當我們看到這個例子的時候,我們就可以確定map是做什麽。就是用於最後確定返回數據類型。在這個代碼中。筆者又用到了一個叫collect的方法。

  • collect:用於收集數據的功能。即是把相關的數據匯總成為另一種數據。

筆者傳入是toList()方法。把最後數據變成一個集合。這個方法是Collectors類的一個靜態方法。當然Collectors類裏面有很多靜態方法。如果你們去看一下他的代碼。你就會發現他的方法名字好像都是在對數據操作的樣子。沒有錯。以後我們開發過程都會用到Collectors類的方法集。
記得引用下面代碼

import static java.util.stream.Collectors.toList;

從上面的幾個例子來看。讓筆者感覺如下

  • stream相關於SQL裏面的FROM
  • filter相當於SQL裏面的WHERE.
  • map相當於SQL裏面的SELECT

那麽其他呢?比如 order by或 group by 。讓我們接著看吧。

現在筆者想在按學分(Score)高到低排序並且只顯示學生名和學分呢?

package com.aomi;

import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.toList;

import java.util.ArrayList;
import java.util.List;

public class SMain {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        List<Student> stus = getSources();

        List<String> names = stus.stream()
                .sorted(comparing(Student::getScore).reversed())
                .map(stu -> "學名:"+stu.getName()+"  學分:"+stu.getScore())
                .collect(toList());

        
        for (String name : names) {
            System.out.println(name);
        }

    }

    public static List<Student> getSources() {
        List<Student> students = new ArrayList<>();

        Student stu1 = new Student();

        stu1.setName("lucy");
        stu1.setSex(0);
        stu1.setPhone("13700227892");
        stu1.setScore(9);

        Student stu2 = new Student();
        stu2.setName("lin");
        stu2.setSex(1);
        stu2.setPhone("15700227122");
        stu2.setScore(9);

        Student stu3 = new Student();
        stu3.setName("lili");
        stu3.setSex(0);
        stu3.setPhone("18500227892");
        stu3.setScore(8);

        Student stu4 = new Student();

        stu4.setName("dark");
        stu4.setSex(1);
        stu4.setPhone("16700555892");
        stu4.setScore(6);

        students.add(stu1);
        students.add(stu2);
        students.add(stu3);
        students.add(stu4);

        return students;
    }
}

運行結果:

技術分享圖片

關於上面sorted的用法。筆者上面已經講過了。
現在筆者想看看男女各位的學習情況。又要如何。來分個組吧。

 1 package com.aomi;
 2 
 3 import static java.util.stream.Collectors.groupingBy;
 4 
 5 import java.util.ArrayList;
 6 import java.util.List;
 7 
 8 public class SMain {
 9 
10     public static void main(String[] args) {
11         // TODO Auto-generated method stub
12 
13         List<Student> stus = getSources();
14 
15         stus.stream()
16         .collect(groupingBy(ss -> ss.getSex())).
17         forEach((Integer sex, List<Student> students) -> {
18             System.out.println("sex:" + sex);
19 
20             for (Student student : students) {
21                 System.out.println("name:" + student.getName() + "  score:" + student.getScore());
22             }
23         });
24 
25     }
26 
27 //去掉學生源的方法。太多了影響查看
28 }

結果:

技術分享圖片

即然都分組了。那就筆者在做一個業務。查看男女個組的人數。

package com.aomi;

import static java.util.stream.Collectors.groupingBy;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class SMain {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        List<Student> stus = getSources();

        stus.stream().collect(groupingBy(ss -> {
            if (ss.getSex() == 0)
                return "女";
            else
                return "男";
        }, Collectors.counting()))
        .forEach((String sex, Long count) -> {
            System.out.println("sex:" + sex + "  count:" + count);

        });

    }
......
.....//去掉數據源
.....

}

運行結果:

技術分享圖片

在來一個分組之後,男女個組的總分。

package com.aomi;

import static java.util.stream.Collectors.groupingBy;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class SMain {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        List<Student> stus = getSources();

        stus.stream().collect(groupingBy(ss -> {
            if (ss.getSex() == 0)
                return "女";
            else
                return "男";
        }, Collectors.summingLong(t -> t.getScore())))
        .forEach((String sex, Long sum) -> {
            System.out.println("sex:" + sex + "  count:" + sum);

        });

    }

    。。。。。
}

運行結果:

技術分享圖片

通過這倆個例子,我們就可以明白一個道理。groupingBy的第二個參數,是一個任何型類的收集器。也就是說分組之後,你可以在進行對分組之後的結果進處理。

好了。你們有沒有感覺跟SQL語句的功能很像呢?如下

  • stream相關於SQL裏面的FROM
  • filter相當於SQL裏面的WHERE.
  • map相當於SQL裏面的SELECT
  • sorted相當於SQL裏面的Order BY
  • Collectors.groupingBy相當於SQL裏面的GROUP BY
  • Collectors.summingLong相當於SQL裏面的SUM函數。只不過他又加了一步結果轉為Long類型
  • Collectors.counting相當於SQL裏面的COUNT函數

理解了上面代碼的基礎用法的概念之後,我們接下要一步步去看看JAVA8流的思想。

JAVA8給我帶了什麽——流(入門)