java8實戰讀書筆記:數值流、Stream建立與Optional類的使用

java8學習筆記目錄:
java8實戰讀書筆記:Lambda表達式語法與函數式編程接口
java8實戰讀書筆記:複合Lambda表達式
java8實戰讀書筆記:初識Stream、流的基本操做(流計算java

本節將詳細介紹Java8中的數值流、流的建立與Optional類的使用。編程

數值流

不知你們還記不得,在介紹函數式編程接口中爲了不基礎數據類型的裝箱/拆箱帶來的性能損耗,特地爲函數式接口引入了基礎數據類型的函數式編程接口,例如IntPredicate、LongPredicate、DoublePredicate。一樣,流API也考慮到基本數據類型的裝箱/拆箱會帶來性能損耗,引入了數值流,例如IntStream、LongStream、DoubleStream。數組

1.1 原始數據特化流

java8中提供了3個原始數據特化流,分別爲IntStream、LongStream、DoubleStream。本文將以IntStream進行講解,其餘流相似,只是數據類型分別表明Long或Double。微信

1.1.1 映射到數據流

首先咱們仍是從一個示例開始本節的學習:計算菜單中全部菜品的卡路里之和。app

1public static void test_reduce_caluli(List<Dish> menu) {
2    int calories = menu.stream()
3                    .map(Dish::getCalories)
4                    .reduce(0, Integer::sum);
5    System.out.println("菜品中的總卡路里:" + calories);
6}

上面包含了一個基本數據類型的裝箱/拆箱動做,java8的流API提供了mapToInt方法,直接返回int類型的流運維

咱們先稍微看一下mapToInt的方法聲明:ide

1IntStream mapToInt(ToIntFunction<? super T> mapper)
2

接受一個T->int的函數式編程接口,直接返回IntStream流對象,並且IntStream自己提供了一些經常使用的聚合函數,例如sum。
使用IntStream來實現計算菜單中全部菜品的卡路里之和,其示例以下:函數式編程

1public static void test_reduce_caluli_intStream(List<Dish> menu) {
2    int calories = menu.stream()
3            .mapToInt(Dish::getCalories)
4            .sum();
5    System.out.println("菜品中的總卡路里:" + calories);
6
7}

1.1.2 轉換回對象流

使用了特化流例如IntStream後,將不能再自動轉換爲其對應的封裝對象流Stream< T >了,咱們能夠隨意從IntStream對象中對應的通用方法的函數聲明,例如IntStream#map函數的聲明以下:函數

1IntStream map(IntUnaryOperator mapper);

只能接受int -> int的函數式編程接口,若是想將IntStream轉回到Stream< Integer >,該如何處理呢?性能

IntStream提供了boxed()方法來實現將基礎數據類型轉換回對應的包裝類型的流。

1.1.3 經常使用函數

Stream中定義的方法,IntStream也能夠使用,例如map、flatMap、distinict等,IntStream除這些以外,還提供了經常使用的聚合函數,例如sum、min、max、average(平均數)。

1OptionalDouble average();
2OptionalInt max();
3OptionalInt min();
4int sum();

有關Optional相關的類將在下文詳細介紹。

另外除了上面提到的聚合函數,IntStream還提供了兩個與數值範圍的方法:

1public static IntStream range(int startInclusive, int endExclusive);
2public static IntStream rangeClosed(int startInclusive, int endExclusive);

rangeClosed與range的區別就是rangeClosed包含結束邊界,舉一個簡單示例以下:

1public static void test_range() {
2    long count = IntStream.range(1,100)
3                        .filter( i -> i % 2 == 0 )
4                         .count();
5    System.out.println("count:" + count);
6
7}

計算【1,100)中包含的偶數個數,將輸出49。若是將range(1,100)修改成rangeClosed(1,100),在輸出的個數爲50。

構建流

2.1 經過值構建流

java 8的Stream提供了兩個重載的of函數來顯示的構建流,其聲明以下:

1public static<T> Stream<T> of(T t)
2public static<T> Stream<T> of(T... values)
3

2.2 經過數組構建流

經過Arrays.stream構建流,其聲明以下:
Arrays#stream

1public static <T> Stream<T> stream(T[] array)
2

2.3 經過文件流

能夠經過文件流建立流,在java.nio.file.Files類中定義了以下建立流的方法。

1public static Stream<Path> list(Path dir) throws IOException
2public static Stream<Path> walk(Path start, int maxDepth, FileVisitOption... options)
3public static Stream<Path> walk(Path start, FileVisitOption... options)
4public static Stream<Path> find(Path start, int maxDepth,BiPredicate<Path, BasicFileAttributes> matcher,   
5    FileVisitOption... options)
6public static Stream<String> lines(Path path, Charset cs)
7public static Stream<String> lines(Path path) throws IOException
8

下面咱們舉一個示例:找出一個文件中不一樣詞的個數。

