Java8特性lambda表达式、函数式接口和方法引用的一个应用实例

关于Java8新特性的一个问题

前几天在一个直播课程上看到这样一种写法:

public class AtomicDemo {
    public static void hellooo() {
        System.out.println("hello");
    }
     
    public static void main(String[] args){
        new Thread(AtomicDemo::hellooo).start();
    }
}

运行结果:输出 hello

看到这个例子,我不太明白new Thread(AtomicDemo::hellooo)这种写法是怎么回事,Thread的构造方法里不是应该传入Runnable对象吗?

我知道这是Java 8的新特性,可是具体是怎么回事就不太清楚了,于是自行求助网络,现在将自己的一些理解记下来:

lambda表达式实例

首先,Java 8有个新特性,叫lambda表达式,这个大家应该都听过。
什么是lambda表达式呢,网上的讲解很多,我这里就不细讲了,基本语法可以这么表示:

(参数) -> 含参数的表达式

(参数) ->{ 对参数进行处理的代码块 }

这个参数如果是多个,要用逗号隔开。如果是一个参数,可以省略参数的左右括号。如果没有参数,括号不能省略。

lambda表达式可以用它来简化代码,比如在Android项目里,一般我们给Button设置点击事件,可以这么写:

        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                btn.setText("clicked");
            }
        });

但是如果换成lambda表达式,可以简化为这样:

btn.setOnClickListener((View v) -> v.setText("clicked"));

再简化下,可以这样:

btn.setOnClickListener( v -> v.setText("clicked"));

很简洁吧,这样写,避免了写匿名内部类的繁琐。不过为什么可以这么写呢?因为Java8还有个新特性,叫函数式接口。

函数式接口的简介

简单说,就是只含有一个抽象方法的接口,比如 View.OnClickListener接口就是函数式接口,它只有一个onClick()抽象方法。

注意函数式接口只有一个抽象方法,但是它可以有静态方法(即static修饰的方法)和默认方法(用default修饰的方法),后两种方法就算有具体实现也可以的。

在Java8中,函数式接口比较常见的如Runnable接口,Callable接口,Comparator接口等,在源码中,它们已经被加上了@FunctionalInterface标签:

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

我们在写函数式接口时,不加这个标签也可以,但加上有助于更好地让编译器做检查,如果不符合函数式接口的规范,编译器会报错。

而且,Java8的设计者为了更好地支持lambda表达式,于是让函数式接口可以隐式地转化为lambda表达式。所以,文章开头那个例子的main()方法可以这么写:

Runnable runnable = () -> {System.out.println("hello");};
new Thread(runnable).start();

或者省略大括号:

Runnable runnable = () -> System.out.println("hello");
new Thread(runnable).start();

或者直接用定义好的方法;

Runnable runnable = () -> hellooo();
new Thread(runnable).start();

这三种写法都一样的。
实际上我随便写一个函数式接口,比如叫做MyInterface,那么我就可以MyInterface face = () -> hellooo()这么写都是可以的,只是这里的face对象就不能传入Thread构造方法里了。

更直接一点,可以这么写:

new Thread(() -> hellooo()).start();

也可以。但是和我们开头例子中的new Thread(AtomicDemo::hellooo).start()还是不一样,这种双冒号的写法是怎么回事呢?这就是Java 8的另一个新特性:方法引用。

方法引用

介绍方法引用之前,先看几个方法引用的简单例子:
如果我们构造了一个Arraylist,

List<String> colorList = Arrays.asList("red", "yellow", "blue");
		

然后想遍历打印,如果用方法引用,只需要一行代码:

colorList.forEach(System.out::println); //forEach也是Java8的新特性

方法引用简单来说,就是类名/对象+双冒号+方法名的写法,具体有下列这么多,此处就不细讲了。它和lambda表达式都是Java的语法糖。

静态方法引用:ClassName::methodName
实例上的实例方法引用:instanceReference::methodName
超类上的实例方法引用:super::methodName
类型上的实例方法引用:ClassName::methodName
构造方法引用:Class::new
数组构造方法引用:TypeName[]::new

那么开头例子中,我们用静态方法引用的写法,就可以写成这样:

Runnable runnable =  AtomicDemo::hellooo;
new Thread(runnable).start();

简化一下,就成了开头的写法new Thread(AtomicDemo::hellooo).start()。

如何让Android项目支持Java 8的这些新特性

如果IDE用的是Android studio,可以这么做:

1.在根目录下的build.gradle添加:

dependencies {
  ...
  classpath 'me.tatarka:gradle-retrolambda:3.2.5' //添加这行
  ...
}

2.在app下的build.gradle添加:

apply plugin: 'me.tatarka.retrolambda'

3.在app下的build.gradle中指定Java版本为java8:

android {
  ...
  compileOptions {
      sourceCompatibility JavaVersion.VERSION_1_8
      targetCompatibility JavaVersion.VERSION_1_8
  }
  ...
}

这样就可以在Android项目中使用Java8新特性了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值