Java Lambda表达式

目录

1. 什么是函数式接口(FunctionalInterface)。

2.  Lambda 表达式和普通写法的对比

3. 什么时候使用Lambda 表达式

4. Lambda 表达式的写法

 5. Java中双冒号(::)和箭头号(->)的区别


Java Lambda 表达式(也称为匿名函数,也就是写函数方法时,没有方法名,只有方法入参和方法体)是 Java 8 引入的一个新特性,它允许你以更简洁的方式表示一个函数式接口的实例。Lambda 表达式可以替代匿名内部类,使代码更加简洁和易读。
Lambda 表达式的出现是用来简化实现函数式接口(注解 @FunctionalInterface)。

1. 什么是函数式接口(FunctionalInterface)。

Java中的函数式接口(Functional Interface)是一个特殊的接口,它只包含一个抽象方法(从Java 8开始,也可以包含默认方法和静态方法,但只能有一个抽象方法,不包括Object类中的方法)。函数式接口的主要用途是与Lambda表达式和方法引用一起使用,以支持函数式编程风格。

  • 为什么只能有一个抽象接口呢
    就是因为我们写Lambda表达式时,是是使用的匿名函数的方式,也就是没有写函数名的,试想如果一个接口类包含多个接口方法,那么我们使用Lambda表达式时,就很容易出现编译错误,因为编译器不知道该使用哪个方法了。
  • 如何定义一个函数式接口
    函数式接口可以通过@FunctionalInterface注解来明确标记,但这并不是必需的。你也可以不用注解标注在接口类上,标注注解,只是在我们写编写方法时帮助我们检查,及早提醒开发者。如果接口中定义了一个以上的抽象方法(不包括从Object类继承的方法)。
    java
    @FunctionalInterface  
    public interface GreetingService {  
        void sayMessage(String message);  
    }

2.  Lambda 表达式和普通写法的对比

假设我们有一个message接口用于规范发送消息( 如SMS/EMAIL等)。

  • 普通写法:
//1. 第一接口
@FunctionalInterface
public interface Message {
    void send();
}

//2. 定义实现类
public class SMS implements Message {
    @Override
    public void send() {
        System.out.println("This is SMS Logic!");
    }
}

//3. new 对象,并调用它的方法
public class Lambda {
    public static void main(String[] args) {
        SMS sms = new SMS();
        sendMessage(sms);
        sendMessage(() -> System.out.println("This is SMS"));
    }
}
  •  Lambda 表达式
//1. 第一步当然同样需要申明接口
@FunctionalInterface
public interface Message {
    void send();
}

//2. 但第二步就不需要新建实现类了,只需要写lambda表达式就行
public class Lambda {
    public static void main(String[] args) {
        sendMessage(() -> System.out.println("This is SMS"));
    }

    public static void sendMessage(Message message){
        message.send();
    }
}

可以看到这样写Lambda表达式,可以减少类的创建。

3. 什么时候使用Lambda 表达式

  • 入参是函数式接口的方法。作为入参传入
    public class Lambda2 {
        public static void main(String[] args) {
            List<String> test = new ArrayList<>();
            test.add("a1");
            test.add("b2");
            // 作为forEach 方法的入参
            test.forEach(p -> System.out.println(p));
        }
    }
    
    运行结果:
    a1
    b2
    我们来看看forEach方法,它接收的是一个Consumer 式的函数式接口作为入参
        default void forEach(Consumer<? super T> action) {
            Objects.requireNonNull(action);
            for (T t : this) {
                action.accept(t);
            }
        }
    我们在看这个Consumer接口
    @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); };
        }
    }
    
  • 返回值的是函数式接口的方法,作为返回值
    这种情况大多使用在链式Stream流中,让代码更加模块化。
        public static void main(String[] args) {
            List<String> test = new ArrayList<>();
            test.add("a1");
            test.add("b2");
            test.forEach(myFun());
        }
    
        public static <T> Consumer<T> myFun(){
            return p -> System.out.println(p);
        }

    4. Lambda 表达式的写法

        Lambda 表达式主要由三部分组成:

  • 参数列表(Parameters): 
    这是 Lambda 表达式的输入参数。参数的类型可以显式声明,也可以由编译器根据上下文推断。如果 Lambda 表达式只有一个参数,并且其类型可以由编译器推断,那么参数列表周围的括号可以省略。对于没有参数的 Lambda 表达式,需要使用一个空括号 ()。
  • 箭头(Arrow): 
    箭头 -> 用于分隔参数列表和 Lambda 主体。
  • Lambda 主体(Body): 
    这是 Lambda 表达式要执行的代码块。对于表达式 Lambda(即返回单个表达式结果的 Lambda),主体可以是一个简单的表达式(不需要大括号)。对于语句 Lambda(即执行多个语句的 Lambda),主体需要由大括号 {} 包围,并且可以有显式的返回语句(如果需要的话)。

      示例:

//1. [没有参数],参数部分的空括号必须保留
        sendMessage(() -> System.out.println("This is SMS"));
//2. [方法体有多条语句],方法体必须使用花括号
        sendMessage(() -> {System.out.println("This is SMS");
            System.out.println("This is SMS2");
        });
//3. [有一个参数],参数部分的括号可以不写,可以写
        sendMessageP1((val1) -> System.out.println("This is P1, phone no is:"));
        sendMessageP1(val1 ->  System.out.println("This is P1, phone no is:"));
//3. [有多余一个参数],参数部分的括号也必须写,参数用逗号分开
        sendMessageP1((val1, val2) -> System.out.println("This is P1, phone no is:"));

 5. Java中双冒号(::)和箭头号(->)的区别

双冒号引用的是对象已有的方法,而箭头号是以现有对象为参数新建方法体。在Java中,双冒号(::)和箭头号(->)在Lambda表达式和方法引用中有明确的区别。
双冒号(::):用于方法引用,允许你引用一个已经存在的方法而不执行它。
箭头号(->):用于Lambda表达式,定义Lambda函数的参数列表和函数体。
其实从是否立即执行它的角度来看lambda表达式,它和方法引用是相同的,都不会立即执行。但Lambda表达式不是方法引用,那么如何理解这个不执行它呢?
其实就是在写它的地方并没有执行它,如下

public class Lambda {
    public static void main(String[] args) {
        processPrintln(System.out::println);
    }
    public static void processPrintln(Consumer<String> consumer){
        List<String> test = new ArrayList<>();
        test.add("aa");
        test.add("ab");
        test.forEach(consumer);
    }
}

  • 17
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值