Lambda的簡介
Java 8的一個大亮點是引入Lambda表達式,使用它設計的代碼會更加簡潔。當開發者在編寫Lambda表達式時,也會隨之被編譯成一個函數式接口。下面這個例子就是使用Lambda表達式代替匿名內部類,代碼簡單且可讀
沒有使用Lambda表達式的匿名內部類:
@Test
public void test1() {
Comparator<Integer> com = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1, o2);
}
};
TreeSet<Integer> ts = new TreeSet<>(com);
}
使用Lambda表達式後:
//Lambda表達式
@Test
public void test2() {
Comparator<Integer> com = (x,y) -> Integer.compare(x, y);
}
是不是感覺寫起來簡單了許多,下來我們就學習一下這種新的語法格式,首先我們要先知道什麼是函數式接口
函數式接口(Functional Interfaces):如果一個接口定義個唯一一個抽象方法,那麼這個接口就成爲函數式接口。同時,引入了一個新的註解:@FunctionalInterface。可以把他它放在一個接口前,表示這個接口是一個函數式接口。這個註解是非必須的,只要接口只包含一個方法的接口,虛擬機會自動判斷,不過最好在接口上使用註解 @FunctionalInterface 進行聲明。在接口中添加了 @FunctionalInterface 的接口,只允許有一個抽象方法,否則編譯器也會報錯。
例:
@FunctionalInterface
public interface MyFunction2<R, T> {
public R getValue(T t1, T t2);
}
Lambda表達式:可以讓你的代碼更加的簡潔。Lambda無法單獨出現,需要一個函數式接口來盛放,可以說lambda表達式方法體是函數式接口的實現,lambda實例化函數式接口,可以將函數作爲方法參數,或者將代碼作爲數據對待。
Java8引入新的操作符 "->" 箭頭操作符 或 Lambda操作符
左側:Lambda表達式參數列表
右側:Lambda表達式所需執行的功能 即Lambda體
Lambda對接口的操作實例
public class TestLambda2 {
// 無參,無返回值
// () -> System.out.println("hello lambda");
@Test
public void test1() {
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("hello world!");
}
};
r1.run();
System.out.println("-------------");
Runnable r2 = () -> System.out.println("hello lambda");
r2.run();
}
// 有一個參數 且無返回值
// (x) -> System.out.println(x);
@Test
public void test2() {
Consumer<String> c = (x) -> System.out.println(x);
c.accept("hello xiaohui");
}
/**
* 有兩個以上的參數,有返回值
*/
public void test3() {
Comparator<Integer> com = (x, y) -> {
System.out.println("函數式接口");
return Integer.compare(x, y);
};
}
/**
* 有兩個以上的參數,有返回值 只有一條語句 參數列表的數據類型可以省略不寫 JVM有類型推斷功能
*/
public void test4() {
Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
}
// 對一個數進行運算
@Test
public void test5() {
Integer num = operation(100, (x -> x * x));
System.out.println(num);
}
private Integer operation(Integer num, MyFun mf) {
return mf.getValue(num);
}
在Java8中提供了四大核心接口
Consumer<T>:消費型接口 void accept(T t);
// Consumer<T> 消費型接口:
@Test
public void test1() {
happy(1000, (m) -> System.out.println("腿腿喜歡老虎機,每次都輸" + m + "元"));
}
public void happy(double money, Consumer<Double> con) {
con.accept(money);
}
Supplier<T>:供給型接口 T get();
// Supplier<T> 供給型接口:
@Test
public void test2() {
List<Integer> numList = getNumList(10, () -> (int)(Math.random()*100));
for (Integer num : numList) {
System.out.println(num);
}
}
// 產生指定個數的整數,並放入集合中
public List<Integer> getNumList(int num, Supplier<Integer> sup) {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < num; i++) {
Integer n = sup.get();
list.add(n);
}
return list;
}
Function<T,R>:函數型接口 R apply(T t);
//Function<T,R> 函數型接口:
@Test
public void test3() {
String strHandler = strHandler("\t\t\t hello xiaohui ", (str) -> str.trim());
System.out.println(strHandler);
String upper = strHandler("xiaohui", (str) -> str.toUpperCase());
System.out.println(upper);
String newstr = strHandler("代虎虎是個二傻子", (str) -> str.substring(5, 8));
System.out.println(newstr);
}
//用於處理字符串
public String strHandler(String str, Function<String, String> fun) {
return fun.apply(str);
}
Predicate<T>:斷言型接口 boolean test(T t);
//Predicate<T> 斷言型接口:
@Test
public void test4() {
List<String> list = Arrays.asList("hello","xiaohui","java","www");
List<String> string = filterStr(list, (s) -> s.length() > 3);
for (String str : string) {
System.out.println(str);
}
}
//將滿足條件的字符串添加到集合中
public List<String> filterStr(List<String> list,Predicate<String> pre){
List<String> strList = new ArrayList<>();
for (String str : list) {
if(pre.test(str)) {
strList.add(str);
}
}
return strList;
}
Lambda對方法的引用
一:方法引用:若Lambda體中的內容有方法已經實現了,我們可以使用"方法引用"
(可以理解爲方法引用是Lambda 表達式的另外一種表現形式)
主要有三種語法格式:
對象::實例方法名
類::靜態方法名
類::實例方法名
// 類::靜態方法名
@Test
public void test4() {
BiPredicate<String, String> bp = (x,y) -> x.equals(y);
BiPredicate<String, String> bp1 = String::equals;
}
// 類::靜態方法名
@Test
public void test3() {
Comparator<Integer> com = (x,y) -> Integer.compare(x, y);
Comparator<Integer> com1 = Integer::compare;
int compare = com1.compare(100, 200);
System.out.println(compare);//-1
}
// 對象::實例方法名
@Test
public void test1() {
PrintStream ps1 = System.out;
Consumer<String> con1 = (x) -> ps1.println(x);
PrintStream ps2 = System.out;
Consumer<String> con2 = ps2::println;
Consumer<String> con3 = System.out::println;
con3.accept("asdfg");
}
注意:
①Lambda 體中調用方法的參數列表與返回值類型,要與函數式接口中抽象方法的函數列表和返回值類型保持一致!
②若Lambda參數列表中的第一個參數是 實例方法的調用者,而第二個參數是實例方法的參數時,可以使用ClassName::method
Lambda對構造器引用
格式:
ClassName::new
注意:需要調用的構造器的參數列表要與函數式接口中抽象方法的參數列表保持一致!
//構造器引用
@Test
public void test5() {
Supplier<Emploee> sup = () -> new Emploee();
//構造器引用方式 無參
Supplier<Emploee> sup2 = Emploee::new;
Emploee emploee = sup2.get();
System.out.println(emploee);
}
Lambda數組引用
//數組引用
@Test
public void test7() {
Function<Integer, String[]> fun = (x) -> new String[x];
String[] strs = fun.apply(10);
System.out.println(strs.length);
Function<Integer, String[]> fun2 = String[]::new;
String[] strs2 = fun2.apply(20);
System.out.println(strs2.length);
}