Java 8新特性 小结

Google在去年的IO大会上宣布使用Jack编译器支持Java 8, 支持的很有限,还问题多多.在后来Google开始"弃坑"了,弃坑了当然会有新的替代方案来支持,Android Studio 2.4 Preview预览版本已经更新了对Java 8的支持

Android 文档资料: https://developer.android.google.cn/studio/preview/features/java8-support.html

先来讨论个问题:编程语言会往哪些方法演进?

这里指已经还在的编程语言

  • 性能会越来越强,多核,并发...
  • 代码语法表达式会越来越精简,简单
  • API的调用会越来越简单,易懂,
  • 语言的也开始适应一些人为因素而改动(项目需求的更改,项目的开发\版本的迭代速度)
  • ....

为什么要问这个问题?当你明白了这些,所有的编程语言的新特性,改进,都只是在这几个大的方向上努力的结果

Studio 2.4版本之前支持Java 8 的两种方式:

不过,都会成为过往人烟,因为2.4要来了,这两种方式不用管了,知道有那么回事。下面是官方文档中支持的一些主要特性:

image.png

Note:Android对Java 8是不完全支持,打个比方说:如果Java 8发布了100个新特性,可能Android现在支持的只有80个. 有些Java 8的新特性用不了也不要奇怪, 估计后面也会更新, Studio 2.4正式版本还未更新,后面的代码均在IntelliJ IDEA编写

Android支持Java 8的主要特性:

  • 默认和静态接口方法
  • FunctionalInterface注解
  • Lambda表达式
  • Function接口
  • 方法引用
  • Stream API
  • 重复注解
  • ......

默认和静态接口方法

在Java 8以前,接口不能编写方法的具体实现,而对于已经设计好的接口,一旦发布出去后,就不能轻易更改接口.如果要修改,所有的实现类均要修改. 在Java 8中,接口允许添加默认和静态方法,也可在方法内写实现代码,实现类不用重写该方法. 特性虽然友好,但不要滥用.比如:List接口新增的默认方法sort:

image.png

FunctionalInterface注解

FunctionalInterface是一个函数注解,用在接口上,如果这个接口是一个函数式接口,这是一个新名词,只有一个抽象方法的接口,就叫函数式接口. Java可能常用的函数式接口:

  • java.lang.Runnable
  • java.util.Comparator
  • java.io.FileFilter
  • java.nio.file.PathMatcher
  • java.util.function包下所有接口
  • ......

@FunctionalInterface用法

image.png

这个注解有什么用? 用来限定你的接口只有一个抽象方法,使之成为函数式接口,如果你在添加第二个抽象方法,不好意思,会提示报错,

image.png

那什么时候用呢?当你要设计一个函数式接口的时候,然后,这个注解是非必需的. 不是说加了这个注解才是函数式接口,不加不是函数式接口,没有这种说法, 函数式接口可参考:java.util.function包下所有接口.
还有一个问题:上面一直在强调一定是抽象方法, 还有新增的默认方法,静态方法不算,如果非要钻牛角尖,Object的toString,hashCode,equals也不算:

image.png

Lambda表达式

什么时候用:当要使用到函数式接口(接口中只有一个抽象方法)的时候,就可以用Lambda表达式,Like this:

  • 伪代码: 方法名(函数式接口)
  • 比如File中的listFiles(FileFilter filter)
  • 比如List中的sort(Comparator<? super E> c)

FileFilter和Comparator都是函数式接口

有什么好处?使代码变得更加紧凑,简洁

代码格式:(parameters参数) -> { statements代码块;}

image.png

代码由两部分组成:左侧的重写函数参数部分,右侧的具体实现代码块,用"->"符号连接,暂且称之为Lambda符号

image.png

你可能注意到这个重写的函数是有返回值的,上面的代码连return关键字都没有, 这里的逻辑是:如果代码的实现部分只有一句话,不用加return关键字语句,连语句结束符号";"也不用加,

上面有说Lambda代码的格式:(parameters参数) -> { statements代码块;},这断代码还能写成,都没有问题:

image.png

Lambda的演进方式更像是这样:干掉接口名,干掉函数以及函数修饰符,在参数和代码块之间插入Lambda符号"->"

image.png

Function接口

java.util.function包下定义了几组基础类型的函数式接口以及针对基本数据类型的子接口,个人对这些接口的理解就是:Java对一些常见的函数接口进行了归纳,总结,然后写了几个高度抽象的样板,供自己和开发者使用

  • Predicate -- 判断型:传入一个参数,返回一个bool结果,方法为boolean test(T t)
  • Consumer -- 消费型:传入一个参数,无返回值,纯消费,方法为void accept(T t)
  • Function -- 功能型:传入一个参数,返回一个结果,方法为R apply(T t)
  • Supplier -- 生产型:无参数传入,返回一个结果,方法为T get()
  • UnaryOperator -- 一元操作符,继承Function,传入参数的类型和返回类型相同。
  • BinaryOperator -- 二元操作符,传入的两个参数的类型和返回类型相同. 继承BiFunction

