1. 程式人生 > >Java 8之數值流使用和構建流的方式

Java 8之數值流使用和構建流的方式

數值流:

數值流,顧名思義就是專門用來操作基礎資料型別的流,那它的作用是什麼呢?先看下面的程式碼。這段程式碼是獲取集合每個物件的num欄位的值,然後求所和。得出的結果是15,看上去沒有問題,但是要注意的是流在進行求和操作的時候從物件中取出來的是基本型別,會進行裝箱操作變成Integer型別再進行求和,效能會有所下降,而數值流就是專門對基本型別資料進行操作的。

public class DataStream {
    public static void main(String[] args){
        List<Num> list = new ArrayList<Num>();
        Num num1 = new Num(1);
        Num num2 = new Num(2);
        Num num3 = new Num(3);
        Num num4 = new Num(4);
        Num num5 = new Num(5);
        list.add(num1);
        list.add(num2);
        list.add(num3);
        list.add(num4);
        list.add(num5);
        System.out.println(list.stream().map(Num::getNum).reduce(Integer::sum));
    }
}

class Num{
    private int num;

    public Num(int num) {
        this.num = num;
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }
}

數值流的使用:

1.想要使用數值流其實很簡單,只需要呼叫Stream.mapToInt()方法就可以獲得一個數值流了,我們會發現數值流有更多的封裝好的計算方法,更加方便我們對數值的計算。

System.out.println(list.stream().mapToInt(Num::getNum).count());
System.out.println(list.stream().mapToInt(Num::getNum).sum());
System.out.println(list.stream().mapToInt(Num::getNum).max());
System.out.println(list.stream().mapToInt(Num::getNum).min());
System.out.println(list.stream().mapToInt(Num::getNum).average());

執行結果:

5
15
OptionalInt[5]
OptionalInt[1]
OptionalDouble[3.0]

2.需要注意的是maxminaverage方法如果在流為空的時候獲取不到值會返回空的Optional物件,而countsum方法則是返回0。

執行結果:

0
0
OptionalInt.empty
OptionalInt.empty
OptionalDouble.empty

3.有時候我們可能會想將數值流轉換回原來的流,我們可以呼叫boxed()方法。

public static void changeStream(){
    int[] arr = new int[]{1,2,3,4,5};
    IntStream intStream =  Arrays.stream(arr);
    Stream<Integer> stream = intStream.boxed();
}

4.上面我們介紹的是IntStream,它專門用來處理int型別的數值,除此之外還有DoubleStreamLongStream,它們分別處理doublelong型別的數值,只要呼叫mapToDoublemapToLong方法即可獲得對應的數值流,使用方法也是IntStream大同小異,這裡就不做詳細介紹了。

構建流:

之前的文章中我們一直都是直接呼叫集合的stream方法來獲取一個流,其實獲取流的方式有很多種。

  1. 直接使用值初始化流

    public static void valueStream(){
        Stream<String> stream = Stream.of("Hello", "World ");
        stream.map(String::toUpperCase).forEach(System.out::println);
    }
  2. 使用Arrays.stream()靜態方法建立流,這個方法接受一個數組

    public  static void arrayStream(){
        String[] strs = new String[]{"Hello","World"};
        Arrays.stream(strs).map(String::toUpperCase).forEach(System.out::println);
    }
  3. 從檔案中讀取獲取流,每一行就是流中的一個元素

    public static void fileStream(){
        try {
            Stream<String> text = Files.lines(Paths.get("C:\\Users\\Half\\Desktop\\test.txt"),Charset.defaultCharset());
            text.forEach(System.out::println);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  4. 用函式生成無限流,分別呼叫Stream.iterate()Stream.generate()方法即可,兩者不同之處在於Stream.iterate()方法沒生成一個值都要依賴於前一個值,適合生成連續的數值,而Stream.generate()則每個值都是獨立生成的,相互之間沒有關聯。要注意的是因為是無限流,所以會一直生成元素,所以必須要呼叫limit()方法來限制生成的個數,否則程式碼會一直執行下。

    • Stream.iterate()接受兩個引數,分別是起始值和後續值的生成程式碼,例如下面這個方法就是從0開始,依次加10

      public static void iterateStream(){
          Stream.iterate(0, num -> num+10).limit(5).forEach(System.out::println);
      }

      執行結果:

      0
      10
      20
      30
      40
    • Stream.generate()接受一個引數,生成數值的程式碼

      public static void generateStream(){
          Stream.generate(Math::random).limit(5).forEach(System.out::println);
      }

      執行結果:

      0.9538068193407456
      0.5113995186169759
      0.20525086606957266
      0.2974528805300197
      0.019653649898021208

總結:

這篇文章介紹了數值流和構建流的方式,流的應用可以很靈活,後續還會介紹流的用法。