java8 lambda 表达式

lambda 表达式

Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。

Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。

使用 Lambda 表达式可以使代码变的更加简洁紧凑。可以把Lambda表达式理解为简洁的表示可传递的匿名函数的一种方式:它没有名称,但它有参数列表,函数主体,返回类型,可能还有一个可以抛出的异常列表。

特性

匿名:lambda表达式不像面向对象的方法一样,有确定的名称。
函数:虽然lambda不是对象的方法,属于某个特定的类。但是lambda表达式一样的有参数列表、函数主体 返回类型和异常声明
传递:lambda表达式可以作为参数传递
简洁:无需像匿名类一样有固定模板的代码,lambda写得少而想得多
JAVA8中 可以为接口增加静态方法、可以为类增加默认方法

语法

lambda 表达式的语法格式如下:

(parameters) -> expression
或
(parameters) ->{ statements; }

以下是lambda表达式的重要特征:

  • 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
  • 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
  • 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
  • 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。

1. 实战案列

1.1 入门案列

        //java8之前写法
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程测试!");
            }
        });
        thread.start();

        //java8 lambda表达式 代码变的更加简洁高效
        new Thread(() -> {System.out.printf("线程测试");}).start();

1.2 入门扩展

/**
 * lambda 表达式扩展
 */
public class LambdaExtend {


    public static void main(String[] args) {

        //java8 之前匿名类写法
        Calcalcuate calcalcuate = new Calcalcuate() {
            @Override
            public int operation(int a, int b) {
                return a + b;
            }
        };
        int c = calcalcuate.operation(1, 2);
        System.out.println("c = " + c);

        //java8 lambda表达式写法 

        //类型声明
        Calcalcuate calcalcuate1 = (int a, int b) -> a + b;
        int c1 = calcalcuate.operation(1, 2);
        System.out.println("c1 = " + c1);

        //不用类型声明
        Calcalcuate calcalcuate2 = (a, b) -> a + b;
        int c2 = calcalcuate2.operation(1, 2);
        System.out.println("c2 = " + c2);

        //类型声明和返回语句 用return的时候 记得要加大括号
        Calcalcuate calcalcuate3 = (int a, int b) -> {
            return a + b;
        };
        int c3 = calcalcuate.operation(1, 2);
        System.out.println("c3 = " + c3);


        //java8  lambda 表达式写法
        Print print = (message) -> System.out.printf(message + "方法");
        print.printMsg("测试");
        //所传参数只有一个话 可以简写小括号
        // Print print=message -> System.out.printf(message+"方法");

        //java8  之前 表达式写法
        Print print1 = new Print() {

            //仔细看 lambda 表达式只相当于 参数列表(expression) 和 方法(statements)
            //拆分
            // (String message)-> {
            //                System.out.printf(message + "方法");
            //            }
            // 合并
            // Print print2 = (String message) -> {
            //    System.out.println(message + "方法");
            //  };
            //print2.printMsg("测试");
            //参数列表,当只有一个参数的时候,可以省略()
            //expression是返回值。
            //statements是代码语句,当statements只有一行的时候,可以省略{}。
            @Override
            public void printMsg(String message) {
                System.out.println(message + "方法");
            }
        };


    }

    //计算接口 只有一个方法
    interface Calcalcuate{
        int  operation(int a,int b);

    }

    //打印接口  只有一个方法
    interface  Print{
        void printMsg(String message);
    }

}

1.3 作用域


JAVA8之前 内部类只允许访问final修饰的变量,现在使用lambda表达式,一个内部类可以访问任何有效的final局部变量-任何值不会发生变化的变量

java限制了 lambda表达式访问的自由变量,值是不可更改的,因为这会导致出现无法预料的并发问题。

java编译器的限制是有限的,只对局部变量有效,如果使用静态变量,或者示例变量,编译器不会提示任何错误。这样仍然是不安全的。

可以用数组 int[] counter =new int[1]; button.setOnAaction(event->counter[0]++); 任然可以让lambda对局部变量进行重新赋值。

lambda表达式的方法体,与被嵌套的代码块具有同样的作用域,所有适用同样的命名冲突和变量屏蔽规则。

1.4 方法引用


对于已有的方法,如果希望作为lambda表达式来使用,可以直接使用方法引用

三种方法引用的情况

对象::实例方法
类::静态方法
类::实例方法
在第一种和第二种方法引用种,方法的引用等于提供方法参数的lambda表达式
例如:

System.out::println() 等同于 System.out.print(x)
Math::pow 等同于 (x,y)->Math.pow(x,y)
对于第三种,则相当于第一个参数成为执行方法的对象
例如:String::compareToIngnoreCase 等同于(x,y) x.compareIngoreCase(Y);


1.5 构造器引用


对于构造器引用,相当于根据构造器的方法的参数,生成一个构造的对象的一个lambda表达式
例如:StringBuilder::new 可以表示为 (Stiring s)->new StringBuilder(s); 具体引用哪个构造器,编译器会根据上下文推断使用符合参数的构造器。

