Java8新特性
Lambda表達(dá)式
概念
lambda表達(dá)式是一段可以傳遞的代碼但指,它的核心思想是將面向?qū)ο笾械膫鬟f數(shù)據(jù)變成傳遞行為
允許把函數(shù)作為一個(gè)方法的參數(shù)(函數(shù)作為參數(shù)傳遞進(jìn)方法中)
作用:使用 Lambda 表達(dá)式可以使代碼變的更加簡(jiǎn)潔緊湊。
AndroidStudio 支持Lambda表達(dá)式
android {
compileSdkVersion 26
defaultConfig {
applicationId "video.uf.com.java8test"
minSdkVersion 15
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
jackOptions.enabled = true //支持Java8 Lambda表達(dá)式配置
}
//支持Java8 Lambda表達(dá)式 配置
compileOptions{
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
語(yǔ)法
(Type1 param1, Type2 param2, ..., TypeN paramN) -> {
statment1;
statment2;
//.............
return statmentM;
}
- 可選類型聲明:不需要聲明參數(shù)類型睬愤,編譯器可以統(tǒng)一識(shí)別參數(shù)值民逼。
- 可選的參數(shù)圓括號(hào):一個(gè)參數(shù)無(wú)需定義圓括號(hào)蜻展,但多個(gè)參數(shù)需要定義圓括號(hào)喻圃。
- 可選的大括號(hào):如果主體包含了一個(gè)語(yǔ)句屈雄,就不需要使用大括號(hào)。
- 可選的返回關(guān)鍵字:如果主體只有一個(gè)表達(dá)式返回值則編譯器會(huì)自動(dòng)返回值伊磺,大括號(hào)需要指定明表達(dá)式返回了一個(gè)數(shù)值。
Button btn = new Button(this);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.e("sss","ssss");
}
});
btn.setOnClickListener(v -> Log.e("sss","ssss"));
變量作用域
lambda 表達(dá)式只能引用 final 局部變量删咱,這就是說(shuō)不能在 lambda 內(nèi)部修改定義在域外的局部變量屑埋,否則會(huì)編譯錯(cuò)誤。
int count = 1;
btn.setOnClickListener(v -> {
count = 10;//編譯錯(cuò)誤
Log.e("sss","ssss")});
匿名類和Lambda表達(dá)式的區(qū)別
- 使用匿名類與 Lambda 表達(dá)式的一大區(qū)別在于關(guān)鍵詞的使用痰滋。對(duì)于匿名類摘能,關(guān)鍵詞 this 解讀為匿名類啼辣,而對(duì)于 Lambda 表達(dá)式怜姿,關(guān)鍵詞 this 解讀為寫就 Lambda 的外部類。
- Lambda 表達(dá)式與匿名類的另一不同在于兩者的編譯方法摆尝。Java 編譯器編譯 Lambda 表達(dá)式并將他們轉(zhuǎn)化為類里面的私有函數(shù)多艇,它使用 Java 7 中新加的 invokedynamic 指令動(dòng)態(tài)綁定該方法
class TestBean {
private TestInterface testInterface;
public TestBean(TestInterface testInterface) {
this.testInterface = testInterface;
}
public void test() {
if (testInterface != null) {
testInterface.test();
}
}
}
interface TestInterface {
void test();
}
private void tt() {
TestBean testBean = new TestBean(new TestInterface() {
@Override
public void test() {
System.out.println("AnonymousClass--->" + this.getClass().getName());//video.uf.com.java8test.Test2$1
}
});
testBean.test();
TestBean testBean1 = new TestBean(() -> System.out.println("Java8--->" + this.getClass().getName()));
//Java8--->video.uf.com.java8test.Test2
testBean1.test();
}
函數(shù)式接口
概念
函數(shù)式接口(Functional Interface)就是一個(gè)具有一個(gè)方法的普通接口逻恐。 @FunctionalInterface注解
特點(diǎn)
可以被隱式轉(zhuǎn)換為lambda表達(dá)式
常用的函數(shù)式接口
java.lang.Runnable
例如:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Create Thread before Java8");
}
}).start();
new Thread(()->System.out.println("Java8-------->")).start();
java.util.Comparator
例如:
List<Integer> list = new ArrayList<>();
list.add(3);
list.add(5);
list.add(4);
System.out.println("origin Data");
for(Integer item : list){
System.out.println("---->"+item);
}
System.out.println("Sorted Collection before Java8");
Collections.sort(list, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1-o2;
}
});
for(Integer item : list){
System.out.println("---->"+item);
}
list = new ArrayList<>();
list.add(3);
list.add(5);
list.add(4);
System.out.println("Sorted Collection By Java8");
Collections.sort(list, (item1,item2)->item1-item2);
for(Integer item : list){
System.out.println("---->"+item);
}
java.io.FileFilter
例如:
File files;
File[] file;
try{
files = new File("/Users/qinzongke/ShareProjects/Java8Studio/app");
file = files.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.isDirectory();
}
});
for (File item : file){
System.out.println("fileFiltertest---->"+item.getAbsolutePath());
}
file = files.listFiles(item->item.isFile());
for (File item : file){
System.out.println("fileFiltertest---->"+item.getAbsolutePath());
}
}catch (Exception e){
}
Java8新增的函數(shù)接口
java.util.function
主要分為以下幾個(gè)基本類別
Function 函數(shù)型接口 輸入?yún)?shù)為類型T, 輸出為類型R峻黍, 記作 T -> R
Consumer 消費(fèi)型接口 輸入?yún)?shù)為類型T复隆, 輸出為void, 記作 T -> void
Supplier 供給型接口 沒有輸入?yún)?shù)姆涩, 輸出為類型T挽拂, 記作 void -> T
Predicate 斷言型接口 輸入?yún)?shù)為類型T, 輸出為類型boolean骨饿, 記作 T -> boolean
static class AddNewInterface{
private BiConsumer<Integer,Integer> customer;
private BiFunction<Integer,Integer,Integer> function;
public AddNewInterface(BiFunction<Integer,Integer,Integer> function){
this.function =function;
}
public AddNewInterface(BiConsumer<Integer,Integer> customer){
this.customer = customer;
}
public void getHandler1(int value1,int value2){
if(customer != null){
customer.accept(value1,value2);
}
}
public int getHandler2(int value1,int value2){
if(function != null){
return function.apply(value1,value2);
}
return 0;
}
private void addNewInterfaceTest(){
AddNewInterface interface1 = new AddNewInterface(new BiConsumer<Integer,Integer>(){
@Override
public void accept(Integer t, Integer u) {
// TODO Auto-generated method stub
System.out.println("value1---->"+t);
System.out.println("value2---->"+u);
}
});
AddNewInterface interface2 = new AddNewInterface((value1,value2)->{
System.out.println("Java8--->value1="+value1);
System.out.println("Java8---->value2="+value2);
});
interface1.getHandler1(10,20);
interface2.getHandler1(30, 40);
AddNewInterface interface3 = new AddNewInterface(new BiFunction<Integer,Integer,Integer>(){
@Override
public Integer apply(Integer t, Integer u) {
// TODO Auto-generated method stub
return t*u;
}
});
AddNewInterface interface4 = new AddNewInterface((value1,value2)->value1+value2);
int count1 = interface3.getHandler2(10,20);
System.out.println("count1---->"+count1);
int count2 = interface4.getHandler2(10,20);
System.out.println("count2---->"+count2);
}
默認(rèn)方法
概念
默認(rèn)方法就是接口可以有實(shí)現(xiàn)方法亏栈,而且不需要實(shí)現(xiàn)類去實(shí)現(xiàn)其方法。
我們只需在方法名前面加個(gè)default關(guān)鍵字即可實(shí)現(xiàn)默認(rèn)方法宏赘。
默認(rèn)方法也可以被重寫
語(yǔ)法
例如:
interface TestInterface{
int add(int value1,int value2);
default void test2(String message){
System.out.println("TestInterface--->test2----->"+message);
}
default void test3(String message){
System.out.println("TestInterface--->test3----->"+message);
}
}
private void defaultMethodTest(){
TestInterface interface1 = (value1,value2)->value1+value2;
int count = interface1.add(10,20);
interface1.test2("aaaaa");
interface1.test3("bbbbb");
}
多個(gè)默認(rèn)方法
一個(gè)類實(shí)現(xiàn)了多個(gè)接口绒北,且這些接口有相同的默認(rèn)方法
interface TestInterface{
int add(int value1,int value2);
default void test2(String message){
System.out.println("TestInterface--->test2----->"+message);
}
default void test3(String message){
System.out.println("TestInterface--->test3----->"+message);
}
}
interface TestInterface2{
int add(int value1,int value2);
default void test2(String message){
System.out.println("TestInterface2--->test2----->"+message);
}
default void test3(String message){
System.out.println("TestInterface2--->test3----->"+message);
}
}
class TestInterfaceClass implements TestInterface,TestInterface2{
@Override
public int add(int value1, int value2) {
return value1+value2;
}
@Override
public void test2(String message) {
//方法1:創(chuàng)建自己的默認(rèn)方法,來(lái)覆蓋重寫接口的默認(rèn)方法
System.out.println("TestInterfaceClass---->"+message);
}
@Override
public void test3(String message) {
//方法2:使用 super 來(lái)調(diào)用指定接口的默認(rèn)方法
TestInterface2.super.test3(message);
}
}
靜態(tài)默認(rèn)方法
interface TestInterface{
int add(int value1,int value2);
default void test2(String message){
System.out.println("TestInterface--->test2----->"+message);
}
static void test4(String message){
System.out.println("TestInterface--->test4--->"+message);
}
default void test3(String message){
System.out.println("TestInterface--->test3----->"+message);
}
}
private void defaultStaticMethodTest(){
TestInterface.test4("defaultStaticMethodTest");
}
方法引用
作用
我們通常使用lambda表達(dá)式來(lái)創(chuàng)建匿名方法察署。然而镇饮,有時(shí)候我們僅僅是調(diào)用了一個(gè)已存在的方法
方法引用可以使語(yǔ)言的構(gòu)造更緊湊簡(jiǎn)潔,減少冗余代碼。
方法引用使用一對(duì)冒號(hào) ::
例如:
String [] arr = {"a","c","d","b"};
Arrays.sort(arr, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareToIgnoreCase(o2);
}
});//普通方式
Arrays.sort(arr,(s1,s2)->s1.compareToIgnoreCase(s2));//lambda 方式
Arrays.sort(arr,String::compareToIgnoreCase);//方法引用方式
適用場(chǎng)景: 當(dāng)一個(gè)Lambda表達(dá)式調(diào)用了一個(gè)已存在的方法
不適用場(chǎng)景: 當(dāng)我們需要引用的方法傳其它參數(shù)的時(shí)候储藐,不適合俱济,
public class MethodReferenceBean {
public static void staticMethodTest(){
System.out.println("i am static method without params");
}
public static void staticMethodTest2(MethodReferenceBean bean){
System.out.println("i am static method without params");
}
}
private void test1(){
List<MethodReferenceBean> list = new ArrayList<>();
for(int i = 0;i<10;i++){
list.add(new MethodReferenceBean());
}
list.forEach(new Consumer<MethodReferenceBean>(){
@Override
public void accept(MethodReferenceBean t) {
// TODO Auto-generated method stub
MethodReferenceBean.staticMethodTest();
}
});
list.forEach(item->MethodReferenceBean.staticMethodTest());//可以使用
list.forEach(item->MethodReferenceBean.staticMethodTest2(item));//可以使用
list.forEach(MethodReferenceBean::staticMethodTest);//不可使用
list.forEach(MethodReferenceBean::staticMethodTest2);//可以使用;
}
構(gòu)造器引用
語(yǔ)法:Class::new
一般同Supplier接口聯(lián)合使用 可自定義類似接口 目前Android最低支持的SDKApi為 24
注意:對(duì)目標(biāo)類必須存在無(wú)參的構(gòu)造方法
例如:
public class Test2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Test2 testBean1 = new Test2();//方法1
Test2 testBean2 = Test2.newInstance();//方法2
Test2 testBean3 = Test2.newInstance(Test2::new);//方法3
}
public static Test2 newInstance(Supplier<Test2> supplier){
return supplier.get();
}
public static Test2 newInstance(){
return new Test2();
}
}
- 下一步優(yōu)化
public class InstanceFactory<T> {
public static<T> T getInstance(Supplier<T> supplier){
return supplier.get();
}
}
public class Test2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Test2 testBean1 = InstanceFactory.getInstance(Test2::new);
}
}
針對(duì)構(gòu)造方法傳遞參數(shù)的情況
@FunctionalInterface
public interface InstanceFactorys<T> {
T getInstance(int param1,String param2,String param3);
}
public class Test2 {
private int id;
private String name;
private String address;
public Test2(int id, String name, String address) {
this.id = id;
this.name = name;
this.address = address;
}
public Test2() {
}
public static void main(String[] args) {
// TODO Auto-generated method stub
//InstanceFactorys函數(shù)式接口 接口內(nèi)至存在一個(gè)方法
InstanceFactorys<Test2> factorys = Test2::new;//必須存在無(wú)參的構(gòu)造方法
Test2 testBean = factorys.getInstance(1,"name","address");
System.out.println("id-->"+testBean.id);
System.out.println("name-->"+testBean.name);
System.out.println("address-->"+testBean.address);
}
}
Stream API
基本概念
本質(zhì): 對(duì)集合功能的完善,以聲明的形式操作集合钙勃,它就像SQL語(yǔ)句蛛碌,我們只需告訴流需要對(duì)集合進(jìn)行什么操作,它就會(huì)自動(dòng)進(jìn)行操作辖源,并將執(zhí)行結(jié)果交給你蔚携,無(wú)需我們自己手寫代碼。
這種風(fēng)格將要處理的元素集合看作一種流克饶, 流在管道中傳輸酝蜒, 并且可以在管道的節(jié)點(diǎn)上進(jìn)行處理, 比如篩選矾湃, 排序亡脑,聚合等。元素流在管道中經(jīng)過中間操作(intermediate operation)的處理邀跃,最后由最終操作(terminal operation)得到前面處理的結(jié)果霉咨。
例如: 獲取一批學(xué)生年齡>=20并且性別為男的同學(xué)集合并按年齡降序排列打印信息
class Student {
public String name;
public int age;
public int sex;// 1 男 2 女
public Student(String name, int age, int sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
}
/**
* 獲取學(xué)生數(shù)據(jù)源集合
* @return
*/
private List<Student> getDataSource() {
List<Student> dataSource = new ArrayList<>();
dataSource.add(new Student("test1", 5, 1));
dataSource.add(new Student("test2", 10, 2));
dataSource.add(new Student("test3", 15, 2));
dataSource.add(new Student("test4", 20, 1));
dataSource.add(new Student("test5", 5, 2));
dataSource.add(new Student("test6", 10, 1));
dataSource.add(new Student("test7", 15, 2));
dataSource.add(new Student("test8", 20, 1));
dataSource.add(new Student("test9", 25, 2));
dataSource.add(new Student("test10", 25, 1));
return dataSource;
}
/**
* Java7處理方式
*/
private void handlerJava7() {
List<Student> dataSource = getDataSource();
List<Student> newData = new ArrayList();
for (Student student : dataSource) {
if (student.age >= 20 && student.sex == 1) {
newData.add(student);
}
}
Collections.sort(newData, new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
// TODO Auto-generated method stub
return s2.age - s1.age;
}
});
for (Student s : newData) {
System.out.println("name--->"+s.name+" age------>" + s.age);
}
}
//Sql處理
select * from student where sex=1 and age >=20 order by age desc
/**
* Java8處理方式
*/
private void handlerJava8() {
List<Student> dataSource = getDataSource();
dataSource.stream().filter(s -> s.age >= 20 && s.sex == 1).sorted((s1, s2) -> s2.age - s1.age)
.collect(Collectors.toList()).forEach(s -> System.out.println("name--->"+s.name+" age--->" + s.age));
}
流的操作步驟
- 準(zhǔn)備一個(gè)數(shù)據(jù)源
- 執(zhí)行中間操作
中間操作可以有多個(gè),它們可以串連起來(lái)形成流水線拍屑。
- 執(zhí)行終端操作
執(zhí)行終端操作后本次流結(jié)束途戒,將獲得一個(gè)執(zhí)行結(jié)果
一個(gè)完整的Stream操作由零個(gè)或多個(gè)中間操作(intermediate operation)和一個(gè)結(jié)束操作(terminal operation)兩部分組成。只有執(zhí)行結(jié)束操作時(shí)僵驰,Stream定義的中間操作才會(huì)依次執(zhí)行喷斋,
從操作的返回值來(lái)看:如果返回值是Stream,那么就是惰性求值蒜茴;如果返回值不是Stream或者是void继准,那么就是及早求值。一個(gè)完整的Stream操作是有多個(gè)惰性求值和一個(gè)及早求值組成
流的獲取
- 集合 這種數(shù)據(jù)源較為常用矮男,通過stream()方法即可獲取流對(duì)象
對(duì)應(yīng)Collection接口
//獲取串形流
default Stream<E> stream() {
return StreamSupport.stream(this.spliterator(), false);
}
//獲取并形流
default Stream<E> parallelStream() {
return StreamSupport.stream(this.spliterator(), true);
}
例如
List<Integer> lists = new ArrayList<>();
Stream<Integer> stream = lists.stream();
- 數(shù)組 通過Arrays類提供的靜態(tài)函數(shù)stream()獲取數(shù)組的流對(duì)象
例如:
String[] names = {"chaimm","peter","john"};
Stream<String> stream = Arrays.stream(names);
- 值 直接將幾個(gè)值變成流對(duì)象
Stream<String> stream =Stream.of("test1","test2","test3");
- 其他
generator方法移必,返回一個(gè)無(wú)限長(zhǎng)度的Stream,其元素由Supplier接口的提供。在Supplier是一個(gè)函數(shù)接口毡鉴,只封裝了一個(gè)get()方法崔泵,其用來(lái)返回任何泛型的值,該結(jié)果在不同的時(shí)間內(nèi)猪瞬,返回的可能相同也可能不相同憎瘸,沒有特殊的要求。這種情形通常用于隨機(jī)數(shù)陈瘦、常量的 Stream幌甘,默認(rèn)是串行(相對(duì) parallel 而言)但無(wú)序的(相對(duì) ordered 而言)。
/**
* Returns an infinite sequential unordered stream where each element is
* generated by the provided {@code Supplier}. This is suitable for
* generating constant streams, streams of random elements, etc.
*
* @param <T> the type of stream elements
* @param s the {@code Supplier} of generated elements
* @return a new infinite sequential unordered {@code Stream}
*/
public static<T> Stream<T> generate(Supplier<T> s) {
Objects.requireNonNull(s);
return StreamSupport.stream(
new StreamSpliterators.InfiniteSupplyingSpliterator.OfRef<>(Long.MAX_VALUE, s), false);
}
/**
* generator 生成Stream
* 配合limit 和filter 使用 否則會(huì)無(wú)限執(zhí)行
*/
private void generatorSteam(){
Stream.generate(()->Math.random()).limit(10).forEach(item->System.out.println("--->"+item));;
}
iterate方法,其返回的也是一個(gè)無(wú)限長(zhǎng)度的Stream锅风,與generate方法不同的是酥诽,其是通過函數(shù)f迭代對(duì)給指定的元素種子而產(chǎn)生無(wú)限連續(xù)有序Stream,其中包含的元素可以認(rèn)為是:seed皱埠,f(seed),f(f(seed))無(wú)限循環(huán)肮帐。
/**
* Returns an infinite sequential ordered {@code Stream} produced by iterative
* application of a function {@code f} to an initial element {@code seed},
* producing a {@code Stream} consisting of {@code seed}, {@code f(seed)},
* {@code f(f(seed))}, etc.
*
* <p>The first element (position {@code 0}) in the {@code Stream} will be
* the provided {@code seed}. For {@code n > 0}, the element at position
* {@code n}, will be the result of applying the function {@code f} to the
* element at position {@code n - 1}.
*
* @param <T> the type of stream elements
* @param seed the initial element
* @param f a function to be applied to to the previous element to produce
* a new element
* @return a new sequential {@code Stream}
*/
public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) {
Objects.requireNonNull(f);
final Iterator<T> iterator = new Iterator<T>() {
@SuppressWarnings("unchecked")
T t = (T) Streams.NONE;
@Override
public boolean hasNext() {
return true;
}
@Override
public T next() {
return t = (t == Streams.NONE) ? seed : f.apply(t);
}
};
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
iterator,
Spliterator.ORDERED | Spliterator.IMMUTABLE), false);
}
/**
* iterate生成Stream
*/
private void iterateStream(){
Stream.iterate(2, item->item*item).filter(item->item!=0).forEach(item->System.out.println("---->"+item));
}
concat方法將兩個(gè)Stream連接在一起,合成一個(gè)Stream边器。若兩個(gè)輸入的Stream都時(shí)排序的训枢,則新Stream也是排序的;若輸入的Stream中任何一個(gè)是并行的忘巧,則新的Stream也是并行的恒界;若關(guān)閉新的Stream時(shí),原兩個(gè)輸入的Stream都將執(zhí)行關(guān)閉處理砚嘴。
/**
* Creates a lazily concatenated stream whose elements are all the
* elements of the first stream followed by all the elements of the
* second stream. The resulting stream is ordered if both
* of the input streams are ordered, and parallel if either of the input
* streams is parallel. When the resulting stream is closed, the close
* handlers for both input streams are invoked.
*
* @implNote
* Use caution when constructing streams from repeated concatenation.
* Accessing an element of a deeply concatenated stream can result in deep
* call chains, or even {@code StackOverflowException}.
*
* @param <T> The type of stream elements
* @param a the first stream
* @param b the second stream
* @return the concatenation of the two input streams
*/
public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) {
Objects.requireNonNull(a);
Objects.requireNonNull(b);
@SuppressWarnings("unchecked")
Spliterator<T> split = new Streams.ConcatSpliterator.OfRef<>(
(Spliterator<T>) a.spliterator(), (Spliterator<T>) b.spliterator());
Stream<T> stream = StreamSupport.stream(split, a.isParallel() || b.isParallel());
return stream.onClose(Streams.composedClose(a, b));
}
/**
* concat 組合生成Stream
*/
private void concatStream(){
Stream.concat(Stream.of(1,2,3),Stream.of(4,5,6)).forEach(item->System.out.println("---->"+item));
}
串行流十酣、并行流
串行流:操作由一個(gè)線程串行處理
并行流:把一個(gè)內(nèi)容分成多個(gè)數(shù)據(jù)塊,并用不同的線程分 別處理每個(gè)數(shù)據(jù)塊的流
相互轉(zhuǎn)換:對(duì)流使用parallel()方法將串行流轉(zhuǎn)換為并行流枣宫。對(duì)流使用sequential()方法將并行流轉(zhuǎn)換為串行流。
/**
* Returns an equivalent stream that is sequential. May return
* itself, either because the stream was already sequential, or because
* the underlying stream state was modified to be sequential.
*
* <p>This is an <a href="package-summary.html#StreamOps">intermediate
* operation</a>.
*
* @return a sequential stream
*/
S sequential();
/**
* Returns an equivalent stream that is parallel. May return
* itself, either because the stream was already parallel, or because
* the underlying stream state was modified to be parallel.
*
* <p>This is an <a href="package-summary.html#StreamOps">intermediate
* operation</a>.
*
* @return a parallel stream
*/
S parallel();
中間操作
中間操作負(fù)責(zé)將一個(gè)流轉(zhuǎn)換為另一個(gè)流吃环,包括 filter()(選擇與條件匹配的元素)也颤、map()(根據(jù)函數(shù)來(lái)轉(zhuǎn)換元素)、distinct()(刪除重復(fù))郁轻、limit()(在特定大小處截?cái)嗔鳎┖?sorted()翅娶。
filter
對(duì)于Stream中包含的元素使用給定的過濾函數(shù)進(jìn)行過濾操作,新生成的Stream只包含符合條件的元素
例如:
private void streamTest(){
Stream.of(1,2,2,3,3,4,4,5,5,6,6,7,8,9,10).filter(item->item%2 == 0).forEach(item->System.out.println("---->"+item));
}
distinct
返回去重的Stream
private void streamTest(){
Stream.of(1,2,2,3,3,4,4,5,5,6,6,7,8,9,10).filter(item->item%2 == 0).distinct().forEach(item->System.out.println("---->"+item));
}
sorted
返回一個(gè)排序的Stream好唯。默認(rèn)升序排列
private void streamTest(){
// Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).distinct().sorted().forEach(item->System.out.println("---->"+item));
Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).distinct().sorted((item1,item2)->item2-item1).forEach(item->System.out.println("---->"+item));
}
limit
返回前n個(gè)元素?cái)?shù)據(jù)組成的Stream竭沫。屬于短路操作
private void streamTest(){
Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).limit(10).filter(item->item%2 == 0).distinct().sorted((item1,item2)->item2-item1).forEach(item->System.out.println("---->"+item));
}
skip
返回第n個(gè)元素后面數(shù)據(jù)組成的Stream
private void streamTest(){
Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).skip(4).filter(item->item%2 == 0).distinct().sorted((item1,item2)->item2-item1).forEach(item->System.out.println("---->"+item));
}
map
對(duì)于Stream中包含的元素使用給定的轉(zhuǎn)換函數(shù)進(jìn)行轉(zhuǎn)換操作,新生成的Stream只包含轉(zhuǎn)換生成的元素骑篙。這個(gè)方法有三個(gè)對(duì)于原始類型的變種方法蜕提,分別是:mapToInt,mapToLong和mapToDouble靶端。這三個(gè)方法也比較好理解谎势,比如mapToInt就是把原始Stream轉(zhuǎn)換成一個(gè)新的Stream,這個(gè)新生成的Stream中的元素都是int類型杨名。之所以會(huì)有這樣三個(gè)變種方法脏榆,可以免除自動(dòng)裝箱/拆箱的額外消耗;
private void streamTest(){
Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).skip(4).peek(item->System.out.println("peek--->"+item)).filter(item->item%2 == 0).distinct().map(item->item*2).sorted((item1,item2)->item2-item1).forEach(item->System.out.println("---->"+item));
}
flatMap
和map類似台谍,不同的是其每個(gè)元素轉(zhuǎn)換得到的是Stream對(duì)象须喂,會(huì)把子Stream中的元素壓縮到
private void streamTest(){
Stream.of(Arrays.asList(1,2,3),Arrays.asList(4,5,6)).flatMap(item->item.stream()).map(item->item*2).forEach(item->System.out.println("flat--->"+item));
// Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).skip(4).peek(item->System.out.println("peek--->"+item)).filter(item->item%2 == 0).distinct().map(item->item*2).sorted((item1,item2)->item2-item1).forEach(item->System.out.println("---->"+item));
}
peek
生成一個(gè)包含原Stream的所有元素的新Stream,同時(shí)會(huì)提供一個(gè)消費(fèi)函數(shù)(Consumer實(shí)例),新Stream每個(gè)元素被消費(fèi)的時(shí)候都會(huì)執(zhí)行給定的消費(fèi)函數(shù)
private void streamTest(){
Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).skip(4).peek(item->System.out.println("peek--->"+item)).filter(item->item%2 == 0).distinct().sorted((item1,item2)->item2-item1).forEach(item->System.out.println("---->"+item));
}
終端操作
數(shù)據(jù)集的處理在執(zhí)行終止操作時(shí)開始坞生,比如縮減(sum() 或 max())仔役、應(yīng)用 (forEach()) 或搜索 (findFirst()) 操作。終止操作會(huì)生成一個(gè)結(jié)果或無(wú)結(jié)果
forEach
將提供的操作應(yīng)用于流的每個(gè)元素
private void streamTest(){
// Stream.of(Arrays.asList(1,2,3),Arrays.asList(4,5,6)).flatMap(item->item.stream()).map(item->item*2).forEach(item->System.out.println("flat--->"+item));
Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).skip(4).peek(item->System.out.println("peek--->"+item)).filter(item->item%2 == 0).distinct().map(item->item*2).sorted((item1,item2)->item2-item1).forEach(item->System.out.println("---->"+item));
}
toArray
使用流的元素創(chuàng)建一個(gè)數(shù)組
Integer[] arrays = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).distinct().toArray(item-> new Integer[item]);
collect
將流的元素聚合到一個(gè)匯總結(jié)果容器中恨胚。
List<Integer> array = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).distinct().collect(Collectors.toList());
Collectors
為Stream的collect提供轉(zhuǎn)換類型
toList
把流中所有元素收集到List中
返回類型: List<T>
toSet
把流中所有元素收集到Set中,刪除重復(fù)項(xiàng)
返回類型:Set<T>
Set<Integer> array = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).collect(Collectors.toSet());
toCollection
把流中所有元素收集到給定的供應(yīng)源創(chuàng)建的集合中
返回類型:Collection<T>
ArrayList array = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).collect(Collectors.toCollection(()->new ArrayList<Integer>()));
counting
計(jì)算流中元素個(gè)數(shù)
返回類型:long
long count = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).collect(Collectors.counting());
summingInt
對(duì)流中元素的一個(gè)整數(shù)屬性求和
返回類型:Integer
int count = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).collect(Collectors.summingInt(item->item));
averagingInt
計(jì)算流中元素integer屬性的平均值
返回值類型:Double
double count = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).collect(Collectors.averagingInt(item->item));
joining
連接流中每個(gè)元素的toString方法生成的字符串
返回值類型:String
String str = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).map(item->String.valueOf(item)).collect(Collectors.joining(","));
maxBy
流中按照給定比較器選出的最大元素的optional
如果為空返回的是Optional.empty()
返回值類型:Optional<T>
Optional<Integer> value = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).collect(Collectors.maxBy((item1,item2)->item1-item2));
minBy
流中按照給定比較器選出的最大元素的optional
如果為空返回的是Optional.empty()
返回值類型:Optional<T>
Optional<Integer> value = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).collect(Collectors.minBy((item1,item2)->item1-item2));
reducing
從一個(gè)作為累加器的初始值開始,利用binaryOperator與流中的元素逐個(gè)結(jié)合,從而將流歸約為單個(gè)值
返回值類型:T / Optional<T>
int value1 = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).collect(Collectors.reducing(100,(item1,item2)->item1+item2));
int value2 = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).collect(Collectors.reducing((item1,item2)->item1+item2)).get();
groupingBy
根據(jù)流中元素的某個(gè)值對(duì)流中的元素進(jìn)行分組,并將屬性值做為結(jié)果map的鍵
返回值類型:Map<K,List<T>>
List<Student> datas = getDataSource();
Map<Integer,List<Student>> data = datas.stream().collect(Collectors.groupingBy((item1)->item1.sex));
partitioningBy
根據(jù)流中每個(gè)元素應(yīng)用謂語(yǔ)的結(jié)果來(lái)對(duì)項(xiàng)目進(jìn)行分區(qū)
返回值類型:Map<Boolean,List<T>>
Map<Boolean,List<Student>> data = datas.stream().collect(Collectors.partitioningBy(item->item.sex==1));
reduce/min/max/count
作用類似Collectors中
int value1 = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).limit(3).filter(item->item%2 == 0).reduce((item1,item2)->item1+item2).get();
int value2 = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).limit(3).filter(item->item%2 == 0).reduce(100,(item1,item2)->item1+item2);
int value3 = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).max((item1,item2)->item1-item2).get();
int value4 = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).min((item1,item2)->item1-item2).get();
anyMatch/allMatch/noneMatch
有一個(gè)符合條件返回true/全部符合條件返回true/完全不符合條件返回true
List<Student> datas = getDataSource();
boolean flag1 = datas.stream().anyMatch(item->item.sex==1);
boolean flag2 = datas.stream().anyMatch(item->item.sex==2);
boolean flag3 = datas.stream().anyMatch(item->item.sex==3);
boolean flag4 = datas.stream().noneMatch(item->item.sex == 3);
boolean flag5 = datas.stream().noneMatch(item->item.sex==2);
boolean flag6 = datas.stream().allMatch(item->item.sex == 1);
findFirst/findAny
返回流的第一個(gè)元素(如果有)/返回流的任一個(gè)元素(如果有)
Student student1 = datas.stream().findFirst().get();
Student student2 = datas.stream().findAny().get();
Optional 類
Optional 類是一個(gè)可以為null的容器對(duì)象骂因。如果值存在則isPresent()方法會(huì)返回true,調(diào)用get()方法會(huì)返回該對(duì)象赃泡。
Optional 類的引入很好的解決空指針異常
class TestBean {
public TestBean1 bean1;
public TestBean(TestBean1 bean1) {
this.bean1 = bean1;
}
}
class TestBean1 {
public TestBean2 bean2;
public TestBean1(TestBean2 bean) {
this.bean2 = bean;
}
}
class TestBean2 {
public String name;
public TestBean2(String name) {
this.name = name;
}
}
private void testJava7(TestBean bean) {
if(bean != null){
if(bean.bean1!=null){
if(bean.bean1.bean2 != null){
System.out.println(bean.bean1.bean2.name);
}
}
}
}
private void testJava8(TestBean bean) {
Optional.ofNullable(bean).map(item->item.bean1).map(item->item.bean2).ifPresent(t->System.out.println(t.name));
}
創(chuàng)建Optional對(duì)象
- of
of方法通過工廠方法創(chuàng)建Optional類寒波。需要注意的是,創(chuàng)建對(duì)象時(shí)傳入的參數(shù)不能為null升熊。如果傳入?yún)?shù)為null俄烁,則拋出NullPointerException
TestBean bean = new TestBean(1,"test1",15,1);
Optional<TestBean> test = Optional.of(bean);
TestBean bean1 = null;
Optional<TestBean> test1 = Optional.of(bean1);//拋出異常 java.lang.NullPointerException
- ofNullable
為指定的值創(chuàng)建一個(gè)Optional,如果指定的值為null级野,則返回一個(gè)空的Optional.ofNullable與of方法相似页屠,唯一的區(qū)別是可以接受參數(shù)為null的情況
TestBean bean = new TestBean(1,"test1",15,1);
Optional<TestBean> test = Optional.ofNullable(bean);
TestBean bean1 = null;
Optional<TestBean> test1 = Optional.ofNullable(bean1);
isPresent
判斷Optional對(duì)象中的值是否存在,若存在返回true,否則返回false
/**
* Return {@code true} if there is a value present, otherwise {@code false}.
*
* @return {@code true} if there is a value present, otherwise {@code false}
*/
public boolean isPresent() {
return value != null;
}
Optional<String> optional1 = Optional.ofNullable("HelloWordl");
boolean flag = optional1.isPresent();
get
若Optional對(duì)象中的值存在則通過get()獲取,否則拋NoSuchElementException異常
/**
* If a value is present in this {@code Optional}, returns the value,
* otherwise throws {@code NoSuchElementException}.
*
* @return the non-null value held by this {@code Optional}
* @throws NoSuchElementException if there is no value present
*
* @see Optional#isPresent()
*/
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
Optional<String> optional = Optional.ofNullable("HelloWordl");
String str = optional.get();
ifPresent
如果 Optional 中有值蓖柔,則對(duì)該值調(diào)用 consumer.accept辰企,否則什么也不做
/**
* If a value is present, invoke the specified consumer with the value,
* otherwise do nothing.
*
* @param consumer block to be executed if a value is present
* @throws NullPointerException if value is present and {@code consumer} is
* null
*/
public void ifPresent(Consumer<? super T> consumer) {
if (value != null)
consumer.accept(value);
}
Optional<String> optional = Optional.ofNullable("HelloWordl");
String str = optional.get();
optional.ifPresent(item->System.out.println(item));
orElse
如果 Optional 中有值則將其返回,否則返回 orElse 方法傳入的參數(shù)
/**
* Return the value if present, otherwise return {@code other}.
*
* @param other the value to be returned if there is no value present, may
* be null
* @return the value, if present, otherwise {@code other}
*/
public T orElse(T other) {
return value != null ? value : other;
}
Optional<String> optional = Optional.of("HelloWorld");
System.out.println(optional.orElse("Java"));
optional = Optional.ofNullable(null);
System.out.println(optional.orElse("Java"));
orElseGet
orElseGet 與 orElse 方法的區(qū)別在于况鸣,orElseGet 方法傳入的參數(shù)為一個(gè) Supplier 接口的實(shí)現(xiàn) —— 當(dāng) Optional 中有值的時(shí)候牢贸,返回值;當(dāng) Optional 中沒有值的時(shí)候镐捧,返回從該 Supplier 獲得的值潜索。
/**
* Return the value if present, otherwise invoke {@code other} and return
* the result of that invocation.
*
* @param other a {@code Supplier} whose result is returned if no value
* is present
* @return the value if present otherwise the result of {@code other.get()}
* @throws NullPointerException if value is not present and {@code other} is
* null
*/
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
Optional<String> optional = Optional.of("HelloWorld");
System.out.println(optional.orElseGet(()->"Java"));
optional = Optional.ofNullable(null);
System.out.println(optional.orElseGet(()->"Java"));
orElseThrow
orElseThrow 與 orElse 方法的區(qū)別在于,orElseThrow 方法當(dāng) Optional 中有值的時(shí)候懂酱,返回值竹习;沒有值的時(shí)候會(huì)拋出異常,拋出的異常由傳入的 exceptionSupplier 提供
/**
* Return the contained value, if present, otherwise throw an exception
* to be created by the provided supplier.
*
* @apiNote A method reference to the exception constructor with an empty
* argument list can be used as the supplier. For example,
* {@code IllegalStateException::new}
*
* @param <X> Type of the exception to be thrown
* @param exceptionSupplier The supplier which will return the exception to
* be thrown
* @return the present value
* @throws X if there is no value present
* @throws NullPointerException if no value is present and
* {@code exceptionSupplier} is null
*/
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
Optional<String> optional = Optional.of("HelloWorld");
System.out.println(optional.orElseThrow(()->new StringNotFoundException("String Not Found")));
optional = Optional.ofNullable(null);
System.out.println(optional.orElseThrow(()->new StringNotFoundException("String Not Found")));
filter
如果有值并且滿足斷言條件返回包含該值的Optional列牺,否則返回空Optional整陌。
Optional<String> optional = Optional.of("HelloWorld");
System.out.println(optional.filter(item->item.length()>10).orElse("NotFoundString"));
map
如果有值,則對(duì)其執(zhí)行調(diào)用mapping函數(shù)得到返回值瞎领。如果返回值不為null蔓榄,則創(chuàng)建包含mapping返回值的Optional作為map方法返回值,否則返回空Optional默刚。
Optional<String> optional = Optional.of("HelloWorld");
System.out.println(optional.filter(item->item.length()>=5).map(item->item+"----->").get());
flatMap
如果有值甥郑,為其執(zhí)行mapping函數(shù)返回Optional類型返回值,否則返回空Optional荤西。flatMap與map(Funtion)方法類似澜搅,區(qū)別在于flatMap中的mapper返回值必須是Optional伍俘。調(diào)用結(jié)束時(shí),flatMap不會(huì)對(duì)結(jié)果用Optional封裝勉躺。
Optional<String> optional = Optional.of("HelloWorld");
System.out.println(optional.filter(item->item.length()>=5).map(item->item+"----->").flatMap(item->Optional.of(item)).get());