程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> JAVA 8 Streams,javastreams

JAVA 8 Streams,javastreams

編輯:JAVA綜合教程

JAVA 8 Streams,javastreams


什麼是Stream

首先要說的是,不要被它的名稱騙了,這裡的Stream跟JAVA I/O中的InputStream和OutputStream是兩個不同的概念。Java 8中的Stream其實是函數式編程裡Monad的概念,關於Monad,感覺還是比較抽象,不好理解,可以參考這篇文章,個人覺得還是比較好看懂的,簡單說,Monad就是一種設計模式,表示將一個運算過程,通過函數拆解成互相連接的多個步驟,有點鏈式操作的感覺。

如下,是一個Stream的例子

import java.util.Arrays;
import java.util.List;

public class Snippet
{
    public static void main(String[] args)
    {
        List<String> myList = Arrays.asList("a1", "a2", "b1", "c2", "c1");

        myList
            .stream()
            .filter(s -> s.startsWith("c"))       //過濾以c字母開頭
            .map(String::toUpperCase)        //字符變成大寫
            .sorted()                                     //排序
            .forEach(System.out::println);    //打印輸出
    }
}

使用Stream的好處

  • 對JAVA集合(Collection)對象功能的增強,方便對集合進行各類操作(過濾、求最大值、最小值、統計等);
  • 更加高效,提供串行和並行兩種模式,並行模式利用了Java中的fork/join框架技術,能充分利用多核處理器,提高程序並發性;

Stream的特征

  • 不是一個數據結構
  • 為lambda表達式設計
  • 不支持索引訪問
  • 很方便的作為數組或集合輸出
  • 支持惰性訪問
  • 並行計算

如何得到Stream對象

從 Collection 和數組

  • Collection.stream()
  • Collection.parallelStream()
  • Arrays.stream(T array) or Stream.of()

從 BufferedReader

  • java.io.BufferedReader.lines()

靜態工廠

  • java.util.stream.IntStream.range()
  • java.nio.file.Files.walk()

自己創建

  • java.util.Spliterator

其它

  • Random.ints()
  • BitSet.stream()
  • Pattern.splitAsStream(java.lang.CharSequence)
  • JarFile.stream()
  • 。。。

Stream的操作類型

Stream有兩種類型的操作:Intermediate操作和Terminal操作。

Intermediate(中間操作)

Stream可以進行多次的Intermediate操作,如前面開頭的那個例子,其中filter、map、sorted都是Intermediate操作,注意該操作是惰性化的,當調用到該方法的時候,並沒有真正開始Stream的遍歷。

Terminal(結束操作)

一個Stream只有一個Terminal操作,如前面開頭的那個例子,其中forEach就是Terminal操作,Terminal操作是Stream的最後一個操作,這時候才會開始Stream的遍歷。

Stream使用示例

 Stream的創建

使用Stream.of

import java.util.stream.Stream;

public class StreamBuilders
{
    public static void main(String[] args)
    {
        Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9);
        stream.forEach(p -> System.out.println(p));
    }
}

使用Arrays.stream

import java.util.Arrays;
import java.util.stream.Stream;

public class StreamBuilders
{
    public static void main(String[] args)
    {
        Stream<Integer> stream = Arrays.stream(new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9});
        stream.forEach(p -> System.out.println(p));
    }
}

使用Collection.stream() or Collection.parallelStream()

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class StreamBuilders
{
    public static void main(String[] args)
    {
        List<Integer> list = 
            new ArrayList<Integer>(Arrays.asList(new Integer[]{ 1, 2, 3, 4, 5, 6, 7, 8, 9 }));
        
        Stream<Integer> stream = list.stream();    //or list.parallelStream();
        stream.forEach(p -> System.out.println(p));
    }
}

使用IntStream.range

import java.util.stream.IntStream;

public class StreamBuilders
{
    public static void main(String[] args)
    {
        IntStream stream = IntStream.range(1, 9);
        stream.forEach(p -> System.out.println(p));
    }
}

使用Random.ints()

import java.util.Random;
import java.util.stream.IntStream;

public class StreamBuilders
{
    public static void main(String[] args)
    {
        IntStream stream = new Random().ints(1, 10);
        stream.forEach(p -> System.out.println(p));
    }
}

使用Stream.generate()

import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;

public class StreamBuilders
{
    static int i = 0;
    public static void main(String[] args)
    {
        Stream<Integer> stream = Stream.generate(() -> {
            try
            {
                TimeUnit.SECONDS.sleep(1);
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
            return i++;
        });
        stream.forEach(p -> System.out.println(p));
    }
}

其它還有很多,這裡暫不一一列出。

Stream類型轉集合/數組類型

使用stream.collect(Collectors.toList())

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

public class StreamBuilders
{
    public static void main(String[] args)
    {
        List<Integer> list = 
            new ArrayList<Integer>(Arrays.asList(new Integer[]{ 1, 2, 3, 4, 5, 6, 7, 8, 9 }));
        
        Stream<Integer> stream = list.stream();
        
        List<Integer> evenNumbersList = stream.filter(i -> i % 2 == 0).collect(Collectors.toList());
        
        System.out.print(evenNumbersList);
    }
}

使用stream.toArray(EntryType[]::new)

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class StreamBuilders
{
    public static void main(String[] args)
    {
        List<Integer> list = 
            new ArrayList<Integer>(Arrays.asList(new Integer[]{ 1, 2, 3, 4, 5, 6, 7, 8, 9 }));
        
        Stream<Integer> stream = list.stream();
        
        Integer[] evenNumbersArr = stream.filter(i -> i % 2 == 0).toArray(Integer[]::new);
        
        System.out.print(Arrays.asList(evenNumbersArr));
    }
}

其它轉為set,map的類似,不一一列出。

Stream核心操作方法