1public static void test_file_stram() {
 2    long uniqueWords = 0;
 3    try(Stream<String> lines = Files.lines(Paths.get("d:/tmp/words.txt"), Charset.defaultCharset())) {  
 4        uniqueWords = lines.flatMap(line -> Arrays.stream(line.split("" )))
 5                .distinct()
 6                .count();
 7
 8        System.out.println("不重複字符個數:" + uniqueWords);
 9    } catch (IOException e) {
10        e.printStackTrace();
11    }
12}

2.4 函數生成流:建立無限流

Stream API提供了兩個靜態方法從函數生成流:iterate、generate,咱們先來看一下其函數聲明:

1public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
2public static<T> Stream<T> generate(Supplier<T> s)
3

2.4.1 iterate

iterate方法的第一個參數類型爲T,表示其初始值,第二個參數以下:

java8實戰讀書筆記:數值流、Stream建立與Optional類的使用

即其函數式聲明爲爲T-T。其示例以下:

1public static void test_iterate() {
2    Stream.iterate(0, a -> a + 2)
3            .limit(10)
4            .forEach(System.out::println);
5}

注意:因爲是無限流,故千萬記得使用limit截斷流,不然會無限循環下去。

2.4.2 generate

其參數爲Supplier< T >,其定義以下:

java8實戰讀書筆記:數值流、Stream建立與Optional類的使用

即構造一個T類型的對象,舉例以下:

1public static void test_iterate() {
2    Stream.iterate(0, a -> a + 2)
3            .limit(10)
4            .forEach(System.out::println);
5}

2.5 集合對象的stream

這個在前面的示例中用的最多,就不作過多介紹。

Optional類

爲了更優雅的處理null值,避免空指針錯誤,java8中引入Optional類。

java8實戰讀書筆記:數值流、Stream建立與Optional類的使用

接下來對這些方法一一作個介紹。

  • public static< T> Optional< T> empty()
    建立一個Optional對象,其內部持有的對象爲null。

  • public static < T > Optional< T > of(T value)
    使用value的值,建立一個Optional對象。

  • public static < T > Optional< T > ofNullable(T value)
    使用v去建立一個Optional對象,若是value爲null,則返回empty()。

  • public T get()
    從Optional對象獲取內嵌的對象,若是爲空,則拋出NoSuchElementException。

  • public boolean isPresent()
    判斷Optional對象中包含的值是否存在。

  • public void ifPresent(Consumer consumer)
    若是Optional包裹的對象存在,則消費該對象。Consumer的函數式編程接口:T -> void。

  • public Optional< T > filter(Predicate predicate)
    若是Optional中包裹的對象爲空,則返回自身,不然若是包裹的對象知足predicate表達式,則返回自身,不然返回empty()。

  • public< U > Optional< U > map(Function mapper)
    若是Optional對象中包裹的對象爲空,則返回empty(),不然運用(T-U),包裹U,固然若是U爲空,則返回empty()。

  • public< U > Optional< U > flatMap(Function> mapper)
    若是Option對象中包裹的對象爲空,則返回empty(),不然使用對Optional中的包裹的對象value應用Function,最終返回Optional對象。

  • public T orElse(T other)
    返回Optional中包裹的對象,若是其值爲空,則返回other。

  • public T orElseGet(Supplier other)
    返回Optional中包裹的對象,若是其值爲空,則返回 Supplier函數式編輯接口中建立的值。

  • public < X extends Throwable> T orElseThrow(Supplier< ? extends X> exceptionSupplier) throws X
    返回Optional中包裹的對象,若是其值爲空,則拋出自定義一次,由Supplier函數式編程接口返回。

其示例代碼以下:

1public static void test_option() {
2Map<String, String> data = new HashMap<>();
3Optional<String> value = Optional.ofNullable(data.get("userName"));
4// 若是存在userName值,則輸出
5value.ifPresent(System.out::println);  
6}

本文就介紹到這裏了,本文詳細介紹了java8中的數值流、Stream的建立以及java8中Optional類的使用。

查看更多文章請關注微信公衆號:
java8實戰讀書筆記:數值流、Stream建立與Optional類的使用
一波廣告來襲,做者新書《RocketMQ技術內幕》已出版上市:
java8實戰讀書筆記:數值流、Stream建立與Optional類的使用《RocketMQ技術內幕》已出版上市,目前可在主流購物平臺(京東、天貓等)購買,本書從源碼角度深度分析了RocketMQ NameServer、消息發送、消息存儲、消息消費、消息過濾、主從同步HA、事務消息;在實戰篇重點介紹了RocketMQ運維管理界面與當前支持的39個運維命令;並在附錄部分羅列了RocketMQ幾乎全部的配置參數。本書獲得了RocketMQ創始人、阿里巴巴Messaging開源技術負責人、Linux OpenMessaging 主席的高度承認並做序推薦。目前是國內第一本成體系剖析RocketMQ的書籍。

相關文章
相關標籤/搜索