Lambda表达式基本概念

 

大家好,
今天给大家分享一下可能会使用到的知识点:

Lambda表达式基本概念

 

 

 

1.背景介绍

Lambda表达式式Java8的重要更新,Lambda表达式支持将代码块作为方法参数,可以使用Lambda 实现以更简洁的代码来创建只有一个抽象方法的接口的实例

2.知识剖析

组成:

形参列表,如果形参列表中只有一个参数,可以将圆括号省略

箭头,由英文的中划线和大于符号组成

代码块,如果代码块中只包含一条语句,可以省略代码块的花括号

匿名内部类

适合于创建那种只需要一次使用的类

创建匿名内部类时会立即创建一个该类的实例,匿名内部类不能重复使用

必须继承一个父类或实现一个接口

Lambda表达式可用于简化匿名内部类对象,代替匿名内部类的繁琐语法

因为Lambda表达式可以将方法作为参数传递

3.常见问题

函数式接口与一般接口区别

 

4.解决方案

函数式接口只有一个抽象方法

 

5.编码实战

 Java8中,你可以通过defaulte关键字,添加非抽象方法
 函数式接口运行存在默认方法、静态方法
 如下,抽象方法calculate旁还有一个sqrt方法, 实现类只需要实现抽象方法calculate
 default方法sqrt是开箱即用的(out of the box).
 注: Math.sqrt函数是计算平方根的。

 

@FunctionalInterface
public interface Formula {
    double calculate(int a);
    default double sqrt(int a) {
        return Math.sqrt(a);
    }

}

这个formula 接口被实现为一个匿名对象,代码是很繁琐的————这么多代码仅仅为了一个简单的运算sqrt(a * 100)

在下一个环节,Java8有一种更好的方式实现单方法对象

 

public class test {

    @Test // lambda表达式
    public void lambda1(){
        Formula formula = new Formula() {
            @Override
            public double calculate(int a) {
                return sqrt(a*100);
            }
        };
        System.out.println(        formula.calculate(100)      );

        System.out.println(    formula.sqrt(16)     );


    }
}

 

注释里讲的很清楚,大家看注释吧。

 

/**
 *让我们首先用老版本,通过对一个含字符串的list进行排序来开始
 *
 *静态的工具类方法Collections.sort接受一个list和比较器来对对list中的元素进行排序
 *
 *  创建一个匿名的比较器然后将参数传递给比较方法。
 *
 * compareTo
 * 调用者小于、等于或大于指定对象,则分别返回负整数、零或正整数
 */
public class Lambda_expressions {

    List<String> names = Arrays.asList("peter", "anna", "mike", "xenia");

    @Test
    public void lambda2(){

        Collections.sort(names, new Comparator<String>() {
            @Override
            public int compare(String a, String b) {
                int i =  a.compareTo(b);
                //System.out.println(i+"");
                return i;
            }
        });
        //降序排列,如果要升序,改为a.compareTo(b);
        System.out.println(names);  //[xenia, peter, mike, anna]
    }

    /**
     * 不用再整天创建匿名对象了,Java8提供了一种更简洁的语法,即lambda表达式
     *
     */
    @Test
    public void lambda2_1(){

        Collections.sort(names, (String a, String b) -> {
            return b.compareTo(a);
        });

        System.out.println(names);  //[xenia, peter, mike, anna]
    }
    /**
     * 通过上面可以看到代码更加简单易读,而且可以更短
     */
    @Test
    public void lambda2_2(){

        Collections.sort(names, (String a, String b) -> b.compareTo(a));

        System.out.println(names);
    }
    /**
     * 对于一行的方法体,你可以省略大括号和return关键字,然而,它还可以更短
     *
     * 因为Java8后,list接口里增加了sort方法,可以直接用,不需要再借助Collections
     * 注意,要想让接口里的方法可以有方法体,要用default修饰
     *
     * Java编译器会推断出你的变量类型,所以也省略
     */
    @Test
    public void lambda2_3(){

       names.sort( (a,b) -> b.compareTo(a));

        System.out.println(names);
    }

}

 

lambda表达式可以通过 :: 引用构造方法、静态方法、对象方法,具体见注释

 

 

public class test {

    @Test
    public void lambda3_1(){
        Converter<String,Integer> converter = (input) -> Integer.valueOf(input);
        Integer converted = converter.convert("123");
        System.out.println(converted);    // 123
    }

    /**
     *
     * 上面的例子可以通过方法引用来简化
     *  类名::方法名
     *
     *  Java8使你可以通过关键字::传递方法或构造方法的引用
     *
     */

    @Test
    public void lambda3_2(){
        Converter<String,Integer> converter = Integer::valueOf;

        Integer output = converter.convert("123");
        System.out.println(output);    // 123
    }

    /**
     * 上面是静态方法的引用,还可以引用对象的方法
     */

    @Test
    public void lambda3_3(){
        Something something = new Something();
        Converter<String, String> converter = something::startsWith;
        String converted = converter.convert("Java");
        System.out.println(converted);    // "J"
    }


    /**
     * 下面我们看一下如何用::关键字引用构造方法
     *
     *  首先定义一个有不同构造方法的类Person
     *  然后创建一个工厂接口用来创建Person对象
     *
     *  不需要在手动的实现工厂接口,通过构造方法的引用将它们粘合起来
     *
     */

    /**
     * 我们通过Person::new创建了Person构造方法的引用,Java编译器会自动选择
     * 正确的构造方法来匹配 personFactory.create
     *
     */

    @Test
    public void lambda3_4(){
       PersonFactory<Person> personFactory = Person::new;
       Person p = personFactory.create("王","狗蛋");
        System.out.println(p);

    }


    /*******************    lambda作用域    ***************************/

       /* 在Lambda表达式中访问外层作用域,这一点和旧版本的匿名对象中的方式类似。Lambda表达式中可以直接访问外部final变量,
         或者实例的字段以及静态变量。
        */


     @Test
     public void lambda5_1(){
         final int num = 1;
         Converter<Integer, String> stringConverter =
                 (from) -> String.valueOf(from + num);
        // num++;
         stringConverter.convert(2);     // 3

     }

     // 不需要显式的声明final,以下代码有效
    @Test
    public void lambda5_2(){
        int num = 1;
        Converter<Integer, String> stringConverter =
                (from) -> String.valueOf(from + num);

        stringConverter.convert(2);     // 3

    }

/*    在以前的java版本中匿名内部类的参数必须是final的,原因在于保证内部和外部类的数据一致性。
    编译的时候内部类和方法在同一级别上,所以方法中的变量或参数只有为final,内部类才可以引用。
    因为局部变量在方法调用之后就消失了,使用final声明的话该局部变量会存入堆中,和内部类有一样的声明周期。
    然而java8中不加final,
    也可以通过编译,在以前的版本中是不允许的。
 */

    /****
     *   这里的num 必须是隐式的final才能去编译,下面代码编译不通过。
     *   在lambda表达式中对num进行更改也许不允许的。
     */
    @Test
    public void lambda5_3(){
        int num = 1;
        // Effectively final
        Converter<Integer, String> stringConverter =
                (from) -> String.valueOf(from + num);


        new  Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(num);
            }
        });
        // num = 3;
    }
    /****
     *   小总结: lambda表达式对方法内的局部变量只能读,不能写。 编译器是按final进行编译的。
     */



    /****
     *   和 局部变量不同的是,在lambda表达式内对静态变量和全局变量即可读又可写,这一点和内部类一样。
     *
     *   附:lambda表达式中存在一行以上代码需要加大括号{}
     */
        static int outerStaticNum;
        int outerNum;

        @Test
        public void lambda5_4(){
            Converter<Integer, String> stringConverter1 = (from) -> {
                outerNum = 23;
                return String.valueOf(from);
            };

            Converter<Integer, String> stringConverter2 = (from) -> {
                outerStaticNum = 72;
                return String.valueOf(from);
            };

            Converter<Integer, String> stringConverter3 = (from) ->
                String.valueOf(from);

        }

    /****
     *   还记得第一节我们在接口Formula定义了 default 方法 sqrt,它可以被每个 Formula实例访问。
     *
     *   但lambda表达式之内不能访问接口中的default方法。
     */
    @Test
    public void lambda5_5(){
        // Formula formula = (a) -> sqrt(a * 100);

    }

}

上面的代码有用到类和接口,如下

 

/**
 * 每个lambda对应一个类型,这个类型有接口指定。
 *
 * 函数式节诶看不学包含一个抽象方法的声明,每个对应类型lambda表达式将可以和这个抽象方法匹配
 *
 * default方法不是抽象的,你随便加
 *
 * 我们可以用任意接口作为lambda表达式,只要这个接口仅含有一个抽象方法。为了确保这一点,你可以在你的接口上加上
 *  @FunctionalInterface 注解,这样在你视图再次增加抽象方法是,编译器会检查报错
 *
 *  但是,即使 @FunctionalInterface 注解被省略代码也依然有效
 */
@FunctionalInterface
interface Converter<F, T> {
    T convert(F from);
}

public class Something {
    public String startsWith(String s) {
        return String.valueOf(s.charAt(0));
    }
}
public class Person {
    String firstName;
    String lastName;

    Person() {}

    public Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    @Override
    public String toString() {
        return firstName+lastName;
    }
}
/**
 *  泛型上下限
 *
 * ?extends E: 接收E类型或者E的子类型。
 *  ? super E: 接收E类型或者E的父类型
 * @param <P>
 */

interface PersonFactory<P extends Person> {
    P create(String firstName, String lastName);
}

Java8还有很多内置函数式接口

 

/**
 *
 *Predicate是一个接受一个参数的布尔型方法,内置了多个默认方法,用来构成复杂的逻辑术语
 * and, or, negate 且 或  取反
 *
 */
public class test {

    @Test // lambda表达式
    public void lambda16_1(){
        Predicate<String> predicate = (s) -> s.length() > 0;

        System.out.println(   predicate.test("foo")   );              // true
        System.out.println(        predicate.negate().test("foo")        );     // false

        Predicate<Boolean> nonNull = Objects::nonNull;
        Predicate<Boolean> isNull = Objects::isNull;

        Predicate<String> isEmpty = String::isEmpty;
        Predicate<String> isNotEmpty = isEmpty.negate();


    }

    /**
     *  Function接受一个参数并产生一个返回值,内置的默认方法可以将多个Function连起来
     *   Default methods can be used to chain multiple functions together (compose, andThen).
     */
    @Test // lambda表达式
    public void lambda16_2(){
        Function<String, Integer> toInteger = Integer::valueOf;
        Function<String, String> backToString = toInteger.andThen(String::valueOf);

        //System.out.println(   toInteger.apply("123456")   );
        System.out.println(             backToString.apply("123")       );     // "123"

    }


    @Test // 开启线程示例
    public void lambda16_3(){

        new Thread(new Runnable() {
            @Override
            public void run() {

                System.out.println("线程1");
            }
        }).start();

       new Thread( () -> System.out.println("线程1")).start();

    }

 

 

6.扩展思考

Lambda表达式有哪些应用,毕竟现在代码中很少见到

 

 

新的框架上可以见到它的身影

比如Vert.x里大量应用

 

 

 

7.参考文献

https://github.com/winterbe/java8-tutorial

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值