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

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

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";//会报错!无法编译运行。
    }
}

执行结果如下:


16102290-a4a019c93c79122a.png
图片.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 + "不是自然数。");
        }
    }
}

运行结果如下:


16102290-3c14a46337eecb44.png
图片.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));
    }
}

执行结果为:


16102290-50cd764ff8cf9d05.png
图片.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"));
    }
}

执行结果为:


16102290-c10efa3cb6fba6ff.png
图片.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));
    }
}

执行结果为:


16102290-e15aa97bb11d2ea8.png
图片.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));
    }
}

执行结果如下:


16102290-9f1dbfc5d6b521a3.png
图片.png

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

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

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

 StringFunc reverse =lambda表达式;
 stringOp(reverse, inStr);
  • 11
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值