 Intermediate(中間操作),這裡只列出常見的幾個

filter方法,過濾元素

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class StreamBuilders
{
    public static void main(String[] args)
    {
        List<String> list = new ArrayList<String>(Arrays.asList(new String[]{ 
                    "Amitabh", "Shekhar", "Aman", "Rahul", 
                    "Shahrukh", "Salman", "Yana", "Lokesh"}));
        
        Stream<String> stream = list.stream();
        
        stream.filter((s) -> s.startsWith("A")).forEach(System.out::println);
    }
}

map方法,修改元素

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class StreamBuilders
{
    public static void main(String[] args)
    {
        List<String> list = new ArrayList<String>(Arrays.asList(new String[]{ 
                    "Amitabh", "Shekhar", "Aman", "Rahul", 
                    "Shahrukh", "Salman", "Yana", "Lokesh"}));
        
        Stream<String> stream = list.stream();
        
        stream.filter((s) -> s.startsWith("A")).map(String::toUpperCase).forEach(System.out::println);
    }
}

sorted方法,排序,可以傳入自定義排序接口Comparator,

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class StreamBuilders
{
    public static void main(String[] args)
    {
        List<String> list = new ArrayList<String>(Arrays.asList(new String[]{ 
                    "Amitabh", "Shekhar", "Aman", "Rahul", 
                    "Shahrukh", "Salman", "Yana", "Lokesh"}));
        
        Stream<String> stream = list.stream();
        
        stream.sorted().map(String::toUpperCase).forEach(System.out::println);
    }
}

Terminal(結束操作),這裡只列出常見的幾個

這裡的例與前面的類似,就不寫出全部代碼了,列出重要部分。

forEach方法,迭代元素,並執行相關操作

       stream.sorted().map(String::toUpperCase).forEach(System.out::println);

collect方法,從Stream中得到集合

        List<String> memNamesInUppercase = stream.sorted().map(String::toUpperCase).collect(Collectors.toList());

        System.out.print(memNamesInUppercase);

Match方法,匹配判斷Stream中的元素是否符合指定規則

        boolean matchedResult = list.stream().anyMatch((s) -> s.startsWith("A"));

        System.out.println(matchedResult);

        matchedResult = list.stream().allMatch((s) -> s.startsWith("A"));

        System.out.println(matchedResult);

        matchedResult = list.stream().noneMatch((s) -> s.startsWith("A"));

        System.out.println(matchedResult);

count方法,計數

        long totalMatched = list.stream().filter((s) -> s.startsWith("A")).count();

        System.out.println(totalMatched);

reduce方法,元素組合操作,常用於字符串拼接、數值的 sum、min、max、average

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

public class StreamBuilders
{
    public static void main(String[] args)
    {
        List<String> list = new ArrayList<String>(Arrays.asList(new String[]{ 
                    "Amitabh", "Shekhar", "Aman", "Rahul", 
                    "Shahrukh", "Salman", "Yana", "Lokesh"}));
        
        Optional<String> reduced = list.stream().reduce((s1, s2) -> s1 + "#" + s2);

        reduced.ifPresent(System.out::println);
        
        //打印結果:Amitabh#Shekhar#Aman#Rahul#Shahrukh#Salman#Yana#Lokesh
    }
}

Stream短路操作

所謂的短路操作。指的是如果符合要求的話,就不繼續執行接下來的操作,類似於&&和||操作,

在Stream中,類似的有anyMatch()和findFirst()方法,

anyMatch(),返回布爾值,只要找到一個匹配的元素,就停止接下來的元素遍歷;

        boolean matched = list.stream().anyMatch((s) -> s.startsWith("A"));

        System.out.println(matched);

        // Output: true

findFirst(),返回元素,同樣,只返回第一個元素,不會全部遍歷;

        String firstMatchedName = list.stream().filter((s) -> s.startsWith("L")).findFirst().get();

        System.out.println(firstMatchedName);

        // Output: Lokesh

並發parallelStream

Java 7引入了Fork/Join並行計算框架,能讓我們以並行方式來拆分任務和加速處理過程。通常編寫並行代碼很難而且容易出錯, 但使用 Stream API 無需編寫一行多線程的代碼,就可以很方便地寫出高性能的並發程序。

如下示例:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class StreamBuilders
{
    public static void main(String[] args)
    {
        List<Integer> list =
            new ArrayList<Integer>(Arrays.asList(new Integer[]{ 1, 2, 3, 4, 5, 6, 7, 8, 9 }));
        
        // Here creating a parallel stream
        Stream<Integer> stream = list.parallelStream();
        Integer[] evenNumbersArr = stream.filter(i -> i % 2 == 0).toArray(Integer[]::new);
        System.out.print(Arrays.asList(evenNumbersArr));
    }
}

使用Stream與不用Stream對比

下面給出一個使用Stream與不使用Stream示例,用於統計字符長度為3的字符串個數。

import java.util.Arrays;
import java.util.List;

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

      List<String> strings = Arrays.asList("abc", "111", "bc", "efg", "12584","", "1254");

      //使用Java 7, 統計字符長度為3的字符串個數
      long count = 0;
      for(String string: strings){
        
         if(string.length() == 3){
            count++;
         }
      }
      System.out.println("using java7:Strings of length 3: " + count);
        
     
      //使用Java 8的stream, 統計字符長度為3的字符串個數
      count = strings.stream().filter(string -> string.length() == 3).count();
      System.out.println("using java8:Strings of length 3: " + count);
        
   }
}

參考資料

http://www.ibm.com/developerworks/cn/java/j-lo-java8streamapi/

http://winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples/

https://www.tutorialspoint.com/java8/java8_streams.htm

 http://howtodoinjava.com/core-java/collections/java-8-tutorial-streams-by-examples/

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved