美文网首页Java 杂谈Android基础知识程序员技术栈
【Java】3.0 Java中lambda表达式(上)

【Java】3.0 Java中lambda表达式(上)

作者: bobokaka | 来源:发表于2019-07-11 12:50 被阅读5次
    1.0 lambda表达式是JDK8新增的功能,它显著增强了Java。

    自C#和C++等语言都添加了lambda表达式后,Java8也开始不甘人后,继续保持自身的活力和创造性。lambda表达式正在重塑Java,将影响到几乎所有的Java程序员。

    2.0 lambda表达式本质是一个匿名(即未命名)方法。实现和理解其实很简单。
    • lambda表达式在Java语言中引入一个新的语法元素和操作符,操作符是“->”,可以称它为lambda操作符或者箭头操作符。符号左侧是参数(没有就打空括号),右侧是具体执行的动作。用自然语言描述时,可以把“->”表达成“成了”或者“进入”。
    • 举个例子,
    () -> 123.45
    

    上面的内容,效果等同于如下所示:

    double myMeth(){
            return 123.45;
    }
    

    第二个代码中小括号内的内容就是第一个代码小括号中的内容,有参数或者无参数。

    • 再举个例子。
    (n) -> (n%2) == 0
    

    上面的内容,效果等同于如下所示:

    boolean myExample(int n){
           return (n%2) == 0;
    }
    
    3.0 高级的来了: 单个表达式
    3.1 无参数的单个lambda表达式。先看完整代码。
    package com.edpeng.game1;
    
    interface MyNumber {
        // 从JDK8开始,可以为接口声明默认行为,即所谓的“默认方法”
        double getValue();
    }
    
    public class test1 {
    
        public static void main(String[] args) {
            MyNumber myNum;
            // 第一个例子
            myNum = () -> 123.45;
            System.out.println("第一个例子输出结果为:" + myNum.getValue());
    
            // 第二个例子,Math.random(),生成0-1之间的伪随机数
            myNum = () -> Math.random() * 100;
            System.out.println("第二个例子第一个值输出结果为:" + myNum.getValue());
            System.out.println("第二个例子第二个值输出结果为:" + myNum.getValue());
    
    //      myNum = () -> "123.45";//会报错!无法编译运行。
        }
    }
    

    执行结果如下:


    图片.png
    • (1)本例中,getValue()方法属于隐式抽象方法,并且是MyNumber定义的唯一方法。因此,MyNumber是一个函数式接口,其功能由getValue()定义。而我们的 lambda表达式定义了函数式接口声明的抽象方法的行为。
    • (2)需要特别说明的是, lambda表达式不能单独执行(单独出现),是要依赖上下文的。意思就是说,目标类型上下文应该能够明确 lambda表达式所需要的变量初始化,return语句和方法参数等。当把一个 lambda表达式赋给一个函数式接口引用时,就创建了这样的上下文。
    • (3)对上面(2)的进一步补充和阐述。例如如果抽象方法指定了两个int型参数,那么 lambda表达式也必须制定两个参数,其类型要么显性指定为int型,要么在上下文中可以被隐式推断为int类型。总之,lambda表达式的参数的类型和数量必须与方法的参数兼容,返回类型也必须兼容,并且 lambda表达式可能抛出的异常也必须能被方法接受。
    3.2 有参数的单个lambda表达式。下面是有参表达式的完整代码实例:
    package com.edpeng.game1;
    
    interface NumericTest {
        // 从JDK8开始,可以为接口声明默认行为,即所谓的“默认方法”
        boolean test(int n);
    }
    
    public class test1 {
    
        public static void main(String[] args) {
            // 例子1
            NumericTest isEven = (n) -> (n % 2) == 0;
            int number = 10;
            if (isEven.test(number)) {
                System.out.println(number + " 能被2整除。");
            } else {
                System.out.println(number + " 不能被2整除。");
            }
    
            // 例子2
            NumericTest isNonNeg = (n) -> n >= 0;
            number = 1;
            if (isNonNeg.test(number)) {
                System.out.println(number + " 是自然数。");
            } else {
                System.out.println(number + "不是自然数。");
            }
            number = -1;
            if (isNonNeg.test(number)) {
                System.out.println(number + "是自然数。");
            } else {
                System.out.println(number + "不是自然数。");
            }
        }
    }
    

    运行结果如下:


    图片.png
    4.0 块lambda表达式

    具体格式如下:

    () -> { };
    
    4.1 看代码就懂了,无非就是箭头符号后面不止一句语句,可以用花括号整合在一起执行。
    package com.edpeng.game1;
    
    interface Numericfunc {
        int func(int n);
    }
    
    public class test1 {
    
        public static void main(String[] args) {
            Numericfunc numericfunc = (n) -> {
                int result = 1;
                for (int i = 1; i <= n; i++) {
                    result = i * result;
                }
                return result;
            };
            // 3的阶乘:1*2*3
            System.out.println("3的阶乘是:" + numericfunc.func(3));
            // 5的阶乘:1*2*3*4*5
            System.out.println("5的阶乘是:" + numericfunc.func(5));
        }
    }
    

    执行结果为:


    图片.png
    • lambda表达式的意思是:需要给我一个参数n,并需要提供最后返回的值,而且都要和抽象函数对象匹配,通过这个函数可以推出需要的参数n为int类型,并且返回值也应该为int类型。(由int func(int n)推出)。
    • 需要注意的是,代码中两个n是两回事,lambda表达式中的n是自己代码块里面用,你们可以换成任何可以自由定义的别的单词,且lambda表达式不能单独声明参数类型,指定数据类型,因为可以由上下文推出。
    4.2 在上面4.1中都是int型,下面可以举一个别的类型的实现。
    package com.edpeng.game1;
    
    interface Stringfunc {
        String func(String n);
    }
    
    public class test1 {
    
        public static void main(String[] args) {
            Stringfunc stringfunc = (str) -> {
                String result = "";
                int i;
                for (i = str.length() - 1; i >= 0; i--) {
                    result += str.charAt(i);
                }
                return result;
            };
    
            System.out.println("将lambda字母颠倒输出为:\n" + stringfunc.func("lambda"));
            System.out.println("将Expression字母颠倒输出为: \n" + stringfunc.func("Expression"));
        }
    }
    

    执行结果为:


    图片.png
    5.0 泛型函数式接口。
    5.1 上面4.2中已经阐述过了,这里需要再强调一下,lambda表达式自身不能指定类型参数。也因此,lambda表达式不能是泛型(当然,它本身存在类型推断,自带一些类似泛型的特征)。
    5.2 但是,,lambda表达式关联的函数式接口可以是泛型。这时候,lambda表达式的目标类型由声明函数式接口引用时指定的参数类型决定。
    5.3 基于此,我们可以把4.1和4.2中两个范例通过泛型函数式接口整合在一起。代码如下:
    package com.edpeng.game1;
    
    //这就叫做“泛型函数式接口”
    interface SomeFunc<T> {
        T func(T t);
    }
    
    public class test1 {
    
        public static void main(String[] args) {
    
            // 4.1中的案例
            SomeFunc<String> reverse = (str) -> {
                String result = "";
                int i;
                for (i = str.length() - 1; i >= 0; i--) {
                    result += str.charAt(i);
                }
                return result;
            };
    
            System.out.println("将lambda字母颠倒输出为:\n" 
            + reverse.func("lambda"));
            System.out.println("将Expression字母颠倒输出为: \n" 
            + reverse.func("Expression"));
    
            // 4.1中的案例等同于:
    //      SomeFunc<String> re = new SomeFunc<String>() {
    //
    //          @Override
    //          public String func(String t) {
    //              // TODO Auto-generated method stub
    //              String result = "";
    //              int i;
    //              for (i = t.length() - 1; i >= 0; i--) {
    //                  result += t.charAt(i);
    //              }
    //              return result;
    //          }
    //      };
    //      System.out.println("将lambda字母颠倒输出为:\n" +re.func("lambda"));
    
            // 4.2中的案例
            SomeFunc<Integer> factorial = (num) -> {
                int result = 1;
                for (int i = 1; i <= num; i++) {
    
                    result = i * result;
                }
                return result;
            };
            // 3的阶乘:1*2*3
            System.out.println("3的阶乘是:" + factorial.func(3));
            // 5的阶乘:1*2*3*4*5
            System.out.println("5的阶乘是:" + factorial.func(5));
        }
    }
    

    执行结果为:


    图片.png
    6.0 作为参数传递lambda表达式

    这个方面是lambda表达式的一种常见用途,极大的增强了Java的表达能力。
    通过一个简单的例子演示就足够了,特别简单直观好理解,而且实用。

    package com.edpeng.game1;
    
    interface StringFunc {
        String func(String n);
    }
    
    class test1 {
        static String stringOp(StringFunc sf, String string) {
            return sf.func(string);
        }
    
        public static void main(String[] args) {
            //案例一:小学转大写
            String inStr = "lambda 表达式 加入 Java";
            String outStr;
    
            System.out.println("输入的字符串为: \n" + inStr);
            outStr = stringOp((str) -> str.toUpperCase(), inStr);
            System.out.println("该字符串的大写为: \n" + outStr);
    
            //案例二:去除文本空格
            outStr = stringOp((str) -> {
                String result = "";
                int i;
    
                for (i = 0; i < str.length(); i++) {
                    if (str.charAt(i) != ' ') {
                        result += str.charAt(i);
                    }
                }
                return result;
            }, inStr);
    
            System.out.println("删除空格的字符串为: \n" + outStr);
    
            //案例三:字符倒转
            StringFunc reverse = (str) -> {
                String result = "";
                int i;
                for (i = str.length() - 1; i >= 0; i--) {
                    result += str.charAt(i);
                }
                return result;
            };
            System.out.println("重新转换的字符串为: \n" + stringOp(reverse, inStr));
        }
    }
    

    执行结果如下:


    图片.png

    这个并没有增加新的内容,只是将其中增加的这个特性再一次强调一下。案例一和案例二都可以简单表述为:

     outStr = stringOp(lambda表达式,inStr);
    

    当然我们也看当这样使用时有些笨拙的,当块lambda表达式看上去特别长的时候,嵌入到方法调用中,很容易把块lambda赋给一个函数式接口变量。所以当使用案例三这种做法时,就显得很简单而且不易出错。案例三可以简单描述为:

     StringFunc reverse =lambda表达式;
     stringOp(reverse, inStr);
    

    相关文章

      网友评论

        本文标题:【Java】3.0 Java中lambda表达式(上)

        本文链接:https://www.haomeiwen.com/subject/fzfhkctx.html