1. 程式人生 > >隨筆6

隨筆6

風格 過濾元素 數據結構 println ted oob 多條件 java8 arr

---恢復內容開始---

了解了下關於stream的內容,把自己的理解和筆記還有一些自己寫的demo放在下面

http://www.runoob.com/java/java8-streams.html

Java 8 API添加了一個新的抽象稱為流Stream,可以讓你以一種聲明的方式處理數據。

Stream 使用一種類似用 SQL 語句從數據庫查詢數據的直觀方式來提供一種對 Java 集合運算和表達的高階抽象。

Stream API可以極大提高Java程序員的生產力,讓程序員寫出高效率、幹凈、簡潔的代碼。

這種風格將要處理的元素集合看作一種流, 流在管道中傳輸, 並且可以在管道的節點上進行處理, 比如篩選, 排序,聚合等。

元素流在管道中經過中間操作(intermediate operation)的處理,最後由最終操作(terminal operation)得到前面處理的結果。

+--------------------+       +------+   +------+   +---+   +-------+
| stream of elements +-----> |filter+-> |sorted+-> |map+-> |collect|
+--------------------+       +------+   +------+   +---+   +-------+
轉換成代碼:
List
<Integer> transactionsIds = widgets.stream() .filter(b -> b.getColor() == RED) .sorted((x,y) -> x.getWeight() - y.getWeight()) .mapToInt(Widget::getWeight) .sum();

流的操作類型分為兩種:
Intermediate:

一個流可以後面跟隨零個或多個 intermediate 操作。其目的主要是打開流,做出某種程度的數據映射/過濾,然後返回一個新的流,

交給下一個操作使用。這類操作都是惰性化的(lazy),就是說,僅僅調用到這類方法,並沒有真正開始流的遍歷。
Terminal:

一個流只能有一個 terminal 操作,當這個操作執行後,流就被使用“光”了,無法再被操作。所以這必定是流的最後一個操作。

Terminal 操作的執行,才會真正開始流的遍歷,並且會生成一個結果,或者一個 side effect。在對於一個 Stream 進行多次轉換操作 (Intermediate 操作),

每次都對 Stream 的每個元素進行轉換,而且是執行多次,這樣時間復雜度就是 N(轉換次數)個 for 循環裏把所有操作都做掉的總和嗎?其實不是這樣的,

轉換操作都是 lazy 的,多個轉換操作只會在 Terminal 操作的時候融合起來,一次循環完成。我們可以這樣簡單的理解,Stream 裏有個操作函數的集合,

每次轉換操作就是把轉換函數放入這個集合中,在 Terminal 操作的時候循環 Stream 對應的集合,然後對每個元素執行所有的函數。

接下來,當把一個數據結構包裝成 Stream 後,就要開始對裏面的元素進行各類操作了。常見的操作可以歸類如下。
Intermediate:
map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered
Terminal:
forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator
Short-circuiting:
anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 limit

特性:
1.不是數據結構
2.它沒有內部存儲,它只是用操作管道從 source(數據結構、數組、generator function、IO channel)抓取數據。
3.它也絕不修改自己所封裝的底層數據結構的數據。例如 Stream 的 filter 操作會產生一個不包含被過濾元素的新 Stream,而不是從 source 刪除那些元素。
4.所有 Stream 的操作必須以 lambda 表達式為參數
5.不支持索引訪問
6你可以請求第一個元素,但無法請求第二個,第三個,或最後一個。不過請參閱下一項。
7.很容易生成數組或者 List
8.惰性化
9.很多 Stream 操作是向後延遲的,一直到它弄清楚了最後需要多少數據才會開始。
10.Intermediate 操作永遠是惰性化的。
11.並行能力
12.當一個 Stream 是並行化的,就不需要再寫多線程代碼,所有對它的操作會自動並行進行的。
13.可以是無限的
14.集合有固定大小,Stream 則不必。limit(n) 和 findFirst() 這類的 short-circuiting 操作可以對無限的 Stream 進行運算並很快完成。

以上都是些理論知識,下面附上自己寫的幾個demo

package com.lk.menu.stream;

import java.io.*;
import java.util.*;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * @Author: Lukizzz
 * @Date: 2018/8/17 10:37
 * @Description:   流的操作
 */

public class StreamServiceTest {

