美文网首页JDK8Android开发笔记Android知识
JAVA8新特性在Android编程的实践研究(一)

JAVA8新特性在Android编程的实践研究(一)

作者: NKming | 来源:发表于2017-04-02 16:04 被阅读369次

    前言

    其实Java8已经出现了很久,听闻Java9都准备出了,但是现在普及率并不不是很高,主流的开发环境依然是Java7,甚至有些依然在使用Java5等比较老旧的开发环境。作为一名Android开发者,Java是我们的主要开发语言,我们还是很有必要去了解并且使用最新型的技术,而且Java8中有许多新的特性也是有利于提高我们开发效率的,下面我来一一介绍一下。

    本文参考了很多网络上已有的文章,且已注明出处。

    介绍

    在Android编程中使用Java8新特性,需要先在Android studio中配置一下,具体配置方法,可参考此配置

    接口默认方法

    在java8中,接口可以添加默认的方法以及静态方法,其类型也是public abstract的类型,实现方式如下:

    public interface DataSource<T> {
    
        List<T> reqeustData(String name);
    
        @RequiresApi(api = Build.VERSION_CODES.N)
        default void defaultMethod() {
            Log.i("DataSource", "i am defaultMethod");
        }
        
        static void staticMethod(){
            Log.i("DataSource", "i am staticMethod");
        }
    }
    

    需要注意的是,接口默认方法现在只能在Android N以上才支持,所以使用的时候要添加声明。

    相比于传统的接口,我们在Java8中可以添加默认的方法,而这个默认方法的类型同样是public 的,所以我们可以把它当做正常方式使用,只是无需去实现。在实际项目当中,当一个接口被多个类实现时,我们去拓展接口里面的方法时会导致工程量变大,而当我们引入接口默认方法时,就无需去修改每个类。

    当一个接口扩展另外一个包含默认方法的接口的时候,有以下3种处理方式。

    • 完全无视默认方法
      直接继承了上级接口的默认方法
    • 重新申明默认方法
      重新把默认方法申明为抽象方法(无实现,具体子类必需再次实现该方法)
    • 重新实现默认方法
      重写了默认方法的实现,依然是一个默认方法。

    我觉得如果对访问权限没有特别要求的,接口基本上能够代替抽象类,而且还能实现多继承。如果对抽象类和接口默认方法感兴趣的童鞋,可以参考这篇文章Java 8 之默认方法(Default Methods)

    Lambda表达式

    Lambda表达式又称为闭包或匿名方法,我觉得lambda表示式式Java8中最受欢迎的一个特性,因为只要用习惯了这个表达式,就不会再想去用旧的方法来实现了。

    Lambda表达式我相信很多人已经听说过,所以我就不做过多介绍,主要说一下我在Android开发中使用到的一些场景:

            button.setOnClickListener(v->showLog("hello"));
            new Thread(()->showLog("hello")).start();
            //多个参数的写法
            List<String> names = Arrays.asList("nickming", "peter", "mike");
            Collections.sort(names, (a, b) -> b.compareTo(a));
            names.forEach(this::showLog);
    

    当然,这只是lambda运用的一部分示例,总结起来lambda的作用就是:

    • 简化代码,可以不用再写匿名内部类,可以将多行代码简化为一行代码。
    • 提供函数式接口,实现函数式编程
    • 提升Java性能

    强烈建议在编程中多使用lambda表达式,特别是配合RxJava以及RxAndroid的使用,写起代码真的是行云流水一气呵成。感兴趣的童鞋可以参考这篇文章Lambda表达式的意义

    但是使用lambda表达式需要注意几点:

    • 在lambda表达式中可以直接访问外层final变量、实例、静态变量。
    • 访问未标记final的变量时,该变量会具有隐形final属性,如果后续更改变量值,会导致编译不通过。
    • 在lambda表达式中,对于内部实例和静态变量可读可写。
    • lambda无法访问到接口的默认方法。

    函数式接口

    “函数式接口”是指仅仅只包含一个抽象方法的接口,每一个该类型的lambda表达式都会被匹配到这个抽象方法。因为 默认方法 不算抽象方法,所以你也可以给你的函数式接口添加默认方法。

    @FunctionalInterface
    public interface Converter<F,T> {
        T convert(F from);
    }
    
    Converter<Integer,String> converter= (f)->String.valueOf(f);
    converter.convert(1);
    
    Converter<String,Integer> converter3=Integer::new;
    Converter<String,Integer> converter2=Integer::valueOf;
    

    这是我们自定义的函数式接口,其实在Java8中已经给很多接口都预置了FunctionalInterface这个关键字,所以这是Java8支持函数式编程的一个重要原因之一,像Runnable、Comparator等接口在Java8中都是标记有FunctionalInterface关键字的。感兴趣的童鞋可以参考这篇文章函数式接口

    由于是函数式编程,在我个人理解就是将函数当做编程的基础,区别于我们之前的面向对象的编程,我们所有操作都以函数为基础,函数可以当做其他函数的变量参数,也可以当做其他函数的返回结果。

    既然Java8支持函数式编程,所以其提供了方法与构造函数引用这个方式,就像我们可以直接通过Integer::new来实现converter,new是直接实现integer的构造函数,valueOf是其方法引用,只要其返回结果是接口需要实现的返回类型即可。

    其实在许多场景下,我们可以直接利用 :: 这个符号来实现方法的引用,例如上文提到的

    names.forEach(this::showLog)
    

    这一行代码中,我们省略了for循环,实际上forEach函数式stream特性的一个,下文会提到。forEach函数需要实现Consumer接口,接着在实现其accept方法:

            names.forEach(new Consumer<String>() {
                @Override
                public void accept(String s) {
                    showLog(s);
                }
            });
            //lambda表达式
            names.forEach(s->showLog(s));
            //方法引用
            names.forEach(this::showLog);
    

    直接组合利用lambda表达式和方法引用,可以简化代码,表达值简单明了。

    常见的函数接口

    Java8实际上提供了很多常用的函数式接口,都位于package java.util.function包下面,常用的如下:

    • Predicate 接口只有一个参数,返回boolean类型。该接口包含多种默认方法来将Predicate组合成其他复杂的逻辑(比如:与,或,非)
    • **Function **接口有一个参数并且返回一个结果,并附带了一些可以和其他函数组合的默认方法(compose, andThen)
    • **Supplier **接口返回一个任意范型的值,和Function接口不同的是该接口没有任何参数
    • **Consumer **接口表示执行在单个参数上的操作
    • **Comparator **是老Java中的经典接口, Java 8在此之上添加了多种默认方法
    • **Optional **被定义为一个简单的容器,其值可能是null或者不是null。在Java 8之前一般某个函数应该返回非空对象但是偶尔却可能返回了null,而在Java 8中,不推荐你返回null而是返回Optional

    我就不仔细分析每个接口的作用了,主要参考函数式接口这篇文章。

    其实,当你尝试过使用RxJava和RxAndroid后,你会发现这些x里面的很多概念都是做法都是和Java8中很相似的,都是提供了各种函数操作符,各种函数接口实现。

    小结

    在这篇文章中,主要是介绍了一下接口默认方法、lambda表达式、函数式接口、方法构造函数的引用这几个特性,在下一篇文章中会着重介绍一下streamDate APIAnnotationCompletableFuture几个特性。

    JAVA8新特性在Android编程的实践研究(二)

    相关文章

      网友评论

      • 曾经的你呀:接口默认方法 我在4.2.2 上使用也没有什么问题啊

      本文标题:JAVA8新特性在Android编程的实践研究(一)

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