方法引用

首先,这个方法引用是为Lambda表达示服务的, 用来替换Lambda表达式, 使代码更加紧凑,并且具有可读性

**定义: **方法引用是用来直接访问类或者实例的已经存在的方法或者构造方法,提供了一种引用而不执行方法的方式,方法引用的操作符是双冒号"::"

先来个匿名函数,Lambda表达式,方法引用对比的例子, 还是用上面的FileFilter接口:


Method References.png

官方文档上提到的几个种类:上面示例使用的引用静态方法


image.png
  • 引用静态方法:ClassName::staticMethodName
  • 引用实例上的实例方法:instanceReference::instanceMethodName
  • 引用特定类型上的实例方法:ClassName::methodName
  • 引用构造方法:Class::new

上面已经提到了方法引用是干什么的?现在来回答另外一个问题:到底什么时候用?或者,这个引用的方法该怎么写?关注两点:保证函数式接口中重写方法和需要引用方法中的参数和返回值一致,即可使用方法引用

image.png

1.静态方法引用 ClassName::staticMethodName(上图)

2.实例方法引用 instanceReference::instanceMethodName

this是当前实例对象的引用


image.png

静态方法引用和实例方法引用的区别就是:静态方法引用加了关键字static.你这不是废话吗?这不是重点:重点是来理解方法引用的操作符“::”,它和方法调用("类名.静态方法")的“.”操作符非常相似,只是换了一个符号,然后起了一个好听的名字--方法引用操作符

android.app.dialog中也有段方法引用的代码:

image.png
这里来说另一个问题:方法引用具有可读性

在Android的代码中Google不惜为定义一个方法名写上三四十个字母,其实是一句话,其中单词还不带有缩写的,目的只有一个,方便开发者在使用该API容易理解

关联到这里呢:方法引用的方法名是自定义的,当你看到dismissDialog时,已经知道这个线程是干嘛的了,还有上面说过:方法引用是为了替换Lambda表达式的,这个可读性也是对Lambda表达式而言

    private final Runnable mDismissAction = this::dismissDialog;
    private final Runnable mDismissAction = () -> {
        //balabala
        //balabala
        //balabala
    };

3.通过类型引用实例方法 ClassName::methodName

官网的示例代码:方法引用String::compareToIgnoreCase会把方法中的参数(String o1, String o2),然后这个方法引用会去调用o1.compareToIgnoreCase(o2); 没看出个所以然来,你们有什么特别的理解可以留言.

image.png
  Barbara
  James
  John
  Linda
  Mary
  Michael
  Patricia
  Robert

4.构造方法引用 Class::new

这里写了一个匿名表达式-->Lambda表达式-->到方法引用的演进,Person实体类,PersonFactory函数式接口,当函数接口中方法参数和构造方法参数一致时,这时候可以考虑使用方法引用中的,构造方法引用


image.png

如果你有天看到了这断代码,一开始会有点难懂

        PersonFactory personFactory = Person::new;

这时候代码要倒过来看:方法引用-->Lmabda表达式-->匿名表达式,引用了Person的构造方法,并把函数式接口中方法参数传了过去

        PersonFactory personFactory = Person::new;

        personFactory = (firstName, lastName) -> new Person(firstName, lastName);

        personFactory = new PersonFactory() {
            @Override
            public Person create(String firstName, String lastName) {
                return new Person(firstName, lastName);
            }
        };        

Stream API

首先,这个Stream API是针对数据容器(集合)的操作, 先来看个例子:扫描一个文件夹,获取视频文件,对大小进行限制,然后对取前面9个,在然后,通过文件名对文件进行排序,然后放到List集合中来:
三种写法对比:谁是你的菜?

  • Java 8以前
  • Stream + Lambda 表达式
  • Stream + Method References


    image.png

怎么用?

  • 对于Collection以及子类(Set,List)调用实例方法.stream()和parallelStream(),区别是前者是顺序,另一个是并发
  • 对于数组使用Arrays.stream(Object[]); (上面示例代码中用法)
  • Stream提供的静态方法Stream.of(Object[])/IntStream.range(int, int)/[Stream.iterate(Object, UnaryOperator)
  • BufferedReader的实例方法lines():获取文件行的流对象
  • Random的实例方法ints();获取随机数流对象
  • ....

流操作:其实更像是工厂的流水线,把数据容器(集合/数组)中的子元素送上流水线,然后对子元素进行一系列的操作(过滤/排序/去重...),最后打包.

这里有两个概念:中间操作,最终操作

  • 中间操作返回Stream流对象,一次处理可以执行多个中间操作
  • 最终操作只能有一个
image.png

常用操作:


image.png

重复注解

对一个元素添加多次同一个类型注解,个人没什么用,一般写框架会用的比较多吧


image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容