Java 8 聚合操作詳解
Oracle在2014年3月19日如期釋出了Java 8。Java 8版本被認為是具有里程碑意義的一個版本,Oracle在該版本中新增了許多新特性,包括Lambda表示式、方法引用、加強了安全等等。
在眾多的新特性中,聚合操作(Aggregate Operations)是針對集合類的一個比較大的變化。通過聚合操作,開發者可以更容易地使用Lambda表示式,並且更方便地實現對集合的查詢、遍歷、過濾以及常見計算等。
聚合操作與Java 8中的Lambda表示式、方法引用等新特性是相關的,一般一起組合使用,但這裡只說明聚合操作的使用,下面就聚合操作的使用進行簡單說明。
集合類的層次結構
集合類是Java語言提供的輔助類,是一種較為通用的資料結構,如Map、Set、List等。Java中集合類層次關係如下:
圖 1
如上圖,Collection是主要集合類的介面,其子介面(具化介面)有Deque、Queue、Set、List等。
Map是另一種型別的集合,以Key、Value的鍵值對儲存資料集。
在Java 8中,在java.util.Collection介面中新增了如下方法:
Stream<E> stream() { return StreamSupport.stream(spliterator(), false); }
stream()方法的可見性修飾符為default,這又是Java 8的新特性。在介面中(Collection為interface),本不需要(也不能)進行方法實現,但引入default修飾後就不同了。開發者不但可以進行方法的實現,而且還不用考慮向後相容的問題。關於Default Method的詳細解釋,讀者可以參考Java 8的官方文件。
正是stream方法引出了集合類的聚合操作。
[注意]
Map介面中並沒有stream()方法,但是Map的values()和keySet()均返回集合物件,在集合物件上當然是可以使用stream()方法的。
聚合操作例項
為說明聚合操作的使用,首先定義一個資料元素類Person,如下:
import java.time.LocalDate; public class Person { String name; LocalDate birthday; Sex gender; String emailAddress; public int getAge() { return LocalDate.now().getYear() - birthday.getYear(); } public void setBirthday(LocalDate birthday){ this.birthday = birthday; } public void setGender(Sex sex){ this.gender = sex; } public void printPerson() { System.out.println("The name is " + name); } public Sex getGender(){ return gender; } public enum Sex { MALE, FEMALE } }
在Java 8以前的版本中,對Person集合的遍歷往往採用以下方式:
Set<Person> persons = new HashSet<Person>();
//傳統遍歷方式 for (Person person : persons) { if (person.getAge() > 18) { System.out.println(person.name + ” is elder than 18.”); } }
同樣的功能,在Java 8中使用聚合操作,可以實現如下:
//使用聚合操作 persons.stream().filter(new Predicate<Person>() { @Override public boolean test(Person person) { if (person.getAge() > 18) { return true; } else { return false; } } }).forEach(new Consumer<Person>() { @Override public void accept(Person person) { System.out.println(person.name + " is elder than 18."); } });
首先,在集合物件persons上呼叫stream()方法(聚合操作),取得person物件的資料集(elements),然後呼叫聚合操作filter()對集合中的元素進行過濾,再呼叫forEach()完成對符合條件的person的列印。
Predicate和Consumer為Java 8中定義的函式介面(Functional Interface),在java.util.function包下面,函式介面也是Java 8的新特性。在上述程式碼中,使用了兩個匿名類分別對Predicate和Consumer進行了實現,這兩個介面都只有一個方法,這也是函式介面的特徵之一。
上述程式碼中的寫法還是比較繁瑣的,為進一步簡化,可以使用Lambda表示式實現,如下:
// 使用聚合操作及Lambda persons.stream() .filter(p -> p.getAge() >= 18) .forEach(p -> System.out.println(p.name + " is elder than 18."));
因為filter()、forEach()的引數均為函式介面,所以可以替換為Lambda表示式的方式。簡單來理解,Lambda表示式就是允許開發者將程式碼邏輯作為引數進行傳遞,關於Lambda表示式的詳細內容,請參Java 8的官方文件。
聚合操作的使用
聚合操作是Java 8針對集合類,使程式設計更為便利的方式,可以與Lambda表示式一起使用,達到更加簡潔的目的。
前面例子中,對聚合操作的使用可以歸結為3個部分:
- 資料來源部分:通過stream()方法,取得集合物件的資料集。
- 通過一系列中間(Intermediate)方法,對資料集進行過濾、檢索等資料集的再次處理。如上例中,使用filter()方法來對資料集進行過濾。
- 通過最終(terminal)方法完成對資料集中元素的處理。如上例中,使用forEach()完成對過濾後元素的列印。
中間方法除了filter()外,還有distinct()、sorted()、map()等等,其一般是對資料集的整理(過濾、排序、匹配、抽取等等),返回值一般也是資料集。
最終方法往往是完成對資料集中資料的處理,如forEach(),還有allMatch()、anyMatch()、findAny()、findFirst(),數值計算類的方法有sum、max、min、average等等。最終方法也可以是對集合的處理,如reduce()、collect()等等。reduce()方法的處理方式一般是每次都產生新的資料集,而collect()方法是在原資料集的基礎上進行更新,過程中不產生新的資料集。
從上面的例子中可以看出,通過stream()方法,從集合物件獲取的資料集與集合物件的迭代器(Iterator)有些類似,但他們也不完全相同:
- 迭代器提供next()、hasNext()等方法,開發者可以自行控制對元素的處理,以及處理方式,但是隻能順序處理;
- stream()方法返回的資料集無next()等方法,開發者無法控制對元素的迭代,迭代方式是系統內部實現的,同時系統內的迭代也不一定是順序的,還可以並行,如parallelStream()方法。並行的方式在一些情況下,可以大幅提升處理的效率。
除上述介紹的聚合操作外,Java 8中還提供了其他更為豐富的聚合操作,讀者可以參考Java 8的開發參考,瞭解更多內容。
總結
Java 8提供的聚合操作,以及一起使用的Lambda表示式為開發者帶來了便利,尤其在面向邏輯易變、開發迭代較快的專案應用時。但筆者個人認為,在帶來方便的同時,可能也帶來了一些麻煩,如相同邏輯的複用,以及程式碼的查錯、修改等,當然這些問題也是相對而言的。畢竟,任何事物都有兩面性,技術在不斷的發展,Java也在不斷地調整自己的適應性,變得功能越來越多,越來越強大了。
相關文章
- Pandas 分組聚合操作詳解
- Java8-9-Stream介紹與操作方式詳解Java
- java 操作符詳解Java
- HBase的JAVA API操作詳解JavaAPI
- Java8 新特性詳解Java
- Oracle 聚合函式詳解Oracle函式
- elasticsearch的java程式碼操作詳解ElasticsearchJava
- 詳解JAVA資料庫基本操作Java資料庫
- Java8的default方法詳解Java
- [Java 8 Tutorial翻譯系列]Java forEach詳解Java
- java 8 Stream,Optional的流庫詳解Java
- Java 8中的default方法使用詳解Java
- Java對各種檔案的操作詳解Java
- 【Mongo】mongo聚合操作Go
- 詳解 RestTemplate 操作REST
- Java8 的流式操作Java
- Java 8 Strem高階操作JavaREM
- mongodb聚合操作記錄MongoDB
- 詳解Java Chassis 3與Spring Cloud的互操作JavaSpringCloud
- es筆記七之聚合操作之桶聚合和矩陣聚合筆記矩陣
- 8年經驗面試官詳解 Java 面試祕訣面試Java
- Java8特性詳解 lambda表示式(一):使用篇Java
- Java8-10-Stream分組與分割槽詳解Java
- Java 8 中新的 Date 和 Time 類入門詳解Java
- java中cookie操作詳細JavaCookie
- java8Stream操作集錦Java
- PHP操作xml詳解PHPXML
- 操作符詳解
- javascript操作iframe詳解JavaScript
- IO流操作詳解
- memcached 命令操作詳解
- MongoDB 基本操作詳解MongoDB
- JS 操作Cookie詳解JSCookie
- es筆記六之聚合操作之指標聚合筆記指標
- MongoDB學習之聚合操作MongoDB
- Spark2 Dataset聚合操作Spark
- Mathematical算術和聚合操作
- Java8特性詳解 lambda表示式(三):原理篇Java