Java8 學習

Java8 新特性

Java並無沒落,人們很快就會發現這一點 本教程將對java8新增的特性進行簡明的較少,使得你們對於java8新特性有一個比較直觀的印象。html

接口中定義默認方法與靜態方法

java在jdk1.8前僅容許在接口中使用抽象方法和靜態常量定義。Java8將容許在接口中定義默認方法和靜態方法。接口中的默認方法主要是用於解決jdk的向下兼容問題。如Collection接口中添加了新的stream方法,則jdk1.7以前的代碼是沒法在1.8平臺上編譯經過,故提供了接口中的默認方法。
###接口中的默認方法 Java 8 容許咱們使用default關鍵字,爲接口聲明添加非抽象的方法實現。這個特性又被稱爲擴展方法。該方法在函數接口或者是非函數接口均可以實現。java

public interface DefaultInterface {
    default void Print() {
        System.out.println("hello world");
    }
}
public interface Formula {
    String TEXT = "text";
    double calculate(int a);
    default double sqrt(int a) {
        return Math.sqrt(a);
    }
}

####默認方法繼承git

重寫與普通方法的大體一致。多重繼承時,使用加強的supergithub

####接口中的靜態方法 該方法主要針對類庫的開發人員,便於工具類(接口)的設計和開發。編程

public interface Formula { 
    static void print() { 
        System.out.println("hello, world"); 
    } 
}

###函數接口(Functional Interfaces) 本節做爲lambda表達式的基礎部分,內容相對較爲簡單。Runnable接口、Callable接口、Comparator接口, 和Java中定義的其它大量接口——在Java 8中咱們稱爲函數式接口:它們是隻須要實現一個方法去知足需求的接口。
每個lambda都可以經過一個特定的函數式接口,與一個給定的類型進行匹配。同時,任意只包含一個抽象方法的接口,咱們均可以用來作成lambda表達式。爲了讓你定義的接口知足要求,你應當在接口前加上@FunctionalInterface 標註。編譯器會注意到這個標註,若是你的接口中定義了第二個抽象方法的話,編譯器會拋出異常。api

@FunctionalInterface
public interface Converter<F, T> {
    T convert(F from);
}
 
Converter<Integer, String> converter = from -> String.valueOf(from);
System.out.println(converter.convert(33));

Java中重要的函數接口

函數名| 參數| 返回類型| 示例| 對應Guava| 備註 ----|--- Predicate<T>| T |boolean |吃了沒? |Predicate<T>| 斷言,判斷表達式是否爲真 Consumer<T>| T |void ||| Function<T,R>| T |R |String 轉int| Function<T,R> | Supplier<T> |無| T |工廠方法 || UnaryOperator<T>| T |T| 邏輯非(!)| | BinaOperator<T>| (T,T)| T| 求兩個數的乘積 ||併發

###方法引用 方法引用語法格式有如下三種: objectName::instanceMethod ClassName::staticMethod ClassName::instanceMethod 對於函數式接口的代碼塊,還有更簡單的實現方式,具體以下oracle

####靜態方法引用app

Converter<Integer, String> methodReference = String::valueOf;
        System.out.println(methodReference.convert(21));

####非靜態方法引用dom

class Something {
    String startsWith(String s) {
        return String.valueOf(s.charAt(0));
    }
}
 
Something something = new Something();
Converter<String, String> converter = something::startsWith;
String converted = converter.convert("Java");
System.out.println(converted);    // "J"

####構造函數引用 對於構造函數(構造函數本質上也是一種靜態方法),此處的用法比較精妙。且看示例:

public class Person {
    String firstName;
    String lastName;
 
    public Person() {}
 
    public Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}
 
interface PersonFactory<P extends Person> {
    P create(String firstName, String lastName);
}
 
PersonFactory personFactory = Person::new;
Person person = personFactory.create("黃", "大仙");

上面展現的代碼中,咱們首先建立了一個Person類,和該類的一個工廠接口用於建立Person對象。最終經過構造函數引用來把全部東西拼到一塊兒,而不是像之前同樣,經過手動實現一個工廠來這麼作。
咱們經過Person::new來建立一個Person類構造函數的引用。Java編譯器會自動地選擇合適的構造函數(person(string, string))來匹配PersonFactory.create函數的簽名,並選擇正確的構造函數形式。