    public static void main(String[] args) throws IOException {

        //1.流的map操作,大小寫轉換
        List<String> wordList = new ArrayList<>();
        wordList.add("apple");
        wordList.add("pear");
        List<String> output = wordList.stream().map(String::toUpperCase).collect(Collectors.toList());
                                                                       //.collect(Collectors.toCollection(LinkedList::new
        System.out.println(output);



        //2.流的map操作,平方數
        List<Integer> nums = Arrays.asList(1,2,3,4);
        List<Integer> aquareNums = nums.stream().map(n -> n * n).collect(Collectors.toList());
        System.out.println(aquareNums);



        //3.IntStream構造流
         IntStream.of(5,6,7,8).map(n -> n * n).forEach(System.out::println);



         //4.流的flatMap操作,把多個list的元素放在一個新的stream裏
        Stream<List<Integer>> inputStream = Stream.of(
                Arrays.asList(1),
                Arrays.asList(2, 3),
                Arrays.asList(4, 5, 6)
        );
        Stream<Integer> outputStream = inputStream.flatMap((childList) -> childList.stream());
        //以數組的形式輸出
        outputStream.forEach(System.out::println);
        //以列表方式輸出
        //System.out.println( outputStream.collect(Collectors.toList()));



        //5.流的filter操作,先進行平方數再留下偶數(篩選)
        List<Integer> nums1 = Arrays.asList(1,2,3,4);
        List<Integer> aquareNums1 = nums1.stream().map(n -> n * n).filter( n -> n%2==0).collect(Collectors.toList());
        System.out.println(aquareNums1);




        //6.peek不同於forEach直接結束,他可以多次使用,因為它對每個元素操作並返回一個新的stream
        //因為惰性的關系,所有操作是在最後一步一起執行的
        Stream.of("one","two","three","four").filter(e -> e.length()>3).peek(e -> System.out.println("Filtered value: " + e))
                                                                       .map(String::toUpperCase)
                                                                       .peek(e -> System.out.println("Mapped value: " + e))
                                                                       .collect(Collectors.toList());




        //7.進行Short-circuiting的操作如findFirst、 findAny時返回的類型需要放在optional容器中
        //多條件篩選是可行的
        List<Integer> nums2 = Arrays.asList(1,2,3,4);
        Optional<Integer> aquareNums2 = nums2.stream().map(n -> n * n).filter(n -> n%2==0 && n>5 ).findFirst();
        System.out.println(aquareNums2);



        //8.reduce()方法的幾個demo
        //字符串拼接
        String concat = Stream.of("A","B","C","D").reduce("",String::concat);
        System.out.println(concat);
        //求最小值
        double minValue = Stream.of(-5.0,-2.0,3.0,5.0,10.0).reduce(Double.MAX_VALUE,Double::min);
        System.out.println(minValue);
        //求最大值
        double maxValue = Stream.of(-5.0,-2.0,3.0,5.0,10.0).reduce(Double.MIN_VALUE,Double::max);
        System.out.println(maxValue);
        //求和,有初始值(初始值:算上這個值)
        int sumValue = Stream.of(5,6,7,8,9).reduce(0,Integer::sum);
        System.out.println(sumValue);
        //求和,無初始值,返回的是optional
        Optional<Integer> sumValue1 = Stream.of(5,6,7,8,9).reduce(Integer::sum);
        System.out.println(sumValue1);
        //過濾掉大寫字母+字符串連接
        concat = Stream.of("a", "B", "c", "D", "e", "F").
                filter(x -> x.compareTo("Z") > 0).
                reduce("", String::concat);
        System.out.println(concat);




       /*9.文件中最長的一行的長度 distinct():去重復 sorted():排序
         根據屬性排序  Stream<T> sorted(Comparator<? super T> comparator);
        對對象的進行操作Stream<T> peek(Consumer<? super T> action);
        截斷--取先maxSize個對象 Stream<T> limit(long maxSize);
        截斷--忽略前N個對象 Stream<T> skip(long n);
        */
        BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("D:\\xxxx.txt"),"gb2312"));
        int longest = br.lines().mapToInt(String::length).max().getAsInt();br.close();
        System.out.println(longest);




        //10.文件中最長的一行的單詞(註意io流讀取文件的時候要規定編碼格式,不然會亂碼)
        BufferedReader br1 = new BufferedReader(new InputStreamReader(new FileInputStream("D:\\xxxx.txt"),"gb2312"));
        List<String> words = br1.lines().flatMap(line -> Stream.of(line.split(""))).filter(word -> word.length() > 0).
                map(String::toLowerCase).distinct().sorted().collect(Collectors.toList());br1.close();
        System.out.println(words);

       /* allMatch:Stream 中全部元素符合傳入的 predicate,返回 true
        anyMatch:Stream 中只要有一個元素符合傳入的 predicate,返回 true
        noneMatch:Stream 中沒有一個元素符合傳入的 predicate,返回 true*/


       //11.隨機生成10個整數,篩選出其中的正整數
        Random rand = new Random();
        Supplier<Integer> supplier = rand::nextInt;
        Stream.generate(supplier).limit(10).filter(n ->n>0).forEach(System.out::println);

        //12.隨機生成10個(10-100)之間的整數
        Random random = new Random();
        IntStream intStream = random.ints(10,100);
        intStream.limit(10).forEach(System.out::println);
    }
}

運行結果截圖:

技術分享圖片

在項目開發過程中又遇到了和stream相關的示例:

//按照uid分組並計算獲得星星數的平均值 
Map<Integer,Double> map = dataSearch.stream().collect(Collectors.groupingBy(AppraiseRecord::getAnchorUid,Collectors.averagingDouble(AppraiseRecord::getStarNum))); Map<Integer,Object> finalMap = new LinkedHashMap<>(); //將map按value值倒序排序並將結果add給finalMap map.entrySet().stream() .sorted(Map.Entry.<Integer,Double>comparingByValue() .reversed()).forEachOrdered(e -> finalMap.put(e.getKey(), e.getValue()));
//遍歷finalMap並將數據添加進dataList
for (Map.Entry<Integer,Object> entry:finalMap.entrySet()){ Map<Integer,Object> data = new HashMap<Integer, Object>(); data.put(1,entry.getKey()); BigDecimal bg = new BigDecimal((Double) entry.getValue()); double f1 = bg.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue(); data.put(2,f1); dataList.add(data); }

隨筆6