java lambda 且行且珍惜

一、先看一个最经典的例子

new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("run...");
            }
}).start();

这是我们以前多线程的写法,在匿名类里面实现run方法,你可能觉得没什么但是仔细看看,6行代码才实现了一个功能,输出run...,除了

System.out.println("run...");

这一句,其他的似乎和我们的功能没什么关系

现在有了lambda表达式,妈妈再也不用担心我的学习了:

new Thread(() ->System.out.println("lambda run...")).start();

一行搞定,有的同学可能看出来了,其实

() ->System.out.println("lambda run...")

就相当于

new Runnable() {
            @Override
            public void run() {
                System.out.println("run...");
            }
}

那我们是不是可以这样写

Runnable r1 = () -> {System.out.println("run...");};

答案是可以的,但是我们不能这样写

Object r1 = () -> {System.out.println("run...");};

编译时会提示异常:

 错误: 不兼容的类型: Object 不是函数接口

我们可以进行类型转换:

Object r1 = (Runnable) () -> {System.out.println("run...");};

这样就可以了,所以lambda表达式可以让我们很方便的写出匿名类,我们实现的时候不需要显示的表明是哪个类的哪个方法,机智的java自己会判断,那就有同学会问,java是怎么判断的呢?答曰:根据方法签名

先来看一下Runnable的源码:

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

@FunctionalInterface表明它是一个函数式接口,但是这个注解不是必须的(什么是函数式接口?自己动手搜吧,少年)

我们看一下它的方法签名:方法名为run,入参为空,返回值为void,而我们的实现刚好符合(除了方法名,上面也说了,我们根本不care,调用的时候就需要知道方法名了)

如果我们还有个类似的接口,方法签名完全一样:

interface MyRunnable
{
	public abstract void run();
}

我们直接把变量类型改了就可以了

MyRunnable r2 = () -> {System.out.println("Hello Lambda!");};

机智的java会知道你实现的到底是哪个类,再比如以下情况:

public static void test(MyRunnable r) {
    r.run();
}

public static void test(Runnable r) {
	r.run();
}

我们如果这样调用:

TestLambda.test(() -> {System.out.println("Hello Lambda!");});

编译时就会出现错误:

 错误: 对test的引用不明确

想想也知道,java根本不知道你的这个实现是哪个接口的,Runnable?MyRunnable?

根据以上我们可以这样来调用:

TestLambda.test((MyRunnable) () -> {System.out.println("Hello Lambda!");});

明确的指明参数类型就可以了


二、java8已经预先定义了很多常用的函数接口方便我们使用:

Function<T, R>——将T作为输入,返回R作为输出
Predicate<T>——将T作为输入,返回一个布尔值作为输出
Consumer<T>——将T作为输入,不返回任何内容
Supplier<T>——没有输入,返回T
BinaryOperator<T>——将两个T作为输入,返回一个T作为输出

java 8中,特别是在操作java集合时你就会碰到很多这样的接口,到时可不要被他们给搞晕掉了,只要记住使用lambda表达式时我们根本不care方法名就会帮你更加容易的进行理解


三、很多文章也说道可以用方法引用来简化lambda表达式,但是有时会出现歧义的情况,比如Double类的2个方法:

public String toString();
public static String toString(double d);

当我们这样写时:

Function<Double,String> f = Double::toString;
String fi = f.apply(1.2);
System.out.println(fi);

编译器根本不知道该调用哪个,出错如下:

    对toString的引用不明确
      Double 中的方法 toString(double) 和 Double 中的方法 toString() 都匹配

所以,这种情况我们还是老老实实的用lambda表达式吧:

Function<Double,String> f = (d) -> {return d.toString();};
String fi = f.apply(1.2);
System.out.println(fi);

或者

Function<Double,String> f = (d) -> {return Double.toString(d);};
String fi = f.apply(1.2);
System.out.println(fi);

这样就可以了


个人觉得还是习惯用普通的lambda表达式,方法引用的话有时候不易理解

转载于:https://my.oschina.net/dxqr/blog/215788

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值