PersonFatory爲一個「函數接口」, 且Person::new 返回的爲一個函數。具體請看上節內容。

##lambda表達式 ###認識lambda表達式

維基百科對lambda表達式的解釋:沒找到

簡單的說lambda表達式:一段帶有輸入參數的可執行語句塊。

(Type1 param1, Type2 param2, ..., TypeN paramN) -> {
  statment1;
  statment2;
  //.............
  return statmentM;
}
//無參數的lambda表達式   
Runnable noArgument = () -> System.out.print("hello, world");
ActionListener oneArgument = event -> System.out.print("button click");
Runnable multiStatement = () -> {
      System.out.print("hello ");
      System.out.print("world");
};
BinaryOperator<Long> add = (x, y) -> x + y;
BinaryOperator<Long> addExplicit = (Long x, Long y) -> x + y;

注意:1. 代碼塊和普通方法遵循的規則一致, 可使用返回或異常進行退出。

####體驗lambda表達式

舉個栗子:將list中的內容由小寫變爲大寫

List<String> names = new ArrayList<>();
names.add("huang");
names.add("chuancong");
List<String> lowercaseNames = new ArrayList<>();
for (String name : names) {
  lowercaseNames.add(name.toLowerCase());
}

List<String> names = new ArrayList<>();
names.add("huang");
names.add("chuancong");
List<String> lowercaseNames = FluentIterable.from(names).transform(new Function<String, String>() {
  @Override
  public String apply(String name) {
    return name.toLowerCase();
  }
}).toList();

List<String> names = new ArrayList<>();
names.add("huang");
names.add("chuancong");
List<String> lowercaseNames = names.stream().map((String name) -> {return name.toLowerCase();}).collect(Collectors.toList());

###Lambda表達式做用域 ####訪問本地變量 對於JDK1.7匿名內部類而言,若是要使用外部的變量,則該變量須要顯式的定義爲final類型。

final String name = "黃傳聰";
Button button = new Button();
button.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("hi: " + name);
    }
});
Java 1.8以後,該final修飾符能夠省略,可是、but java8雖然放鬆了限制,可是該變量仍是「既成事實上必須是final」。
String name = "黃傳聰";
name += "黃傳聰";
button.addActionListener(e -> System.out.println("hi: " + name));

該代碼會編譯失敗, 總而言之,java1.8雖然放鬆了 限制,可是在編譯時仍要保證該變量爲final類型。所以,lambda表達式訪問外部變量有一個很是重要的限制:變量不可變(只是引用不可變,而不是真正的不可變)。

訪問屬性和靜態變量

對於靜態變量和屬性的訪問方式同匿名內部類一致。

class Lambda4 {
    static int outerStaticNum;
    int outerNum;

    void testScopes() {
        Converter<Integer, String> stringConverter1 = (from) -> {
            outerNum = 23;
            return String.valueOf(from);
        };

        Converter<Integer, String> stringConverter2 = (from) -> {
            outerStaticNum = 72;
            return String.valueOf(from);
        };
    }
}

###訪問接口的默認方法 接口的默認方法爲java1.8新加的屬性,具體可參看第一小節。接口中默認方法,能夠被其實現類、或匿名內部類進行調用。可是,Lambda表達式不能使用。

Lambda表達式中的this

#####類型推斷 Lambda表達式中的類型推斷,其實是java7中就引入的目標類型推斷的擴充。Java7中提供了<>操做符,使得javac可根據該操做符推斷出泛型參數的類型。如:

Map<String, String> map = new HashMap<String, String>();
Map<String, String> map = new HashMap<>();
 
private void useMap(Map<String, String> map);
useMap(new HashMap<>);

lambda表達式可省略全部的參數類型,javac能夠根據上下文推斷參數類型,可是,也有推斷不出的情景,且看下文方法重載。

方法重載

方法的重載可能會致使lambda表達類型推斷失敗。 對於推導過程:

  • 若是隻有一個可能的目標類型,由相應的函數接口李德參數類型推導出具體類型;
  • 若是有多個可能的目標類型。由最具體的類型推導出;
  • 若是有多個可能的目標類型,且最具體的類型不明確,則需認爲指定。
  • 發生場景:Lambda表達式做爲參數進行傳遞時..
@FunctionalInterface
public interface IntPredicate {
    public boolean test(int value);
}
 
@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);
}
 