2 函数式接口

函数式接口介绍
总结:就是只定义了一个抽象方法的接口,即使有一堆的default方法(default方法是为了增强某些API但避免现有大范围改动所有API所以推出了默认方法)

不同接口的默认方法冲突问题
如果实现的接口已有一个默认方法,但是另一个父类或者接口也有同样的默认方法。

如果是父类和接口默认方法一致,那么直接使用父类的方法实现,忽略接口中的默认方法(类优先规则,如果尝试重写默认方法toString 那么永远都不会优于Object的toString)

如果一个父接口提供了一个默认方法,另一个接口也提供了同名称和参数的方法(不论是否默认方法)那么都必须覆盖改方法。

2.1 常见函数式接口

Predicate 返回布尔值

  /**
         * java.util.Predicate 是一个只有test方法,返回布尔值的一个函数式接口,
         * 与其类似的还有用于比较,排序的Comparator接口,其只有一个返回整数的比较接口
         * @param list
         * @param p
         * @param <T>
         * @return
         */
        public static <T> List<T> filter(List<T> list, java.util.function.Predicate<T> p){
            List<T> result=new ArrayList<>();
            for (T t : list) {
                if (p.test(t)) {
                    result.add(t);
                }
            }
            return result;
        }

        public static void main(String[] args) {
            //Predicate函数式接口示例
            List<Student> studentList=new ArrayList<>();
            studentList.add(new Student("李小明",17,"一班"));
            studentList.add(new Student("李明",18,"一班"));
            studentList.add(new Student("李大明",19,"一班"));

            //java8 之前写法 执行test方法的时候 判断 是否年龄大于18
            studentList=filter(studentList, new Predicate<Student>() {
                
                
                //代码拆分
                // test(Student p) {
                //                    return p.getAge()>18;
                //                }
                //合并 缩写 建议先敲匿名类方式 习惯后 在写lambda 表达式
                // studentList=filter(studentList, p -> p.getAge()>18);
                @Override
                public boolean test(Student p) {
                    return p.getAge()>18;
                }
            });
         
            
            studentList.stream().map(stl->stl.getName()).collect(Collectors.toList()).forEach(System.out::println);

        }

      }

Counsumer接口

Accept ()方法签名为,输入某个对象 返回void


    /**
     * 常用2:Consume
     * consume接口定义了一个 名为accept的抽象方法,接收泛型 T 返回void
     * 可用来访问T类型的对象,并且执行某些操作。
     * 如下用其创建,一个foreach方法,可以实现对所有List的遍历。且对每个对象执行consume定义的操作。
     * 该foreach方法,java8之后成了List接口的default方法。
     * @param list
     * @param <T>
     */
    public static <T> void foreach(List<T> list, Consumer<T> consumer){
        for (T t : list) {
            consumer.accept(t);
        }
    }

        public static void main(String[] args) {
            //Predicate函数式接口示例
            List<Student> studentList=new ArrayList<>();
            studentList.add(new Student("李小明",17,"一班"));
            studentList.add(new Student("李明",18,"一班"));
            studentList.add(new Student("李大明",19,"一班"));

            // 打印学生姓名
           foreach(studentList, new Consumer<Student>() {

               // consumer.accept(t);这一步执行的是 以下传过去的方法
               //拆分
               //(Student student) {
               //                    System.out.println("student = " + student.getName());
               //       }
               //合并 缩写
               // student -> System.out.println("student = " + student.getName())

               @Override
                public void accept(Student student) {
                    System.out.println("student = " + student.getName());
                }
            });

        }

Function
输入某个对象、返回某个对象

    /**
     * 常用3:function
     * Apply() 方法签名:输入某个对象、返回某个对象
     * @param <T>
     */
    public static <T> T foreach(Function<String, T>  function){
        String age="20";
        T result=function.apply(age);
        return  result;
    }

        public static void main(String[] args) {

          Integer age= foreach(new Function<String, Integer>() {

              //这里想要Integer类型 学生年龄
              //拆分
              //(String s) {
              //                    return Integer.valueOf(s);
              //   }
              //合并 简写
              //  foreach( s -> Integer.valueOf(s));
                @Override
                public Integer apply(String s) {
                    return Integer.valueOf(s);
                }
            });

            System.out.println("age = " + age);

        }

2.2  常见的Lambda和已有的实现

案例lambda例子对应的函数式接口
布尔表达式
boolean test(T t)
Predicate
创建对象
T get()
Supplier
消费一个对象
void accept(T t)
Consumer
从一个对象中提取
R apply(T t)
Function 或者其特殊化的 ToIntFunction
合并两个值
int applyAsInt(int left, int right)
IntBinaryOperator
比较两个对象
int compare(T o1, T o2)
Comparator BigFunction<Apple,Apple,Integer> ToIntBigFunction<Apple,Apple>

参考连接

栗子叶

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值