Stream流

Stream流

JDK1.8的新特性之一
它跟我們所學的 IO 流完全沒有什麼關係
Stream 它是Lambda的衍生物。

通過一個例子來看:

需求:我們先找出性張的,再性張的中找出三個字的,然後遍歷集合

public class Test {
    public static void main(String[] args) {

        ArrayList<String> list = new ArrayList();
        //給集合添加元素
        Collections.addAll(list,"張無忌","張三","王二","張三明","馬六");

        //先找姓張的
        ArrayList<String> zhangList = new ArrayList<>();
        for (String s : list) {
            if(s.startsWith("張")){
                zhangList.add(s);
            }
        }

        //在找三個字的
        ArrayList<String> threeList = new ArrayList<>();
        for (String s : zhangList){
            if (s.length() == 3){
                threeList.add(s);
            }
        }

        //遍歷集合
        for (String s : threeList){
            System.out.println(s);
        }
    }
}


結果:
	張無忌
	張三明

這樣寫顯然我們要進行三次遍歷,不但代碼多,而且還很浪費功夫,還容易寫錯。

JDK1.8的新特性中就指明瞭流的思想,下面讓我們看看使用Stream之後的代碼吧。

		ArrayList<String> list = new ArrayList();
        //給集合添加元素
        Collections.addAll(list,"張無忌","張三","王二","張三明","馬六");

		//使用Stream流
		list.stream().filter(s->s.startsWith("張"))
				.filter(s->s.length() == 3).forEach(s-> System.out.println(s));


結果:
	張無忌
	張三明

可以看到兩個例子的結果完全一致,流的使用簡化了很多的代碼。
我相信正在讀文章的你也很好奇,那麼久讓我們先看一下流是怎樣做到這一點的吧。

下面的代碼片段是流的傳統寫法:

我們可以發現,stream流的方法中都有一個參數,而且該參數都是一個接口並且該接口中只有一個抽象方法,我相信看過我上篇Lambda表達式的小夥伴都應該知道,這是符合Lambda表達式的使用條件的,那麼就讓我們來簡化一下吧。

		//流的原始方式寫法
		list.stream().filter(new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.startsWith("張");
            }
        }).filter(new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.length() == 3;
            }
        }).forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });

		
		//流與Lambda表達式結合使用,簡化後的代碼如下:
		list.stream().filter(s->s.startsWith("張"))
				.filter(s->s.length() == 3).forEach(s-> System.out.println(s));

從這裏可以看到,流的引入給我們帶來了很大的便利,下面就讓我們充分的認識一下它吧!

獲取流的方式

java.util.stream.Stream 是Java 8新加入的最常用的流接口。(這並不是一個函數式接口。)
獲取一個流非常簡單,有以下幾種常用的方式:

Collection 集合及其子類都可以通過 .stream() 獲取流。
Stream接口的靜態方法 .of 可以獲取數組對應的流。

		//通過單列集合獲取流
		ArrayList<String> list = new ArrayList<>();
        Stream<String> stream = list.stream();

		//通過Stream接口的靜態方法也可以獲取流
		String[] arr = {"a","b","c"};
        Stream<String> Stream1 = Stream.of(arr);

		//map方式獲取流	基本用不到
        HashMap<String, String> map = new HashMap<>();
        Stream<String> s1 = map.keySet().stream();
        Stream<String> s2 = map.values().stream();
        Stream<Map.Entry<String, String>> s3 = map.entrySet().stream();

常用方法

流模型的操作很豐富,這裏介紹一些常用的API。這些方法可以被分成兩種:

  • 終結方法:返回值類型不再是 Stream 接口自身類型的方法,因此不再支持類似 StringBuilder 那樣鏈式調用。本次介紹的終結方法包括 count 和 forEach 方法。
  • 非終結方法:返回值類型仍然是 Stream 接口自身類型的方法,因此支持鏈式調用。(除了終結方法外,其餘方法均爲非終結方法。)

方法介紹:
終結方法:不支持鏈式調用

  • count : 統計個數(終結方法,不支持鏈式調用)
  • forEach :逐一處理,遍歷的意思(終結方法,不支持鏈式調用)

其他方法(非終結方法):除了終結方法,其他方法都支持鏈式調用

  • filter : 過濾
  • limit : 取前幾個
  • skip : 跳過前幾個
  • map : 映射
  • static concat : 組合,拼接(只能通過Stream接口調用)
  • static of : 獲取數組對應的流(只能通過Stream接口調用)
  • collect(Collectors接口) : 把流轉換成指定的集合
  • toArray : 轉化成數組