public boolean predicate(Predicate<Integer> predicate) {
    return predicate.test(1);
}

public boolean predicate(IntPredicate predicate) {
    return predicate.test(1);
}
application.predicate(a -> a > 1);

該段代碼在Intellij 中提示:
輸入圖片說明
表示,推斷系統沒法推斷lambda表達式的具體類型,由於該表達式對於兩個方法的參數都契合。

Lambda表達式與匿名內部類之間的區別請參考

##Stream stream流 API是java8中最大的一次改動,咱們將從 什麼是流,流的做用及流的實戰等方面進行相關的討論。

A sequence of elements supporting sequential and parallel aggregate operations.

針對java給出的定義咱們進行簡單的解釋: Stream是元素的集合,相似於Iterator;能夠經過順序和並行的方式對流進行匯聚操做。
你們能夠把Stream當成一個高級版本的Iterator。原始版本的Iterator,用戶只能一個一個的遍歷元素並對其執行某些操做;高級版本的Stream,用戶只要給出須要對其包含的元素執行什麼操做,好比「過濾掉長度大於10的字符串」、「獲取每一個字符串的首字母」等,具體這些操做如何應用到每一個元素上,就給Stream就行了!
舉個栗子:

List<Integer> integerList =new ArrayList<>();
integerList.add(1);
integerList.add(2);
integerList.add(null);
integerList.stream().filter(num -> num != null).count();

該例子的左右:統計integerList中元素不爲null的值得數量。
輸入圖片說明

對於該例子的拆解,能夠發現使用stream流能夠分爲如下三個步驟:

建立Stream;

轉換Stream,每次轉換原有Stream對象不改變,返回一個新的Stream對象(能夠有屢次轉換);
對Stream進行聚合(Reduce)操做,獲取想要的結果;
輸入圖片說明

建立stream

常見的建立stream的方法有兩種
經過Stream接口的靜態工廠方法;
經過Collection接口的默認方法把一個Collection對象轉換成Stream
經過Stream接口的靜態工廠方法建立
經過該接口中提供的靜態方法 of()進行建立
其源碼以下,該方法存在兩個重載方法。

public static<T> Stream<T> of(T t) {
    return StreamSupport.stream(new Streams.StreamBuilderImpl<>(t), false);
}

@SafeVarargs
@SuppressWarnings("varargs") // Creating a stream from an array is safe
public static<T> Stream<T> of(T... values) {
    return Arrays.stream(values);
}
使用該方法建立Stream的示例以下:
Stream<Integer> integerStream = Stream.of(1);
 Stream<String> stringStream = Stream.of("1", "2");

使用generator方法建立流

Returns an infinite sequential unordered stream where each element is generated by the provided Supplier
該方法返回一個無限長度的stream, 該方法適合生成 固定元素或隨機元素的流。如:
Stream.generate(new Supplier<String>() {
    @Override
    public String get() {
        return "1";
    }
});
 
Stream.generate(new Supplier<Double>() {
    @Override
    public Double get() {
        return Math.random();
    }
});
Stream.generate(() -> Math.random());
Stream.generate(Math::random);

三條語句的做用都是同樣的,這個無限長度Stream是懶加載,通常這種無限長度的Stream都會配合Stream的limit()方法來用。

使用iterator生成stream

也是生成無限長度的Stream,和generator不一樣的是,其元素的生成是重複對給定的種子值(seed)調用用戶指定函數來生成的。其中包含的元素能夠認爲是:seed,f(seed),f(f(seed))無限循環

Returns an infinite sequential ordered Stream produced by iterative application of a function f to an initial element seed, producing a Stream consisting of seed, f(seed), f(f(seed)), etc. The first element (position 0) in the Stream will be the provided seed. For n > 0, the element at position n, will be the result of applying the function f to the element at position n - 1.

沒看懂,不講了

使用 Collection默認方法建立

該種方法應該是使用比較頻繁的方法,流大多數的使用場景在於對容器中得數據的處理。

default Stream<E> stream() {
    return StreamSupport.stream(spliterator(), false);
}

示例:

List<Integer> integerList =new ArrayList<>();
integerList.add(1);
integerList.add(2);
integerList.add(null);
integerList.stream();

轉換Stream

這一節是純抄的的,抄的,抄的 轉換Stream其實就是把一個Stream經過某些行爲轉換成一個新的Stream。Stream接口中定義了幾個經常使用的轉換方法,下面咱們挑選幾個經常使用的轉換方法來解釋。

