Lambda属于函数式编程

为什么使用Lambda表达式

  • 避免匿名内部类定义过多
  • 可以让你的代码看起来很简洁
  • 去掉一堆没有意义的代码,只留下核心的逻辑

函数式接口

JDK 1.8 新增加的函数接口:java.util.function

函数式接口的定义:任何接口,如果只包含唯一一个抽象方法,那么他就是一个函数式接口。

使用@FunctionalInterface注解可以检测该接口是否为函数式接口

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}

java.util.function 它包含了很多类,用来支持 Java 的 函数式编程,该包中的函数式接口主要有:

四大核心函数式接口

函数式接口

参数类型

返回类型

用途

Consumer

消费型接口

T

void

对类型为T的对象应用操作,包含方法:void accept(T t)

Supplier

供给型接口


T

返回类型为T的对象,包含方法:T get()

Function<T, R>

函数型接口

T

R

对类型为T的对象应用操作,并返回结果。结果是R类型的对象。包含方法:R apply(T t)

Predicate

断定型接口

T

boolean

确定类型为T的对象是否满足某约束,并返回boolean 值。包含方法:boolean test(T t)

其他接口

函数式接口

参数类型

返回类型

用途

BiFunction<T, U, R>

T, U

R

对类型为 T, U 参数应用操作,返回 R 类型的结

UnaryOperator

(Function子接口)

T

T

对类型为T的对象进行一元运算,并返回T类型的结果。包含方法为:T apply(T t);

BinaryOperator
(BiFunction子接口)

T, T

T

对类型为T的对象进行二元运算,并返回T类型的结果。包含方法为: T apply(T t1, T t2);

BiConsumer<T, U>

T, U

void

对类型为T, U 参数应用操作。包含方法为: void accept(T t, U u)

BiPredicate<T,U>

T,U

boolean

包含方法为: boolean test(T t,U u)

ToIntFunction

ToLongFunction

ToDoubleFunction

T

int

long

double

分别计算int、long、double值的函数

IntFunction

LongFunction

DoubleFunction

int

long

double

R

参数分别为int、long、double 类型的函数

Lambda表达式

学习Lambda表达式,需要理解函数式接口(Function Interface)

对于函数式接口,我们可以通过lambda表达式来创建该接口的对象

Consumer consumer = (o)-> System.out.println(o);

看到现在不是还有点懵,没关系,我们来看看jdk8之前我们怎么实现一个接口的,Lambda是怎么慢慢简化来的

//1.实现类
public class MyConsumer implements Consumer{
    public void accept(Object o) {
        System.out.println(o);
    }
}

public class TestLambda1{
    //2.静态内部类
    static class MyConsumer implements Consumer{

        @Override
        public void accept(Object o) {
            System.out.println(o);
        }
    }
    public static void main(String [] args){
        //3.局部内部类
        class MyConsumer implements Consumer{
            public void accept(Object o) {
                System.out.println(o);
            }
        }
       	//4.匿名内部类
        Consumer MyConsumer = new Consumer() {
            @Override
            public void accept(Object o) {
                System.out.println(o);
            }
        };
        //5.Lambda表达式
        Consumer MyConsumer1 = (o) -> System.out.println(o);
    }
}

从1-5可以看出,接口的实现类慢慢从外部到内部,然后到局部,从一开始的多行代码,到最后简单的一行代码解决,可以看出Lambda表达式就是为了简化代码,去掉一堆没有意义的代码,只留下核心的逻辑,但是用Lambda写出来的代码虽然简洁,但是对于阅读来说不够友好

接下来我们看一下Lambda的几种情景和写法

public class TestLambda2{
	public static void main(String [] args){
        Consumer consumer = null;
       
        //情况1:无参无返回,一行代码,省去大括号
        Runnable run = () -> System.out.println("Runnable接口");
        //情况2:无参无返回,多行代码
        Runnable run1 = () -> {
            System.out.print("Runnable");
            System.out.println("接口");
        };
        //情况3:一个参数,无返回
        //写法1
        consumer = (Object o) -> System.out.println(o);
        //写法2:数据类型可以省略,因为可由编译器推断得出,称为“类型推断”
        consumer = (o) -> System.out.println(o);
        //写法3:若只需要一个参数时,参数的小括号可以省略,多个参数不能省去小括号
        consumer = o -> System.out.println(o);
        
        //情况4:两个或以上的参数,多条执行语句,并且可以有返回值
        Comparator<Integer> com1 = (o1,o2) -> {
            System.out.println(o1);
            System.out.println(o2);
            return o1.compareTo(o2);
        };
        
        //情况5:当 Lambda 体只有一条语句时,return 与大括号若有,都可以省略
        Comparator<Integer> com2 = (o1,o2) -> o1.compareTo(o2);
    
    }
}

注意

Java 8 在类型推测方面有了很大的提高,这就使代码更整洁,不需要太多的强制类型转换了。

首先,在Lambda中去掉参数类型,是类型推测的一种,还有其他常用的如下例子

//原
ArrayList<String> list = new ArrayList<String>();
//类型推断
ArrayList<String> list = new ArrayList<>();

//原
int[] arr = new int[]{1,2,3};
//类型推断
int[] arr = {1,2,3};