一、简述
Lambda 表达式,也可称为闭包,它
允许把函数作为一个方法的参数 (函
数作为参数传递进方法中)
Lambda 简化了匿名内部类的形式,
可以达到同样的效果,匿名内部类在
编译之后会创建一个新的匿名内部类
出来,而 Lambda 是调用
JVM invokedynamic 指令实现的,并
不会产生新类
Lambda表达式返回的是接口对象实例
(2) 基本语法:
(参数列表) → {
方法体
};
→ 是 Lambda 运算符,英文名是
goes to
二、Lambda 表达式语法
6 种情况:
public class Test {
    public static void main(String[] args) {
        I01 i01 = () -> {
            System.out.println("无返回值、无参数");
        };
        I02 i02 = (int a) -> {
            System.out.println("无返回值,单个参数。a=" + a);
        };
        I03 i03 = (int a, int b) -> {
            System.out.println("无返回值,多个参数。a=" + a + ",b=" + b);
        };
        I04 i04 = () -> {
            System.out.println("有返回值、无参数");
            return 4;
        };
        I05 i05 = (int a) -> {
            System.out.println("有返回值,单个参数。a=" + a);
            return 5;
        };
        I06 i06 = (int a, int b) -> {
            System.out.println("有返回值,多个参数。a=" + a + ",b=" + b);
            return 6;
        };
        i01.method();
        i02.method(5);
        i03.method(5,10);
        System.out.println(i04.method());
        System.out.println(i05.method(5));
        System.out.println(i06.method(5, 10));
    }
}
interface I01 {
    void method();
}
interface I02 {
    void method(int a);
}
interface I03 {
    void method(int a, int b);
}
interface I04 {
    int method();
}
interface I05 {
    int method(int a);
}
interface I06 {
    int method(int a, int b);
} 
输出:
无返回值、无参数
无返回值,单个参数。a=5
无返回值,多个参数。a=5,b=10
有返回值、无参数
4
有返回值,单个参数。a=5
5
有返回值,多个参数。a=5,b=10
6 
 
三、函数式接口 (Functional Interface)
Java 8 为了使现有的函数更加友好地
支持 Lambda 表达式,引入了函数式
接口的概念
函数式接口本质上是一个仅有一个抽
象方法的普通接口,所以又叫 SAM 接
口 (Single Abstract Method Interface)
函数式接口在实际使用过程中很容易
出错,比如某人在接口定义中又增加
了另一个方法,则该接口不再是函数
式接口,此时将该接口转换为 Lambda
表达式会报错。为了克服函数式接口
的脆弱性,并且能够明确声明接口是
作为函数式接口的意图,Java 8增加
了**@FunctionalInterface**注解来标
注函数式接口。
使用@FunctionalInterface注解标注的
接口必须是函数式接口,也就是说该
接口中只能声明一个抽象方法,如果
声明多个抽象方法就会报错。但是默
认方法和静态方法不属于抽象方法,
因此在函数式接口中也可以定义默认
方法和静态方法
@FunctionalInterface
interface InterfaceDemo {
    void method(int a);
    static void staticMethod() {
        ...
    }
    default void defaultMethod() {
        ...
    }
} 
 
四、Lambda 表达式精简语法
① 参数类型可以省略
I02 i02 = (inta) -> {System.out.println(...);};
I02 i02 = (a) -> {System.out.println(...);};
② 假如只有一个参数,那么()括号
可以省略
I02 i02 =(a)-> {System.out.println(...);};
I02 i02 = a -> {System.out.println(...);};
③ 假如方法体只有一条语句,那么语
   句后的;分号和方法体的{}大括号可
以一起省略
I02 i02 = a ->{System.out.println(...);};
I02 i02 = a -> System.out.println(...);
④ 如果方法体中唯一的语句是 return
返回语句,那么在省略第3种情况的
   同时,return也必须一起省略
I05 i05 = a ->{return1;};
I05 i05 = a -> 1;
五、方法引用(Method Reference)
在Java 8中可以用方法引用来进一
步简化 Lambda 表达式
有时候多个 Lambda 表达式的实现
函数是一样的,我们可以封装成一
个通用方法,再通过方法引用来实
现接口
1. 方法引用语法
① 如果是实例方法:
对象名::实例方法名
② 如果是静态方法:
类名::实例方法名
③ 如果是构造方法:
类名::new
2. 实例方法引用
public class Test {
    public void eat(int a) {
        System.out.println("吃东西。" + "a=" + a);
    }
    public static void main(String[] args) {
        //Lambda表达式写法:
        Dog dog1 = (a) -> System.out.println("吃东西。" + "a=" + a);
        Cat cat1 = (a) -> System.out.println("吃东西。" + "a=" + a);
        dog1.doSomething(5);
        cat1.doSomething(5);
        //方法引用写法:
        Test test = new Test();
        Dog dog2 = test::eat;
        Cat cat2 = test::eat;
        dog2.doSomething(10);
        cat2.doSomething(10);
    }
}
@FunctionalInterface
interface Dog {
    void doSomething(int a);
}
@FunctionalInterface
interface Cat {
    void doSomething(int a);
} 
3. 构造方法引用
如果函数式接口的实现恰好可以通过
调用一个类的构造方法来实现 (比如
说接口方法与这个构造方法的参数个
数、参数类型和返回值都对的上),那
么就可以使用构造方法引用
public class Test {
    public void eat(int a) {
        System.out.println("吃东西。" + "a=" + a);
    }
    public static void main(String[] args) {
		//Lambda表达式写法:
        DogService dogService1 = (name, age) -> new Dog(name, age);
        System.out.println(dogService1.getDog("大狗", 5));
        //方法引用写法:
        DogService dogService2 = Dog::new;
        System.out.println(dogService2.getDog("二狗", 3));
    }
}
@FunctionalInterface
interface DogService {
    Dog getDog(String name, int age);
}
class Dog {
    String name;
    int age;
    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
} 
 
六、内置函数式接口
java.util.function 包下有一系列内
置函数式接口,也是 Java 8 伴随
Lambda 表达式一起推出的

/*
 * Java8 内置的四大核心函数式接口
 * 
 * Consumer<T> : 消费型接口
 * 		void accept(T t);
 * 
 * Supplier<T> : 供给型接口
 * 		T get(); 
 * 
 * Function<T, R> : 函数型接口
 * 		R apply(T t);
 * 
 * Predicate<T> : 断言型接口
 * 		boolean test(T t);
 * 
 */
public class TestLambda3 {
	
	//Predicate<T> 断言型接口:
	@Test
	public void test4(){
		List<String> list = Arrays.asList("Hello", "atguigu", "Lambda", "www", "ok");
		List<String> strList = filterStr(list, (s) -> s.length() > 3);
		
		for (String str : strList) {
			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;
	}
	
	//Function<T, R> 函数型接口:
	@Test
	public void test3(){
		String newStr = strHandler("\t\t\t 我大尚硅谷威武   ", (str) -> str.trim());
		System.out.println(newStr);
		
		String subStr = strHandler("我大尚硅谷威武", (str) -> str.substring(2, 5));
		System.out.println(subStr);
	}
	
	//需求:用于处理字符串
	public String strHandler(String str, Function<String, String> fun){
		return fun.apply(str);
	}
	
	//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;
	}
	
	//Consumer<T> 消费型接口 :
	@Test
	public void test1(){
		happy(10000, (m) -> System.out.println("每次消费:" + m + "元"));
	} 
	
	public void happy(double money, Consumer<Double> con){
		con.accept(money);
	}
} 



