distinct

對於Stream中包含的元素進行去重操做(去重邏輯依賴元素的equals方法),新生成的Stream中沒有重複的元素;
distinct方法示意圖(如下全部的示意圖都要感謝RxJava項目的doc中的圖片給予的靈感, 若是示意圖表達的有錯誤和不許確的地方,請直接聯繫我。):
輸入圖片說明

filter:

對於Stream中包含的元素使用給定的過濾函數進行過濾操做,新生成的Stream只包含符合條件的元素; filter方法示意圖: 輸入圖片說明 #####map: 對於Stream中包含的元素使用給定的轉換函數進行轉換操做,新生成的Stream只包含轉換生成的元素。這個方法有三個對於原始類型的變種方法,分別是:mapToInt,mapToLong和mapToDouble, 主要用於解決自動裝箱、拆箱的開銷。這三個方法也比較好理解,好比mapToInt就是把原始Stream轉換成一個新的Stream,這個新生成的 Stream中的元素都是int類型。之因此會有這樣三個變種方法,能夠免除自動裝箱/拆箱的額外消耗; map方法示意圖: 輸入圖片說明

flatMap:

和map相似,能夠將其看做爲列表的合併操做
flatMap方法示意圖:
輸入圖片說明
示例代碼:

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);
//outputStream.forEach(t -> System.out.println(t));

運行結果爲:
輸入圖片說明
起做用:至關於將多個容器對應的流合併到同一個流中。

#####peek: 生成一個包含原Stream的全部元素的新Stream,同時會提供一個消費函數(Consumer實例),新Stream每一個元素被消費的時候都會執行給定的消費函數;
peek方法示意圖:
輸入圖片說明
#####limit: 對一個Stream進行截斷操做,獲取其前N個元素,若是原Stream中包含的元素個數小於N,那就獲取其全部的元素;
limit方法示意圖:
輸入圖片說明

skip:

返回一個丟棄原Stream的前N個元素後剩下元素組成的新Stream,若是原Stream中包含的元素個數小於N,那麼返回空Stream;

輸入圖片說明
#####在一塊兒,在一塊兒!

List<Integer> nums = Lists.newArrayList(1,1,null,2,3,4,null,5,6,7,8,9,10);
System.out.println(「sum is:」+nums.stream().filter(num -> num != null).
   			distinct().mapToInt(num -> num * 2).
               peek(System.out::println).skip(2).limit(4).sum());

這段代碼演示了上面介紹的全部轉換方法(除了flatMap),簡單解釋一下這段代碼的含義:給定一個Integer類型的List,獲取其對應的Stream對象,而後進行過濾掉null,再去重,再每一個元素乘以2,再每一個元素被消費的時候打印自身,在跳過前兩個元素,最後去前四個元素進行加和運算(解釋一大堆,很像廢話,由於基本看了方法名就知道要作什麼了。這個就是聲明式編程的一大好處!)。你們能夠參考上面對於每一個方法的解釋,看看最終的輸出是什麼。
######性能問題

有些細心的同窗可能會有這樣的疑問:在對於一個Stream進行屢次轉換操做,每次都對Stream的每一個元素進行轉換,並且是執行屢次,這樣時間複雜度就是一個for循環裏把全部操做都作掉的N(轉換的次數)倍啊。其實不是這樣的,轉換操做都是lazy的,多個轉換操做只會在匯聚操做(見下節)的時候融合起來,一次循環完成。咱們能夠這樣簡單的理解,Stream裏有個操做函數的集合,每次轉換操做就是把轉換函數放入這個集合中,在匯聚操做的時候循環Stream對應的集合,而後對每一個元素執行全部的函數。

##Reduce 該操做是對Stream流進行的最後一步操做。

A reduction operation (also called a fold) takes a sequence of input elements and combines them into a single summary result by repeated application of a combining operation, such as finding the sum or maximum of a set of numbers, or accumulating elements into a list. The streams classes have multiple forms of general reduction operations, called reduce() and collect(), as well as multiple specialized reduction forms such as sum(), max(), or count().
簡單翻譯一下:匯聚操做(也稱爲摺疊)接受一個元素序列爲輸入,反覆使用某個合併操做,把序列中的元素合併成一個彙總的結果。好比查找一個數字列表的總和或者最大值,或者把這些數字累積成一個List對象。Stream接口有一些通用的匯聚操做,好比reduce()和collect();也有一些特定用途的匯聚操做,好比sum(),max()和count()。注意:sum方法不是全部的Stream對象都有的,只有IntStream、LongStream和DoubleStream是實例纔有。

