转载

Java - Lambda表达式

你之所以能优于别人,正是因为你坚持了别人所不能坚持的。

本文相关代码在我的Github,欢迎Star~

https://github.com/zhangzhibo1014/DaBoJava

Lambda

Lambda 是一个匿名函数,是一个可传递的代码块,可以在以后执行一次或多次。使用 Lambda 表达式,可以写出更加紧凑、更加简洁、更加灵活的代码。

语法

(parameters) -> expression
(parameters) -> { statements; }
(参数) -> 方法体(表达式/代码块)

使用的限制

Lambda 并不是任何地方都可以使用, Lambda 表达式需要“函数式接口”的支持。

函数式接口

接口中只有一个抽象方法的接口,称为函数式接口,可以用 @FunctionalInterface 修饰一下,这里需要注意的是:未使用 @FunctionalInterfaces 注解的接口未必就不是函数式接口,一个接口是不是函数式接口的条件只有一条,即接口中只有一个抽象方法的接口( Object 类中的方法不算)。而使用 @FunctionalInterface 注解修饰了的接口就一定是函数式接口,添加 @FunctionalInterface 注解可以帮助我们检查是否是函数式接口。

常用的函数式接口

Consumer<T> : 消费型接口(无返回值,有去无回)
         void accept(T t);
 Supplier<T> : 供给型接口
         T get();
         
 Function<T,R> : 函数型接口
        R apply(T t);
        
 Predicate<T> : 断言型接口
        boolean test(T t);
        
四大核心接口的-->扩展子接口

@FunctionalInterface
public interface Runnable {

    public abstract void run();
}

@FunctionalInterface
public interface Supplier<T> {

    T get();
}

@FunctionalInterface
public interface Consumer<T> {

    void accept(T t);
    
    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}

其他的类似,这些函数式接口都在java.util.function包下,读者可去这个包下去查询。

Lamdba表达式的重要特征

  • 可选的类型声明:不需要声明参数类型,编译器可以统一识别参数值
  • 可选的参数周围的括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
  • 可选的大括号:如果表达式体里面只有一个语句,那么你不必用大括号括起来。
  • 可选的返回关键字:如果表达式体只有单个表达式用于值的返回,那么编译器会自动完成这一步。若要指示表达式来返回某个值,则需要使用大括号。

Lambda表达式实例

1.不需要参数
    () -> 5
2.接收一个参数
    x -> x * 2
3.接收两个参数
    (int x, int y) -> x * y
    (x, y) -> x - y
4.接收一个 String 对象
    (String s) -> System.out.println(s)
/**
 * lambda表达式
 */
public class Demo {

    public static void main(String[] args) {
        Demo demo = new Demo();
        // 表达式
        Cal addCal = (x, y) ->  x + y;

        Cal subCal = (int x, int y) -> {return (x - y); };

        Cal mulCal = (x, y) -> x * y;

        Cal divCal = (int x, int y) ->  x / y;

        System.out.println("10 + 2 =" + demo.cals(10, 2, addCal));
        System.out.println("10 - 2 =" + demo.cals(10, 2, subCal));
        System.out.println("10 * 2 =" + demo.cals(10, 2, mulCal));
        System.out.println("10 / 2 =" + demo.cals(10, 2, divCal));
    }

    public static int cals(int a, int b, Cal cal) {
        return cal.calNumbers(a,b);
    }
}

interface Cal{
    int calNumbers(int a, int b);
}

方法引用

方法也是一种对象,可以通过名字来引用。不过方法引用的唯一用途是支持Lambda的简写,使用方法名称来表示Lambda。不能通过方法引用来获得诸如方法签名的相关信息。

方法引用可以通过方法的名字来引用其本身。方法引用是通过 :: 符号(双冒号)来描述的。

  • 构造器引用。语法是Class::new,或者更一般的Class< T >::new,要求构造器方法是没有参数
  • 静态方法引用。语法是Class::static_method,要求接受一个Class类型的参数
  • 特定对象的方法引用,它的语法是instance::method。要求方法接受一个参数
import java.util.function.Consumer;
import java.util.function.Supplier;

/**
 * 方法引用
 */
public class Demo1 {
    public static void main(String[] args) {
        //构造方法
        Supplier<DaBoJava> supplier = DaBoJava::new;
        System.out.println(supplier.get());
        //静态方法
        Consumer<String> consumer = DaBoJava::staticMethod;
        consumer.accept("DaBoJava");
        //对象方法
        DaBoJava daBoJava = new DaBoJava();
        Consumer<String> consumer1 = daBoJava::method;
        consumer1.accept("instance");
    }
}

class DaBoJava{
    public DaBoJava() {
    }
    public static void staticMethod(String name) {
        System.out.println(name);
    }
    public void method(String name){
        System.out.println(name);
    }
}

总结

Lambda 虽然代码看上去简洁,但是如果复杂的话还是比较难看明白的。

在学习 Lambda 的时候,我们应该清楚有哪些常见的函数式接口,并且了解相应的函数式接口的用法(参数,返回值类型)

Lambda 表达式返回的是 接口对象实例 ,如果 函数式接口的实现恰好可以通过调用一个方法来实现 ,那么我们可以使用方法引用来替代Lambda表达式

相关代码记录于 GitHub 中,欢迎各位伙伴 Star

有任何疑问 微信搜一搜 [程序猿大博] 与我联系~

如果觉得对您有所帮助,请 点赞收藏 ,如有不足,请评论或私信指正,谢谢~

原文  https://segmentfault.com/a/1190000021997778
正文到此结束
Loading...