函數式接口
函數式接口:
有且僅有一個抽象方法的接口(可以有其他方法)
@FunctionalInterface註解:
和Override用法基本相同,此註解可以用於任何接口,表示函數式接口,加了註解編譯器會自動檢是否有且僅有一個抽象函數。不加註解滿足函數式接口的條件也是函數式接口
自定義函數式接口:
@FunctionalInterface
interface IB {
int sub(int a,int b);
}
public class 有參有返回值 {
public static void main(String[] args) {
fun(new IB() {
@Override
public int sub(int a,int b) {
System.out.println("有參有返回值-匿名內部類");
return a + b;
}
},10,20);
fun((a,b)->{
System.out.println("有參有返回值-lambda表達式");
return a + b;
},10,20);
}
public static void fun(IB ib,int x,int y) {
System.out.println(ib.sub(x, y));
}
}
函數式編程
Lambda的應用_執行延遲:
計算完數據再去判斷是否執行和先判斷是否執行再計算數據,如果先計算就會浪費資源,
讓計算的部分先交給接口,然後判斷條件,如果滿足在進行計算。
@FunctionalInterface
interface IA {
String s();
}
public class 執行延遲 {
public static void main(String[] args) {
String s1 = "我";
String s2 = "愛";
String s3 = "你";
fun(2,()->s1 + s2 + s3);
}
public static void fun(int level,IA ia) {
if (level == 1) {
System.out.println(ia.s());
}
}
}
Lambda的應用_作爲參數和返回值:
@FunctionalInterface
interface IC{
void show();
}
public class 作爲返回值 {
public static void main(String[] args) {
fun1(()-> System.out.println("作爲參數"));
fun2().show();
}
//作爲參數
public static void fun1(IC ic) {
ic.show();
}
//作爲返回值
public static IC fun2() {
return () -> System.out.println("作爲返回值");
}
}
方法引用
所謂“方法引用”就是:使用現有的方法,來代替實現的Lambda。
替代規則:
“替代的方法”的形參、返回值類型,必須與被替換的"函數式接口”中抽象
方法的一致。
靜態方法替代Lambda:
可以是自定義靜態方法,也可以是類庫中的靜態方法,只要這個靜態方法和函數式接口中的抽象方法一樣,(參數和返回值類型一致)就可以替代,語法 ::(雙冒號)
@FunctionalInterface
interface IA{
void show();
}
public class 自定義方法替代Lambda {
public static void main(String[] args) {
//使用Lambda表達式
fun(()-> System.out.println("使用Lambda表達式"));
//使用自定義方法替代Lambda表達式
fun(自定義方法替代Lambda::s);
}
public static void fun(IA ia) {
ia.show();
}
public static void s() {
System.out.println("自定義靜態方法替代Lambda");
}
}
對象成員方法替代:
首先創建對象,替換格式 對象名::方法名。返回值類型和參數一致
使用this本類方法:
@FunctionalInterface
interface Game{
public void run();
}
class Student{
public void playGame(Game game) {
System.out.println("我開始打遊戲:");
game.run();
}
public void show(){
// playGame(() -> System.out.println("我喜歡打羽毛球...."));
playGame(this::ymq);
}
public void ymq(){
System.out.println("我喜歡打羽毛球....");
}
}
public class Demo {
public static void main(String[] args) {
Student stu = new Student();
stu.show();
}
}
使用super父類方法:
要有繼承關係
@FunctionalInterface
interface Game{
public void run();
}
class Fu{
public void like(){
System.out.println("我喜歡喝啤酒(我是父親)....");
}
}
class Student extends Fu{
public void playGame(Game game) {
System.out.println("我開始打遊戲:");
game.run();
}
public void show(){
//1.使用Lambda
playGame(() -> System.out.println("我喜歡喝啤酒...."));
//2.使用父類的like方法代替Lambda表達式
playGame(super::like);//使用父類的like方法代替Lambda表達式
}
}
public class Demo {
public static void main(String[] args) {
Student stu = new Student();
stu.show();
}
}
類的構造器引用:
@FunctionalInterface
interface ID {
Cat getCat();
}
interface IE{
Cat getCat(String name);
}
class Cat {
public String name;
public Cat() {
}
public Cat(String name) {
this.name = name;
}
public void eat() {
System.out.println("小貓吃魚");
}
public void pao() {
System.out.println(name+"在跑");
}
}
public class 類的構造器引用 {
public static void main(String[] args) {
//Lambda表達式
fun(() -> new Cat());
//類的構造器替代(無參)
fun(Cat::new);
//類的構造器替代(有參)
fun2(Cat::new,"大花貓");
}
public static void fun(ID id) {
id.getCat().eat();
}
public static void fun2(IE ie,String name) {
ie.getCat(name).pao();
}
}
數組構造器引用:
@FunctionalInterface
interface IA{
public int[] getArr(int len);
}
public class Demo {
public static void main(String[] args) {
//2.使用Lambda
fun((int len)->{return new int[len];},10);
//3.使用數組的構造器代替:Lambda
fun(int[]::new,15);
}
public static void fun(IA a,int len){
int[] arr = a.getArr(len);
System.out.println(arr.length);
}
}
常用函數式接口;
生產者接口_Supplier接口
1).生產者結果:只生產數據,不接收參數
public static void main(String[] args) {
fun1(()->10);
fun2(()->"hello");
}
public static void fun1(Supplier<Integer> ia) {
Integer a = ia.get();
System.out.println(a);
}
public static void fun2(Supplier<String> is) {
String s = is.get();
System.out.println(s);
}
消費者接口_Consumer接口_抽象方法accept
1).消費接口,只接受參數,無返回值;
public static void main(String[] args) {
fun((String s)-> System.out.println(s),"hello");
}
public static void fun(Consumer<String> cs,String s) {
cs.accept(s);
}
Consumer接口_默認方法andThen
作用:將兩個Consumer對象的accept()方法的結果連在一起
源碼:
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
例子:消費一個數據的時候,先調用第一個參數的accept,然後調用第二個參數的accept
實現兩個組合
public static void main(String[] args) {
fun((String s)-> System.out.println("第一個:"+s),(String s)-> System.out.println("第二個:"+s),"hello");
}
public static void fun(Consumer<String> cs1, Consumer<String> cs2, String s) {
cs1.andThen(cs2).accept(s);
}
andThen返回一個Consumer類型, 重寫的accept方法的方法體是
accept(t); after.accept(t);,先調用第一個accept再調用第二個accept,對應的就是方法調用處的第一個參數和第二個參數,也就是執行兩個Consumer對象重寫的accept方法