filter與forEach使用:

public class Work5 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();

        Collections.addAll(list,"王佳樂","張三丰","王思聰","張飛","劉曉敏","張靚穎","王敏");

		//獲取流
        Stream<String> stream = list.stream();
        
         //注意:因爲已經調用了終結方法,後面就不能使用這個流進行操作了,因爲該流已經不存在了,要想操作還需要再次創建新的流
        stream.filter(s->s.startsWith("張")).forEach(s-> System.out.println(s));
        
        //流對象已經消失,該語句會報錯的
        stream.filter(s -> s.startsWith("王")).forEach(s-> System.out.println(s));
     }
}

結果:
注意:因爲已經調用了終結方法,後面就不能使用這個流進行操作了,因爲該流已經不存在了,要想操作還需要再次創建新的流
在這裏插入圖片描述

count使用:

public class Test1 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("張無忌");
        list.add("張三");

        //count是終結方法,調用後此流就不能在使用,不然會報異常,要想使用需要新創建一個流
        long count = list.stream().count();

        System.out.println(count);

    }
}

結果:
	2

limit使用:

public class Work5 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();

        //給集合添加元素
        Collections.addAll(list,"王佳樂","張三丰","王思聰","張飛","劉曉敏","張靚穎","王敏");

        //獲取流
        Stream<String> stream = list.stream();

        //調用方法 使用limit獲取集合前三個並打印
        stream.limit(3).forEach(s-> System.out.println(s));
    }
}


結果:
	王佳樂
	張三丰
	王思聰

skip使用:

public class Work5 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();

        //給集合添加元素
        Collections.addAll(list,"王佳樂","張三丰","王思聰","張飛","劉曉敏","張靚穎","王敏");

        //獲取流
        Stream<String> stream = list.stream();

        //調用方法 使用skip跳過集合中前三個元素並打印
        stream.skip(3).forEach(s-> System.out.println(s));
    }
}

結果:
	張飛
	劉曉敏
	張靚穎
	王敏

map使用

//Person類
public class Person {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }
}

//測試類
public class Work6 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();

        Collections.addAll(list,"王佳樂","張三丰","王思聰","張飛");

        //把集合中的元素映射到Person對象中並打印
        list.stream().map(Person::new).forEach(s-> System.out.println(s));

    }
}

結果:
	Person{name='王佳樂'}
	Person{name='張三丰'}
	Person{name='王思聰'}
	Person{name='張飛'}

collect(Collectors接口)使用

Collectors接口下的方法:
toList 、 toSet 等等

//Person類
public class Person {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }
}

//測試類
public class Work6 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();

        Collections.addAll(list,"王佳樂","張三丰","王思聰","張飛");

        //把集合元素映射到Person對象中,並且把流轉換成list集合
        List<Person> collect = list.stream().map(Person::new).collect(Collectors.toList());

        //打印list集合
        System.out.println(collect);
    }
}

結果:
	[Person{name='王佳樂'}, Person{name='張三丰'}, Person{name='王思聰'}, Person{name='張飛'}]


toArray使用:

public class Test1 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("張無忌");
        list.add("張三");
        list.add("王二");
        list.add("馬六");
        list.add("馬騰飛");

        //獲取流,找出姓張的,然後把流轉換成數組
        Object[] arr = list.stream().filter(s -> s.startsWith("張")).toArray();

        System.out.println(Arrays.toString(arr));
    }
}

結果:
	[張無忌, 張三]

concat使用:

注意:concat是靜態方法,要使用Stream接口來調用

public class Test1 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("張無忌");
        list.add("張三");
        
        ArrayList<String> list1 = new ArrayList<>();
        list1.add("王二");
        list1.add("馬六");
        list1.add("馬騰飛");

        //獲取兩個集合的流對象
        Stream<String> stream = list.stream();
        Stream<String> stream1 = list1.stream();

        //調用 靜態的concat方法
        Stream<String> concat = Stream.concat(stream, stream1);
        
        //打印 concat流
        concat.forEach(s-> System.out.println(s));
        
    }
}


結果:
	張無忌
	張三
	王二
	馬六
	馬騰飛

of使用:

注意:of是靜態方法,要使用Stream接口來調用

		//通過Stream接口的靜態方法也可以獲取流
		String[] arr = {"a","b","c"};
        Stream<String> stream = Stream.of(arr);

如果能夠幫到你,就留下一個贊吧!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章