Java 函数式接口、lambda表达式、初识Stream

1.函数式接口:

有且仅有一个函数接口(可以有其他非抽象的方法),函数式接口的典型使用场景就是作为方法的入参。
比如 java.lang.Runnable就是一个函数式接口。java.util.function包中提供了丰富的函数式接口:Supplier、Consummer、Function等。

2.@FunctionalInterface

用于一个接口的定义上,一旦使用该注解来定义接口,编译器将会强制检查该接口是否确实有且仅有一个抽象方法,否则会将会报错。与@Override注解类似。

示例:

@FunctionalInterface
public interface MyFunctionalInterface {
    void myMethod();
}

public class DemoMyFunctionalInterface {
    // 自定义的函数式接口作为方法的参数
    private static void doSomething(MyFunctionalInterface inter) {
        inter.myMethod(); // 调用自定义的函数式接口方法
    }

    public static void main(String[] args) {

        // 通过匿名内部类操作 使用了调用函数式接口的方法
        doSomething(new MyFunctionalInterface() {
            @Override
            public void myMethod() {
                System.out.println("匿名内部类 执行");
            }
        });

        // 通过lambda操作 使用了调用函数式接口的方法
        doSomething(() -> System.out.println("lambda 执行"));
    }
}

3. lambda

3.1 Lambda表达式, 也可以称为闭包,它是推动 java 8 发布的最重要的新特性。Lambda允许把函数作为一个方法的参数(即就是,函数作为参数传递进方法中)。Lambda表达式的一个重要的用法就是简化某些匿名内部类的写法。
Lambda标准格式:(参数类型 参数名)->{代码块儿/代码语句}
3.2 省略规则:
Lambda标准格式的基础上,使用省略写法的规则:
(1)小括号内参数的类型可以可以省略;
(2)如果小括号内有且仅有一个参数,则小括号可以省略;
(3)如果打括号内有且仅有一个语句,则无论是否返回值,都可以省略大括号、return 关键字以及语句分号。

示例:

@FunctionalInterface
public interface MessageBuilder {
    String buildMessage();
}

public class DemoMessageBuilderLogger {

    private static void traditionalLog(int level, String msg) {
        if (level == 1) {
            System.out.println(msg);
        }
    }

    private static void lambdaLog(int level, MessageBuilder builder){
        if (level == 1){
            System.out.println(builder.buildMessage());
        }
    }

    public static void main(String[] args) {
        String msgA = "Hello";
        String msgB = "World";
        String msgC = "Java";

        traditionalLog(1, msgA + msgB + msgC);

        lambdaLog(1, new MessageBuilder() {
            @Override
            public String buildMessage() {
                return msgA + msgB + msgC;
            }
        });

        lambdaLog(1,() -> msgA + msgB + msgC);
    }

注意:
使用Lambda的依据必须有相应的函数接口(函数接口,是指内部只有一个抽象方法的接口),Lambda的实际类型就是对应函数类型的接口类型。

具体内部怎么调用与实现的呢?
JVM内部就是通过invokedynamic指令来实现Lambda表达式的的hi用Lambda简化过的匿名内部类在外部类编译后不会生成内部类的class文件,Lambda表达式被封装成了主类的一个私有方法。并通过invokedynamic 指令进行调用。
lambda是延迟执行的,有些场景的代码执行后,执行结果不一定会被使用,从而造成性能的浪费。而lambda 表达式是延迟执行的,正好可以作为解决方案,提升性能。

4.初识 Stream

这里的Stream到底是什么呢?
说到Stream我们很容易想到I/O Stream,然而实际上没有人规定“流”就一定是“io流”,所以在java 8中得益于Lambda所带来的函数式编程,引入了一个全新的Stream概念,用于解决已有集合类库存在的弊端。

我们知道集合中要进行频繁的遍历操作,然而我们经常使用的都是循环遍历,每次需要遍历的操作都需要从 for从前到后遍历集合,比较麻烦。

我们可以大胆进行对比各种遍历的代码量:

  List<String> list = new ArrayList<>();
        list.add("张无忌");
        list.add("周芷若");
        list.add("赵敏");
        list.add("张强");
        list.add("张三丰");

        /**
         * 普通的遍历
         */
        System.out.println("普通遍历:");
        for (int i = 0; i < list.size(); i++){
            System.out.println(list.get(i));
        }
        System.out.println("---------------------");
        /**
         * 增强for循环
         */
        System.out.println("增强for遍历:");
        for (String s : list){
            System.out.println(s);
        }
        System.out.println("******************");
        /**
         * 使用迭代器Iterator进行遍历
         */
        System.out.println("利用Iterator遍历:");
        Iterator<String> iterator = list.iterator();
        while(iterator.hasNext()){
            String s = iterator.next();
            System.out.println(s);
        }

        /**
         * 使用Stream 进行遍历
         */
        System.out.println("使用Stream遍历:");
        list.stream().forEach(System.out::println);


输出结果:

普通遍历:
张无忌
周芷若
赵敏
张强
张三丰


增强for遍历:
张无忌
周芷若
赵敏
张强
张三丰


利用Iterator遍历:
张无忌
周芷若
赵敏
张强
张三丰


使用Stream遍历:
张无忌
周芷若
赵敏
张强
张三丰

到这我们差不多认识了这家伙,后期继续会深入的进行了解并在开发中进行大量的使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值