Lambda表达式
1.Lambda表达式简介
1.1.什么是Lambda表达式
Lambda是Java 8添加的一个新特性.说白了,Lambda就是匿名函数
1.2.为什么要使用Lambda?
使用Lambda表达式可以对接口进行非常简洁的实现
package com.Lambda;
public class Program {
public static void main(String[] args) {
/**
* 2. 使用匿名内部类
*/
Comparator comparator2 = new Comparator(){
@Override
public int comparator(int a, int b) {
return a-b;
}
};
//3. 使用Lambda表达式
Comparator comparator3 = (a,b) -> a-b;
}
}
/**
* 1. 接口的实现类,Comparator comparator1 = new MyComparator();
*/
class MyComparator implements Comparator{
@Override
public int comparator(int a, int b) {
return a-b;
}
}
interface Comparator{
int comparator(int a,int b);
}
1.3.Lambda对接口的要求
虽然可以使用Lambda表达式对某些接口进行简单的实现,但是并不是所有的接口都可以用Lambda表达式来实现.要求接口中定义的必须要实现的抽象方法只能是一个
在Java8对接口加了一个新的特性: default ,可以对方法进行默认实现;对Lambda的实现没有影响
@FunctionalInterface
用来修饰函数式接口的,接口中的抽象方法只有一个
2.Lambda表达式基础语法
首先创建若干个接口
package interfaces;
@FunctionalInterface
public interface LambdaNoneReturn {
void test();
}
package interfaces;
@FunctionalInterface
public interface LambdaNoneReturnSingleParameter {
void test(int a);
}
package interfaces;
@FunctionalInterface
public interface LambdaNoneReturnMutipleParameter {
void test(int a,int b);
}
package interfaces;
@FunctionalInterface
public interface LambdaReturnNoneParameter {
int test();
}
package interfaces;
@FunctionalInterface
public interface LambdaSingleReturnParameter {
int test(int a);
}
package interfaces;
@FunctionalInterface
public interface LambdaMutipleReturnParameter {
int test(int a,int b);
}
Lambda基础语法
Lambda是个匿名函数,普通函数要有返回值类型 、方法名、参数列表、方法体;而对于Lambda来说我们关心的是参数列表和方法体
( ) : 用来描述参数列表
-> : lmbda运算符号 ,读作goes to
{ } : 用来描述方法体
package lmbdaSyntax;
import interfaces.LambdaNoneReturn;
public class Sytax1 {
public static void main(String[] args) {
//无参无返回
LambdaNoneReturn l1 = () -> {System.out.println("hello world");};
l1.test();
//单参无返回
LambdaNoneReturnSingleParameter l2 = (int a) -> {System.out.println(a);};
l2.test(100);
//多参无返回
LambdaNoneReturnMutipleParameter l3 = (int a,int b) -> {System.out.println(a+b);};
l3.test(10, 15);
//无参有返回
LambdaReturnNoneParameter l4 = () ->{return "Hello world"; };
String str = l4.test();
//单参有返回
LambdaSingleReturnParameter l5 =(int a) ->{
System.out.println(a);
return a;
};
l5.test(100);
//多参有返回
LambdaMutipleReturnParameter l6 = (int a,int b) -> {
System.out.println(a+b);
return a+b;
};
l6.test(6, 13);
}
}
3.Lambda表达式语法精简
- 参数: 由于在接口的抽象方法中,已经定义了了参数的数量和类型,所以在Lmbda表达式中,参数可以省略类型
备注 : 如果需要省略类型,则每个参数的类型都要省略
LambdaNoneReturnMutipleParameter lambda1 = (a, b) -> {
System.out.println(a+b);
};
- 参数小括号: 如果参数列表中,参数的数量只有一个,此时小括号可以省略
LambdaNoneReturnSingleParameter lambda2 = a -> {
System.out.println(a);
};
- 方法大括号: 方法体中只有条语句的情况下大括号可以省略
LambdaNoneReturnMutipleParameter lambda3 = (a,b) -> System.out.println("hello world");
- 返回值: 如果方法体中唯一的一条语句是一个返回值,则在省略掉大括号的同时,也必须省略掉return
LambdaReturnNoneParameter lambda4 = () -> "hello world";
LambdaMutipleReturnParameter lambda5 =(a,b) -> a+b;
4.Lambda表达式语法进阶
方法引用: 可以快速的将一个Lambda表达式的实现,指向一个已经实现的方法
语法 :方法的隶属者(类,或者对象)::方法名
注意:
- 参数数量和类型一定要和接口中定义的方法一致
- 返回值的类型一定要和接口中定义的方法一致
package lmbdaSyntax;
import interfaces.LambdaMutipleReturnParameter;
public class Sytax3 {
public static void main(String[] args) {
//这样会造成冗余,我们可以对(a,b) -> a+b进行封装
LambdaMutipleReturnParameter Lambda1 = (a,b) -> a+b;
LambdaMutipleReturnParameter Lambda2 = (a,b) -> a+b;
//封装后变成这样
LambdaMutipleReturnParameter Lambda3 = (a,b) -> change( a, b);
/**
* 等价于
* 方法引用 : 引用了change方法的实现
*/
LambdaMutipleReturnParameter Lambda4 =Sytax3::change;
int test = Lambda4.test(1, 2);
}
private static int change(int a,int b){
return a+b;
}
}
构造方法的引用:
package Data;
public class Person {
public String name;
public int age;
public Person(){
System.out.println("无参");
}
public Person(String name,int age){
this.name = name;
this.age =age;
System.out.println("带参");
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
package lmbdaSyntax;
import Data.Person;
public class Sytax4 {
public static void main(String[] args) {
PersonCreater p1 = ()-> {
return new Person();
};
PersonCreater p2 = ()-> new Person();
//构造方法的引用
PersonCreater p3 = Person :: new;
Person person = p3.getPerson();
/**
* 具体引用有参还是无参根据接口中的参数而定
*/
PersonCreater2 p4 = Person :: new;
Person person2 = p4.getPerson("小明",10);
}
}
interface PersonCreater{
Person getPerson();
}
interface PersonCreater2{
Person getPerson(String name,int age);
}
5.Lambda表达式案例
package exercise;
import java.util.ArrayList;
import Data.Person;
public class Exercise1 {
//集合排序:
//ArrayList<>
public static void main(String[] args){
// 需求:已知在一个ArrayList中有若个Person对象,将这些Person对象按照年龄进行降序排序
ArrayList<Person> list = new ArrayList<>();
list.add(new Person("小明",10));
list.add(new Person("小红",11));
list.add(new Person("小张",12));
list.add(new Person("小王",12));
list.add(new Person("小李",14));
list.add(new Person("小刚",15));
list.sort((o1,o2) ->{
return o2.age-o1.age;
});
list.sort((o1,o2) -> o2.age-o1.age);
System.out.println(list);
}
}
package exercise;
import java.util.TreeSet;
import Data.Person;
public class Exercise2 {
//set排序:
//TreeSet<>
public static void main(String[] args){
/*TreeSet<Person> set = new TreeSet<>();
set.add(new Person("小明",10));
set.add(new Person("小红",11));
set.add(new Person("小张",12));
set.add(new Person("小王",13));
set.add(new Person("小李",14));
set.add(new Person("小刚",15));*/
//java.lang.ClassCastException: Data.Person cannot be cast to java.lang.Comparable
//System.out.println(set);
/**
* 使用Lambda表达式来实现Comparable接口,并实例化一个TreeSet对象
*/
TreeSet<Person> set2 = new TreeSet<>((o1,o2) -> {
if(o1.age>=o2.age){
return -1;
}else{
return 1;
}
});
set2.add(new Person("小明",10));
set2.add(new Person("小红",11));
set2.add(new Person("小张",12));
set2.add(new Person("小王",12));
set2.add(new Person("小李",14));
set2.add(new Person("小刚",15));
System.out.println(set2);
}
}
package exercise;
import java.util.ArrayList;
import java.util.Collections;
public class Exercise3 {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
Collections.addAll(list, 1,2,3,4,5,6,7,8,9,0);
// 将集合中的每个元素都带入到方法accept中
//list.forEach(System.out::println);
//遍历集合中所有的偶数
list.forEach(ele -> {
if(ele%2==0){
System.out.println(ele);
}
});
list.sort((o1,o2) -> o1-o2);
System.out.println(list);
}
}
package exercise;
import java.util.ArrayList;
import java.util.Iterator;
import Data.Person;
public class Exercise4 {
//删除元素
public static void main(String[] args){
ArrayList<Person> list = new ArrayList<>();
list.add(new Person("小明",10));
list.add(new Person("小红",11));
list.add(new Person("小张",12));
list.add(new Person("小王",13));
list.add(new Person("小李",14));
list.add(new Person("小刚",15));
//使用迭代器
Iterator<Person> listIterator = list.iterator();
while (listIterator.hasNext()) {
Person ele = listIterator.next();
if(ele.age>10){
listIterator.remove();
}
}
//使用Lambda
list.removeIf(ele -> ele.age>10);
System.out.println(list);
}
}
package exercise;
public class Exercise5 {
public static void main(String[] args) {
new Thread(() -> {
System.out.println("创建线程");
}).start();
}
}
6.系统内置函数式接口
常用的函数式接口
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t); //参数T 返回值boolean
}
@FunctionalInterface
public interface Consumer<T> {
void accept(T t); //参数T 返回值void
}
@FunctionalInterface
public interface Function<T, R> {
R apply(T t); //参数T 返回值R
}
@FunctionalInterface
public interface Supplier<T> {
T get(); //无参 返回值T
}
了解
@FunctionalInterface
public interface UnaryOperator<T> extends Function<T, T> {
static <T> UnaryOperator<T> identity() {
return t -> t; //参数T 返回值T
}
}
@FunctionalInterface
public interface BiFunction<T, U, R> {
R apply(T t, U u);
}
@FunctionalInterface
public interface BinaryOperator<T> extends BiFunction<T,T,T> { // 参数T, T 返回值T
public static <T> BinaryOperator<T> minBy(Comparator<? super T> comparator) {
Objects.requireNonNull(comparator);
return (a, b) -> comparator.compare(a, b) <= 0 ? a : b;
}
public static <T> BinaryOperator<T> maxBy(Comparator<? super T> comparator) {
Objects.requireNonNull(comparator);
return (a, b) -> comparator.compare(a, b) >= 0 ? a : b;
}
7.闭包
package closure;
import java.util.function.Supplier;
public class ClosureDemo {
public static void main(String[] args) {
int n = getNumber().get();
System.out.println(n); //打印了10
/*
* 思考:为什么打印10,方法结束[getNumber()]局部变量应该被销毁
* num在方法结束时,不会被销毁
*/
}
private static Supplier<Integer> getNumber(){
int num =10;
//用方法把变量包裹起来就叫闭包;闭包会提升包裹变量的声明周期;我们可以闭包来获得某一方法的局部变量
return () -> {
return num;
};
}
}
package closure;
import java.util.function.Consumer;
public class ClosureDemo2 {
public static void main(String[] args) {
int a =10;
Consumer<Integer> c =ele -> {
//Local variable a defined in an enclosing scope must be final or effectively final
System.out.println(a++);
};
c.accept(a);
/**
* 如果你在闭包中使用了局部变量,那么默认用final修饰,使其成为常量(无法修改)
* final int a =10;
*/
}