likes
comments
collection
share

你应该知道的Java8新特性之Lambda表达式

作者站长头像
站长
· 阅读数 49

Lambd表达式

Lambda表达式是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码 像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。

1. 格式

'->' :lambda操作符或箭头操作符 '->'的左边: Lambda形参列表(其实就是接口中的抽象方法的形参列表) '->'的右边: Lambda体 (其实就是 重写的抽象方法的方法体)

2. Lambda表达式的使用

Lambda表达式的使用为了方便理解,分为6种情况介绍,通过内置函数式接口来举例,也可以对比匿名函数来理解。

  1. 语法格式一:无参,无返回值,Lambda体只需一条语句
Runnable r2 = ()->{
            System.out.println("Test1");
        };
  1. 语法格式二:Lambda需要一个参数,并且无返回值
Consumer<String> con2 = (String s)->{
            System.out.println(s);
        };
        con2.accept("test2");
  1. 语法格式三:Lambda只需要一个参数时,参数的小括号可以省略,同时省略参数变量类型(类型推断)
Consumer<String> con2 = s->{
            System.out.println(s);
        };
        con2.accept("test2");
  1. 语法格式四:Lambda需要两个参数,并且有返回值
Comparator<Integer> com2 = (Integer o1,Integer o2) -> {
    return o1.compareTo(o2);
};
  1. 语法格式五:当 Lambda 体只有一条语句时,return 与大括号可以省略
Comparator<Integer> com2 = (Integer o1,Integer o2) -> o1.compareTo(o2);
  1. 语法格式五:数据类型可以省 略,因为可由编译器推断得出, 称为“类型推断
// 数据类型可以省略,因为可由编 译器推断得出, 称为“类型推断  
Comparator<Integer> com2 = (o1,o2) -> o1.compareTo(o2);

上述 Lambda 表达式中的参数类型都是由编译器推断得出的。Lambda 表达式中无需指定类型,程序依然可以编译,这是因为 javac 根据程序的上下文,在后台推断出了参数的类型。Lambda 表达式的类型依赖于上下文环境,是由编译器推断出来的。这就是所谓的“类型推断”

3. 函数式接口

3.1 什么是函数式接口

只包含一个抽象方法的接口,称为函数式接口。

你可以通过 Lambda 表达式来创建该接口的对象。(若 Lambda 表达式抛出一个受检异常,那么该异常需要在目标接口的抽象方法上进行声明)。Lambda表达式也是依赖于函数式接口的。

我们可以在任意函数式接口上使用 @FunctionalInterface 注解, 这样做可以检查它是否是一个函数式接口,同时javadoc也会包含一条声明,说明这个接口是一个函数式接口。

3.2 如何理解函数式接口

1.Java从诞生口起就是一直倡导“一切皆对象”,在Java里面面向对象(OOP)编程是一切。但是随着python、 scala等语言的兴起和新技术的挑战,Java不得不做出调整以便支持更加广泛的技术要求,也即Java不但可以支持OOP还可以支持OOF(面向函数编程)

2.在函数式编程语言当中,函数被当做一等公民对待。在将函数作为一等公民的编程语言中,Lambda表达式的类型是函数。但是在Java8中,有所不同。在Java8中,Lambda表达式是对象,而不是函数,它们必须依附于一类特别的对象类型-函数式接口。

3.简单的说,在Java8中,Lambda表达式就是一个函数式接口的实例。这就是Lambda表达式和函数式接口的关系。也就是说,只要一少对象是函数式接口的实例,那么该对象就可以用Lambda表达式来表示。

所以以前用匿名实现类表示的现在都可以用Lambda表达式来写。

3.3 自定义函数式接口

/**
这个接口里只能写一个方法,写多个方法注解会爆红,注解的作用是验证该接口是否是函数接口
若果不写该注解,并且接口只有一个方法则该接口也是函数式接口
*/
@FunctionalInterface  
public interface MyInterface { 
    void method();
}

//泛型写法
@FunctionalInterface  
public interface MyInterface<T> { 
    T method(T t);
}

3.4 Java 内置四大核心函数式接口

函数式接口参数类型返回类型用途
Consumer 消费型接口Tvoid对类型为T的对象应用操 作,包含方法:void accept(T t)
Supplier供给型接口T返回类型为T的对象,包含方法:T get();
Function<T,R>函数型接口TR对类型为T的对象应用操 作,并返回结果。结果 是R类型的对象。包含方 法:R apply(T t);
Predicate断定型接口Tboolean确定类型为T的对象是否 满足某约束,并返回 boolean 值。包含方法 boolean test(T t);

举两个简单的例子

public void test4(){
        Consume(500, new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) {
                System.out.println("消费了"+integer);
            }
        });
        //lambda表达式写法
        Consume(400,money-> System.out.println("赚了"+money));
    }

public static void Consume(int money, Consumer<Integer> consumer){
        consumer.accept(money);
}
public void test5(){
        List<String> list = Arrays.asList("sss","rrr","yyyyy","ssdasds","sd");
        list = predit(list, new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.length()>3;
            }
        });
        System.out.println(list.toString());
    	//lambda表达式写法
        List<String> list1 = Arrays.asList("12","13","14","15","16","17");
        list1 = predit(list1,i->Integer.parseInt(i)>14);
        System.out.println(list1.toString());
    }
    public static List<String> predit(List<String> strings, Predicate<String> predicate){
        List<String> list = new ArrayList<>();
        for (String s:strings){
            if (predicate.test(s)){
                list.add(s);
            }
        }
        return list;
    }

下篇预告:Stream常用的API,欢迎继续交流学习

转载自:https://juejin.cn/post/7148334544755064846
评论
请登录