下面會分兩部分來介紹匯聚操做:

  1. 可變匯聚:把輸入的元素們累積到一個可變的容器中,好比Collection或者StringBuilder;
  2. 其餘匯聚:除去可變匯聚剩下的,通常都不是經過反覆修改某個可變對象,而是經過把前一次的匯聚結果當成下一次的入參,反覆如此。好比reduce,count,allMatch;

可變匯聚

可變匯聚對應的只有一個方法:collect,正如其名字顯示的,它能夠把Stream中的要有元素收集到一個結果容器中(好比Collection)。先看一下最通用的collect方法的定義(還有其餘override方法):

<R> R collect(Supplier<R> supplier,
                  BiConsumer<R, ? super T> accumulator,
                  BiConsumer<R, R> combiner);

先來看看這三個參數的含義:Supplier supplier是一個工廠函數,用來生成一個新的容器;BiConsumer accumulator也是一個函數,用來把Stream中的元素添加到結果容器中;BiConsumer combiner仍是一個函數,用來把中間狀態的多個結果容器合併成爲一個(併發的時候會用到)。看暈了?來段代碼!

List<Integer> nums = Lists.newArrayList(1,1,null,2,3,4,null,5,6,7,8,9,10);
       List<Integer> numsWithoutNull = nums.stream().filter(num -> num != null).
               collect(() -> new ArrayList<Integer>(),
                       (list, item) -> list.add(item),
                       (list1, list2) -> list1.addAll(list2));

上面這段代碼就是對一個元素是Integer類型的List,先過濾掉所有的null,而後把剩下的元素收集到一個新的List中。進一步看一下collect方法的三個參數,都是lambda形式的函數(上面的代碼可使用方法引用來簡化,留給讀者本身去思考)。 第一個函數生成一個新的ArrayList實例;
第二個函數接受兩個參數,第一個是前面生成的ArrayList對象,二個是stream中包含的元素,函數體就是把stream中的元素加入ArrayList對象中。第二個函數被反覆調用直到原stream的元素被消費完畢;
第三個函數也是接受兩個參數,這兩個都是ArrayList類型的,函數體就是把第二個ArrayList所有加入到第一個中;
可是上面的collect方法調用也有點太複雜了,不要緊!咱們來看一下collect方法另一個override的版本,其依賴Collector

1	<R, A> R collect(Collector<? super T, A, R> collector);

這樣清爽多了!少年,還有好消息,Java8還給咱們提供了Collector的工具類–Collectors,其中已經定義了一些靜態工廠方法,好比:Collectors.toCollection()收集到Collection中, Collectors.toList()收集到List中和Collectors.toSet()收集到Set中。這樣的靜態方法還有不少,這裏就不一一介紹了,你們能夠直接去看JavaDoc。下面看看使用Collectors對於代碼的簡化:

List<Integer> numsWithoutNull = nums.stream().filter(num -> num != null).
                collect(Collectors.toList());
JavaDoc示例:

     // Accumulate names into a List
     List<String> list = people.stream().map(Person::getName).collect(Collectors.toList());

     // Accumulate names into a TreeSet
     Set<String> set = people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new));

     // Convert elements to strings and concatenate them, separated by commas
     String joined = things.stream()
                           .map(Object::toString)
                           .collect(Collectors.joining(", "));

     // Compute sum of salaries of employee
     int total = employees.stream()
                          .collect(Collectors.summingInt(Employee::getSalary)));

     // Group employees by department
     Map<Department, List<Employee>> byDept
         = employees.stream()
                    .collect(Collectors.groupingBy(Employee::getDepartment));

     // Compute sum of salaries by department
     Map<Department, Integer> totalByDept
         = employees.stream()
                    .collect(Collectors.groupingBy(Employee::getDepartment,
                                                   Collectors.summingInt(Employee::getSalary)));

     // Partition students into passing and failing
     Map<Boolean, List<Student>> passingFailing =
         students.stream()
                 .collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD));

其餘匯聚

