Lambda表示式的基本使用方法
Lambda表示式
從JDK1.8開始為了簡化使用者進行程式碼的開發,專門提供有Lambda表示式的支援,利用此操作可以實現函式式的程式設計,對於函數語言程式設計比較著名的語言有:Haskell、Scala,利用函式式的程式設計可以避免掉面向物件程式設計之中一些繁瑣的處理問題。
範例:觀察傳統開發中的問題
package org.demo.innerclass;
interface IMessage {
public void send(String str);
}
public class JavaDemo {
public static void main(String[] args) {
IMessage i = new IMessage() {
public void send(String str) {
System.out.println(str);
}
};
i.send("www.baidu.com");
}
}
在這樣的程式裡,實際上核心的功能只有一行語句System.out.println(str),但是為了這一行的核心語句,我們仍然需要按照完整的面向物件給出的結構進行開發。於是這些問題隨著技術的發展也是越來越突出了。
範例:使用Lambda表示式實現與之前完全一樣的功能
package org.demo.innerclass;
interface IMessage {
public void send(String str);
}
public class JavaDemo {
public static void main(String[] args) {
IMessage i = (str) -> {
System.out.println(str);
};
i.send("www.baidu.com");
}
}
現在在程式碼中就十分簡潔了,只寫了關鍵語句**System.out.println(str)** ,於是利用這種形式就避免了面向物件複雜的結構化要求。這便是Lambda表示式的基本處理形式。
Lambda表示式如果要想使用,那麼必須要有一個重要的實現要求:SAM(Single Abstract Method),只有一個抽象方法,以IMessage介面為例,這個接口裡面只是提供有一個send()方法,除此之外沒有任何其他方法定義,所以這樣的介面就被稱為函式式介面,而只有函式式接口才能被Lambda表示式所使用。
範例:錯誤的定義
package org.demo.innerclass;
interface IMessage {
public void send(String str);
public void say();
}
public class JavaDemo {
public static void main(String[] args) {
IMessage i = (str) -> {
System.out.println(str);
};
i.send("www.baidu.com");
}
}
所以很多時候為了明確的標註出你是一個函式式介面,往往會在介面上面增加一行註釋@functionalInterface。但是,預設方法和靜態方法不會破壞函式式介面的定義。
所以說,之所以在JDK1.8之後提供有預設和靜態方法,也都是為函式式開發做準備。
Lambda表示式的幾種格式
· 方法沒有引數: ()->{};
·方法有引數::(引數,引數···)->{};
·如果只有一行語句返回:(引數可有可無)->語句;
下面看幾個例子:
使用Lambda表示式(無參)
package org.demo.innerclass;
@FunctionalInterface
interface IMessage {
public void send();
}
public class JavaDemo {
public static void main(String[] args) {
IMessage i = () -> {
System.out.println("www.baidu.com");
};
i.send();
}
}
使用Lambda表示式(有參)
package org.demo.innerclass;
@FunctionalInterface
interface IMath {
public int add(int x, int y);
}
public class JavaDemo {
public static void main(String[] args) {
IMath math = (t1, t2) -> { // t1,t2是形參名,隨便取
return t1 + t2;
};
System.out.println(math.add(20, 30));
}
}
以上的表示式之中你會發現只有一行語句“ return t1 + t2;”,這時候可以進一步簡化。
使用Lambda表示式簡化(再度簡化Lambda表示式,把return語句也省略)
@FunctionalInterface
interface IMath{
public int add(int x , int y);
}
public class Demo01 {
IMath math = (n1,n2)-> n1 + n2;
System.out.println(math.add(10,20));
}
}
利用Lambda表示式確實可以使得程式碼更加簡便。
方法引用
引用資料型別最大的一個特點是可以進行記憶體的指向處理,但是傳統的開發之中一直所使用的只是物件引用操作,而從JDK1.8之後也提供有方法的引用,即不同的方法名稱可以描述同一個方法。如果要進行方法的引用在Java裡面提供有如下形式:
引用靜態方法
語法格式: 類名稱::static方法名稱
在String類裡面提供有String.valueOf()方法,這方法就屬於靜態方法。
public static String valueOf(int i) 該方法有引數,還有返回值,引數的型別有很多種。
@FunctionalInterface
//P描述的引數型別,R描述的是返回值
interface IFunction<P,R>{
public R change(P p);//這裡的方法名可以使用中文定義!但是一般不這麼用
}
public class Demo01 {
public static void main(String[] args) {
IFunction<Integer,String> fun = String::valueOf;
String str = fun.change(100);
System.out.println(str.length());
}
}
引用例項化物件中的方法
語法格式: 例項化物件::普通方法;
在String類中有一個轉大寫的方法: public String toUpperCase();必須有例項化物件才能呼叫
@FunctionalInterface //函式時介面
//R描述的是返回值
interface IFunction<R>{
public R upper();
}
public class Demo01 {
public static void main(String[] args) {
IFunction<String> fun = "www.baidu.com" :: toUpperCase;
//“www.baidu.com”相當於例項化物件,然後引用toUpperCase
System.out.println(fun.upper());
}
}
在進行方法應用的時候也可以引用特定類中的一些操作方法,比如在String類中提供有一個字元創大小關係的比較:public int compareTo(String anotherString);這是一個普通方法,如果要引用普通方法,往往需要例項化物件,但是如果你現在不想給出物件,只想引用方法,則就可以使用特定類來進行引用處理。
引用特定型別的方法
語法格式: 特定類::普通方法
package org.demo.innerclass;
@FunctionalInterface
//P描述的引數型別,R描述的是返回值
interface IFunction<P>{
public int compare(P p,P p2);
}
public class JavaDemo {
public static void main(String[] args) {
IFunction<String> fun = String::compareTo;
//沒有例項化物件,直接通過String來引用
System.out.println(fun.compare("A","a"));
}
}
引用構造方法
語法格式: 類名稱::new
class Person{
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return this.name ;
}
public int getAge() {
return this.age;
}
public String toString() {
return "姓名:"+ this.name +"、年齡"+ this.age;
}
}
@FunctionalInterface //函式時介面
//R描述的是返回值
interface IFunction<R>{
public R creat(String s, int a );//根據構造方法引入create方法
//傳入兩個引數
}
public class Demo01 {
public static void main(String[] args) {
IFunction<Person> fun = Person :: new;
System.out.println(fun.creat("張三",18));
}
}
內建函式式介面
在JDK1.8之中,提供有Lambda表示式和方法引用,但是你會發現如果由開發者自己定義函式式的介面,往往都需要使用"@FunctionalInterface"來進行大量的宣告,於是很多的情況下如果為了方便則可以引用系統中提供的函式式介面。
在系統之中專門提供有一個java.util.functional的開發包,裡面可以直接使用函式式介面,在這個包下面一共有如下幾個核心的介面供我們使用。
功能型函式式介面
·在String類中有一個方法判斷是否以指定的字串開頭:public boolean startsWith(String str);
介面定義: | 介面使用: |
---|---|
@FunctionalInterface public interface Function<T,R>{ public R apply(T t); } | 如下所示 |
package org.demo.innerclass;
import java.util.function.*;
/*
@FunctionalInterface
T是引數型別
R是返回型別
public interface Function<T,R>{
public R apply(T t);
}
*/
public class JavaDemo {
public static void main(String[] args) {
//這樣就不用自己去建函式式介面了
Function<String,Boolean> fun = "**Hello" :: startsWith;//這個Function是基礎介面
//引用例項化物件的方法
System.out.println(fun.apply("**"));
}
}
消費型函式式介面
消費性函式式介面,只能進行資料的處理操作,而沒有返回值
· 在進行系統輸出的時候使用的是:System.out.println();這個操作只是進行資料的輸出和消費,而不能返回,這就是消費性介面。
介面定義 | 介面使用 |
---|---|
@FunctionalInterface public interface Consumer{ public void accept(T t){ } } | 如下 |
import java.util.function.*;
public class Demo01 {
public static void main(String[] args) {
Consumer<String> con = System.out :: println;
con.accept("www.baidu.com");
}
}
供給型函式式介面
·在String類中提供有轉小寫方法,這個方法沒有接收引數,但是有返回值 public String toLowerCase();
介面定義 | 介面使用 |
---|---|
@FunctionalInterface public interface Supplier{ public T get(); } | 如下 |
import java.util.function.*;
public class Demo01 {
public static void main(String[] args) {
Supplier <String> sup = "WWW.BAIDU.COM" :: toLowerCase;
System.out.println(sup.get());
}
}
斷言型函式處理:進行判斷處理
介面定義 | 介面使用 |
---|---|
@FunctionalInterface public interface Predicate{ public boolean test(T t); } | 如下 |
在String類中有一個cequalsIgnoreCase()方法
import java.util.function.*;
public class Demo01 {
//斷言型函式式介面
public static void main(String[] args) {
Predicate <String> pre = "baidu" :: equalsIgnoreCase;
System.out.println(pre.test("BAIDU"));
}
}
如果JDK本身提供的函式式介面可以被我們所使用,那麼就沒必要重新去定義了。