javaSE新特性——介面定義加強、Lambda表示式、方法引用
一、介面定義加強
首先我們回顧一下之前學習過的介面。讓它要求我們的介面只能夠由抽象方法、全域性常量組成。但是我們今天講解一下接口裡面除了這兩種元素以外還可以有普通方法和static方法。但是這樣的特性是在我們JDK1.8以後才有的。
1.可以使用default來定義普通方法,需要通過物件呼叫。
package com.wschase.interfaces; /** * Author:WSChase * Created:2018/12/3 */ //1.在介面中定義普通方法 //interface IMessage{ // //在介面中定義普通方法需要用到default這個關鍵字,但是它不表示 // //這個方法的許可權是default,我們不違背前面所學內容,在interface中 // //只有public這個許可權。 // public default void fun(){ // System.out.println("Heollo IMessage"); // } // public void print(); //} //class MessageImpl implements IMessage{ // @Override // public void print() { // System.out.println("Hello MessageImpl"); // } //} //public class TestDemo { // public static void main(String[] args) { // IMessage message = new MessageImpl(); // message.print(); // message.fun(); // } //}
2.可以和類裡面定義靜態方法一樣,使用static關鍵字修飾方法,定義靜態方法,這個方法可以直接由介面名字呼叫。
//2.定義static方法 interface IMessage{ //定義了普通方法 public default void fun(){ System.out.println("Hello IMessage"); } //靜態方法就和類裡面的靜態方法相似,可以直接由(類名)介面名稱呼叫 public static IMessage getInstance(){ return new MessageImpl(); } public void print(); } class MessageImpl implements IMessage{ @Override public void print() { System.out.println("Hello MessageImpl"); } } public class TestDemo{ public static void main(String[] args) { IMessage message=IMessage.getInstance(); System.out.println(message); message.print(); } }
注意:學完這個新特性,我們需要知道,當在以後面對介面的認識這種型別的問題的時候,我們需要將這個新特性也告訴別人。
二、Lambda表示式
這個也是我們java在JDK1.8以後才有的新特性。之所以會出現Lambda表示式,是因為在我們的C語言是面向過程程式設計的,而我們的Java是面向物件程式設計的。所以我們的Lambda表示式是是函數語言程式設計。
1.首先我們對比一下傳統面向物件程式設計和函數語言程式設計的區別:
面向物件程式設計:
package com.bittech.lambda; /** * Author:WSChase * Created:2018/12/3 */ interface IMessage{ public void print(); } public class TestLamda { public static void main(String[] args) { //這是我們傳統的面向物件的程式設計——>匿名物件實現介面並且建立物件 IMessage message=new IMessage() { @Override public void print() { System.out.println("這是介面中的抽象方法"); } }; message.print(); } }
函數語言程式設計:
//2.函數語言程式設計
interface IMessage{
public void print();
}
public class TestLamda{
public static void main(String[] args) {
//函數語言程式設計實現與上面一樣的功能
IMessage message= () -> System.out.println("這是介面中的抽象方法");
message.print();
}
}
上面就是我們的Lambda表示式,它就是函數語言程式設計。但是我們需要注意的是:我們的函數語言程式設計由一個前提,介面必須只有一個方法,如果有兩個方法那麼將不能使用函數語言程式設計。為了避免我們在定義介面的時候不知道我們這個介面是為了函數語言程式設計,我們又有了一個新的註解:@FunctionlInterface。
//2.函數語言程式設計
@FunctionlInterface
interface IMessage{
public void print();
}
public class TestLamda{
public static void main(String[] args) {
//函數語言程式設計實現與上面一樣的功能
IMessage message= () -> System.out.println("這是介面中的抽象方法");
message.print();
}
}
2.Lambda表示式語法
語法1:(引數)->單行語句;
語法2:(引數)->{};
例子:
////單行語句:
//interface IMessage{
// public void print();
//}
//public class TestLamda{
// public static void main(String[] args) {
// //函數語言程式設計實現與上面一樣的功能
// IMessage message= () -> System.out.println("這是介面中的抽象方法");
// message.print();
// }
//}
//多行語句:
//2.函數語言程式設計
@FunctionalInterface
interface IMessage{
public void print();
}
public class TestLamda{
public static void main(String[] args) {
//函數語言程式設計實現與上面一樣的功能
IMessage message= () -> {
System.out.println("這是介面中的抽象方法");
System.out.println("Hello World");
};
message.print();
}
}
其實Lambda表示式,就是將方法和物件連線起來了。
//直接進行計算
@FunctionalInterface
interface IMath{
public int add(int x,int y);
}
public class TestLamda{
public static void main(String[] args) {
//函式是程式設計的使用,還是輸出一句話
IMath msg= (p1, p2) -> p1+p2;
System.out.println(msg.add(10,20));
}
}
對於這個例子我們可以更加清楚的知道Lambda表示式的含義:首先左邊的IMath msg是面向物件的,這是在例項化一個物件;右邊這是在重寫方法,相當於是函式,這是面向過程的,所以這樣就很好的將函數語言程式設計和物件式程式設計結合起來了。
使用Lambda表示式注意:
Lambda表示式:
有一個大前提:介面有且僅有一個抽象方法。
- 如果實現抽象方法中如果只有一條命令,大括號就可以省略。
- 如果抽象方法的引數只有一個的時候,引數列表的括號可以省略;連個引數不可以省略。
- 如果抽象方法實現中有返回值,並且之只有一個語句,那麼這條語句的結果就是返回值。
- 標準寫法:不簡寫。
Lambda表示式:(引數列表)->{實現內容};
eg:介面 物件名=(引數列表)->{實現內容};
注意:在Lambda表示式所在的作用域下防止引數列表中的名字作用與中的其他變數的名字重複。
5.註解:FunctionInterface是為了讓我們的這個接口裡面只有一個抽象方法。它會檢查如果發現接口出現了多個抽象方法,那麼就會報錯。
三、方法引用
我們在之前的java學習中也有用到引用,但是隻有陣列、類、介面具備引用操作。這些都是可以例項化物件的。在JDK1.8以後追加了方法引用,其實引用就是起別名。
下面我們以類為例解釋什麼是引用:
(1)面向物件中呼叫方法有三種情況:
靜態方法、普通方法、構造方法,對於它們的使用我們有不同的規則:
類名稱.靜態方法
例項化物件.普通方法
類名稱.構造方法
方法引用就是將這些方法在使用的時候起一個別名,就相當於我們數學中的函式:
y=f(x):輸入自變數x,返回函式y。<–類比於方法引用–>
(1)f(x)<=>類名稱.靜態方法(這是我們需要實現的)
(2)f()<=>類名稱.靜態方法()
(3)f(x)<=>類名稱.靜態方法(引數列表)
(4)y=f(x)<=>別名=類名稱.靜態方法(引數列表)
對於我們的函式f(x)它的別名就是y,而對於我們的方法引用,是將我們呼叫方法這個過程起一個別名。
對於方法引用型別一共有以下四種形式:
(1)引用靜態方法:類名稱::static方法名稱;
(2)引用某個物件的方法:例項化物件::普通方法;
(3)引用某個特定類的方法:類名稱::普通方法;
(4)引用構造方法:類名稱::new;
package com.wschase.yinyong;
/**方法引用:
* y=f(g(z(args)))
* ()->引數
* f->{}即是執行語句
* y就相當於式return語句
* Author:WSChase
* Created:2018/12/3
*/
//注意:我們的方法引用是函式與物件接軌,但是又有個要求就是我們在使用方法引用的時候要求我們這個函式在面向物件中
//已經存在了,這個時候我們採用方法引用可以減少方法體的內容,這樣的話就將函式與物件結合起來了。
//那麼如果這個函式在我們面向物件裡面沒有,我們就需要採用Lambda表示式或者是匿名物件的方法去實現這個功能。
//方法引用的目的:覆用我們面向物件中已經實現的內容。
// //1.引用靜態方法
// //String類的valueOf()方法:將基本資料型別轉化為整型
// @FunctionalInterface
// interface IUtil<P,R>{
// public R switchPara(P p);
// }
//
//public class Testyinyong {
// public static void main(String[] args) {
//這個地方相當於是將介面中的方法進行了重寫的,只是實現的方法是方法引用。-》前提是這個方法在面向物件中已經存在的方法。
// IUtil<Integer,String> iu=String :: valueOf;//方法引用:就是將呼叫靜態方法這個過程起了個別名叫iu,並且限定了這個別名的型別
// String str=iu.switchPara(1000);//相當於呼叫了String.valueOf(1000)
// System.out.println(str.length());
// }
//}
////2.引用物件方法
//@FunctionalInterface
//interface IUtil<R>{
// public R switchPara();
//}
//public class TestDemo{
// public static void main(String[] args) {
// IUtil<String> iu="hello"::toUpperCase;//進行方法引用
// System.out.println(iu.switchPara());
// }
//}
////3.引用類中普通方法
////String有一個compareTo方法,次方法為普通方法
//@FunctionalInterface
//interface IUtil<R,P>{
// public R compare(P p1,P p2);
//}
//public class Testyinyong{
// public static void main(String[] args) {
// IUtil<Integer,String> iu=String::compareTo;
// System.out.println(iu.compare("劉","霍"));
// }
//}
////4.引用構造方法
//class Person{
// private String name;
// private int age;
// public Person(String name,int age){
// super();
// this.name=name;
// this.age=age;
// }
//
// @Override
// public String toString() {
// return "Person [name="+name+"age="+age+"]";
// }
//}
//@FunctionalInterface
//interface IUtil<R,PN,PA>{//這個括號裡面的內容是方法返回型別和引數型別
// public R createPerson(PN p1,PA p2);
//}
//public class Testyinyong{
// public static void main(String[] args) {
// IUtil<Person,String,Integer> iu=Person::new;
// System.out.println(iu.createPerson("yusima",25));
// }
//}
四、內建函式式介面
java.util.function實際上函數語言程式設計分為以下四種介面:
1.功能型函式式介面:public interface Function<T,R>R apply(T t);
2.供給型函式式介面:public interface Supplier T get();
3.消費型函式式介面:public interface Consumer void accept(T t);
4.斷言型介面:public interface Predicate boolean test(T t);
package com.wschase.neijian;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.function.Consumer;
import java.util.function.Predicate;
/**內建函式式介面
* Author:WSChase
* Created:2018/12/3
*/
////1.功能型介面(有進有出)
//public class Neijian {
// public static void main(String[] args) {
// Function<Integer,String>fun=String::valueOf;
// System.out.println(fun.apply(1000));
// }
//}
////2.供給型(無進有出)
//public class Neijian{
// public static void main(String[] args) {
// Supplier<String> sup="hello"::toUpperCase;
// System.out.println(sup.get());
// }
//}
////3.消費型(有進無出)
//public class Neijian{
// public static void main(String[] args) {
// Consumer<String> cons=System.out::println;
// cons.accept("哈嘍");
//
// }
//}
////4.斷言型(預測以什麼開始,以什麼結束)
//public class Neijian{
// public static void main(String[] args) {
// Predicate<String> pre="##jsshhd112"::startsWith;
// System.out.println(pre.test("##"));
// }
//}