除去可變匯聚剩下的,通常都不是經過反覆修改某個可變對象,而是經過把前一次的匯聚結果當成下一次的入參,反覆如此。好比reduce,count,allMatch; – reduce方法:reduce方法很是的通用,後面介紹的count,sum等均可以使用其實現。reduce方法有三個override的方法,本文介紹兩個最經常使用的,最後一個留給讀者本身學習。先來看reduce方法的第一種形式,其方法定義以下:

Optional<T> reduce(BinaryOperator<T> accumulator);

接受一個BinaryOperator類型的參數,在使用的時候咱們能夠用lambda表達式來。

List<Integer> ints = Lists.newArrayList(1,2,3,4,5,6,7,8,9,10);
System.out.println("ints sum is:" + ints.stream().reduce((sum, item) -> sum + item).get());

能夠看到reduce方法接受一個函數,這個函數有兩個參數,第一個參數是上次函數執行的返回值(也稱爲中間結果),第二個參數是stream中的元素,這個函數把這兩個值相加,獲得的和會被賦值給下次執行這個函數的第一個參數。要注意的是:第一次執行的時候第一個參數的值是Stream的第一個元素,第二個參數是Stream的第二個元素。這個方法返回值類型是Optional,這是Java8防止出現NPE的一種可行方法,後面的文章會詳細介紹,這裏就簡單的認爲是一個容器,其中可能會包含0個或者1個對象。 這個過程可視化的結果如圖: 輸入圖片說明 reduce方法還有一個很經常使用的變種:
T reduce(T identity, BinaryOperator<T> accumulator);

這個定義上上面已經介紹過的基本一致,不一樣的是:它容許用戶提供一個循環計算的初始值,若是Stream爲空,就直接返回該值。並且這個方法不會返回Optional,由於其不會出現null值。下面直接給出例子,就再也不作說明了。

List<Integer> ints = Lists.newArrayList(1,2,3,4,5,6,7,8,9,10);
System.out.println("ints sum is:" + ints.stream().reduce(0, (sum, item) -> sum + item));

– count方法:獲取Stream中元素的個數。比較簡單,這裏就直接給出例子,不作解釋了。

List<Integer> ints = Lists.newArrayList(1,2,3,4,5,6,7,8,9,10);
System.out.println("ints sum is:" + ints.stream().count());
– 搜索相關

– allMatch:是否是Stream中的全部元素都知足給定的匹配條件
– anyMatch:Stream中是否存在任何一個元素知足匹配條件
– findFirst: 返回Stream中的第一個元素,若是Stream爲空,返回空Optional
– noneMatch:是否是Stream中的全部元素都不知足給定的匹配條件
– max和min:使用給定的比較器(Operator),返回Stream中的最大|最小值
下面給出allMatch和max的例子,剩下的方法讀者當成練習。

List<Integer&gt; ints = Lists.newArrayList(1,2,3,4,5,6,7,8,9,10);
System.out.println(ints.stream().allMatch(item -> item < 100));
ints.stream().max((o1, o2) -&gt; o1.compareTo(o2)).ifPresent(System.out::println);

Stream 小結

Stream到此告一段落,簡單對Stream進行簡單的總結:
上文中講述的Stream都是順序操做,固然Stream一樣支持並行操做,具體可本身查閱 ;
Stream的使用,包括三個環節,同時有幾個比較重要的狀態須要瞭解一下。轉換Stream,能夠認爲是Stream的中間狀態,jdk描述以下:

Intermediate operations return a new stream. They are always lazy; executing an intermediate operation such as filter() does not actually perform any filtering, but instead creates a new stream that, when traversed, contains the elements of the initial stream that match the given predicate. Traversal of the pipeline source does not begin until the terminal operation of the pipeline is executed.

正如上文中所言,該狀態的Stream爲了效率起見,並不會當即執行,只有執行到終態時才觸發。處於該狀態的操做主要爲上文中提到的Stream的轉換操做。

###參考文獻:
http://www.oracle.com/technetwork/java/javase/8-whats-new-2157071.html
http://winterbe.com/posts/2014/03/16/java-8-tutorial/
http://ifeve.com/java-8-tutorial-2/
http://www.importnew.com/10360.html
http://ifeve.com/lambda/
http://ifeve.com/stream/
http://ifeve.com/java8/#more-21384
http://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html

相關文章
相關標籤/搜索