AndroidStudio与Java8(一)

来源:互联网 发布:淘宝商品展示页面html 编辑:程序博客网 时间:2024/06/12 20:31

前言

从3月14日Android Developers在Google+上发布的文章来说,Android要支持Java8了。当时说的是在新版的Android Studio中提供支持,并且是in the coming weeks.想着肯定是2.4了,果然2.4pre版就发了。然而等了一个月正式版还是不见发布,估摸着要在I/O大会上发布了也不一定(然额,I/O上说要发布3.0版本了。。。)。7.0发布的时候就支持Java8 了,然而也就是观望了观望,一直也没用Java8开发过,由于需要useJack,又面向Android7.0,所以没在实际开发中用过,既然Studio开始支持Java8了,构建当然简单多了,翻了翻去年整理的东西,在这里瞅一瞅,说不定就快要用上了。

相信近年来学习Java的应该都是以Java5.0为基础学习的,那么后来Java6、7、8发生了什么,以及快要发布的Java9有些什么特性呢?来瞅一瞅。当然,Java9今天没打算说,毕竟暂时肯定用不上。

Java6

恩,这是个无所谓的东东。
主要是内部的一些更新:

  • 引入了一个支持脚本引擎的新框架
  • UI的增强
  • 对WebService支持的增强(JAX-WS2.0和JAXB2.0)
  • 一系列新的安全相关的增强
  • JDBC4.0
  • Compiler API
  • 通用的Annotations支持

Java7

  1. switch中可以使用字符串了
    Java7之前switch不能对字符串操作是个很麻烦的事,于是乎,支持了。
  2. 泛型实例化类型自动推断
    List<String> tempList = new ArrayList<>();
    这在Android Studio里应该很常见了,右侧的尖括号中不用写泛型类型了。
  3. 数值可加下划线:
    int one_million = 1_000_000;
    数字加上下划线方便阅读。
  4. 支持二进制文字
    int binary = 0b1001_1001;
  5. 在try catch异常扑捉中,一个catch可以写多个异常类型,用”|”隔开:

    try {     ...} catch(ClassNotFoundException | SQLException ex){     ex.printStackTrace(); }
  6. jdk7之前,你必须用finally{}在try内使用资源,在finally中关闭资源,不管try中的代码是否正常退出或者异常退出。
    jdk7之后,你可以不必要写finally语句来关闭资源,只要你在try()的括号内部定义要使用的资源。

    try (BufferedReader in = new BufferedReader(new FileReader("in.txt"));     BufferedWriter out = new BufferedWriter(new FileWriter("out.txt"))) {    int charRead;    while ((charRead = in.read()) != -1) {         System.out.printf("%c ", (char)charRead);         out.write(charRead);     }} catch (IOException ex) {     ex.printStackTrace(); }

    注意:需添加@TargetApi(Build.VERSION_CODES.KITKAT)—19

  7. 自动关闭类

    public interface AutoCloseable {   / * * Closes this resource, relinquishing any underlying resources.       *  This method is invoked automatically on objects managed by the      *  {@code try}-with-resources statement.       * */     void close() throws Exception; }

    只要实现该接口,在该类对象销毁时自动调用close方法,你可以在close方法关闭你想关闭的资源。

此外,还有一些Java7的特性,在Android中不能使用。不想看的这部分可以跳过。


  • 语法上支持集合,而不一定是数组
List<String> list=["item"]; //向List集合中添加元素String item=list[0]; //从List集合中获取元素Set<String> set={"item"}; //向Set集合对象中添加元素Map<String,Integer> map={"key":1}; //向Map集合中添加对象int value=map["key"]; //从Map集合中获取对象
  • 新增一些取环境信息的工具方法
File System.getJavaIoTempDir() // IO临时文件夹File System.getJavaHomeDir() // JRE的安装目录File System.getUserHomeDir() // 当前用户目录File System.getUserDir() // 启动java进程时所在的目录
  • Boolean类型反转,空指针安全,参与位运算
Boolean Booleans.negate(Boolean booleanObj)//True => False , False => True, Null => Nullboolean Booleans.and(boolean[] array)boolean Booleans.or(boolean[] array)boolean Booleans.xor(boolean[] array)
  • 两个char间的equals
boolean Character.equalsIgnoreCase(char ch1, char ch2)
  • 安全的加减乘除
int Math.safeToInt(long value)int Math.safeNegate(int value)long Math.safeSubtract(long value1, int value2)long Math.safeSubtract(long value1, long value2)int Math.safeMultiply(int value1, int value2)long Math.safeMultiply(long value1, int value2)long Math.safeMultiply(long value1, long value2)long Math.safeNegate(long value)int Math.safeAdd(int value1, int value2)long Math.safeAdd(long value1, int value2)long Math.safeAdd(long value1, long value2)
  • map集合支持并发请求,且可以写成
    Map map = {name:"xxx",age:18};

这些用不到,看看不犯罪。


Java8

恩,正式说的Java8了。
先瞅一眼Android Studio2.4支持的Java8新特性有哪些吧,上图:

java8

那就先按照这个顺序说吧。一篇感觉说不完,分两篇说了。

Lambda表达式(Lambda expressions)

前世——来自C

在 C# 1.0 时,C#中就引入了委托(delegate)类型的概念。通过使用这个类型,我们可以将函数作为参数进行传递。在某种意义上,委托可理解为一种托管的强类型的函数指针。
通常情况下,使用委托来传递函数需要一定的步骤:

  1. 定义一个委托,包含指定的参数类型和返回值类型。
  2. 在需要接收函数参数的方法中,使用该委托类型定义方法的参数签名。
  3. 为指定的被传递的函数创建一个委托实例。

可能这听起来有些复杂,不过本质上说确实是这样。上面的第 3 步通常不是必须的,C# 编译器能够完成这个步骤,但步骤 1 和 2 仍然是必须的。
幸运的是,在 C# 2.0 中引入了泛型。现在我们能够编写泛型类、泛型方法和最重要的:泛型委托。尽管如此,直到 .NET 3.5,微软才意识到实际上仅通过两种泛型委托就可以满足 99% 的需求:

Action :无输入参数,无返回值
Action :支持1-16个输入参数,无返回值
Func :支持1-16个输入参数,有返回值

Action 委托返回 void 类型,Func 委托返回指定类型的值。通过使用这两种委托,在绝大多数情况下,上述的步骤 1 可以省略了。但是步骤 2 仍然是必需的,但仅是需要使用 Action 和 Func。
那么,如果我只是想执行一些代码该怎么办?在 C# 2.0 中提供了一种方式,创建匿名函数。但可惜的是,这种语法并没有流行起来。下面是一个简单的匿名函数的示例:

Func<double, double> square = delegate(double x){    return x * x;};

为了改进这些语法,在 .NET 3.5 框架和 C# 3.0 中引入了Lambda 表达式。
首先,Lambda来自微积分数学中的 λ,其涵义是声明为了表达一个函数具体需要什么。
更确切的说,它描述了一个数学逻辑系统,通过变量结合和替换来表达计算。所以,基本上我们有 0-n 个输入参数和一个返回值。而在编程语言中,我们也提供了无返回值的 void 支持。

Funcdouble<double, double>  product = (x, y) => x * y;Funcdouble<double>  square = x => x * x;Actiondouble<double>  printProduct = (x, y) => { Console.WriteLine(x * y); };

从这些语句中可以看出:
- 如果仅有一个入参,则可省略圆括号。
- 如果仅有一行语句,并且在该语句中返回,则可省略大括号,并且也可以省略 return 关键字。

今生——Android中的Lambda表达式

首先来看一段代码:
对字符串的比较排序问题:

List<String> names = Arrays.asList("aaa", "eee", "sss", "ccc");Collections.sort(names, new Comparator<String>() {    @Override    public int compare(String a, String b) {        return b.compareTo(a);    }});

只需要给静态方法 Collections.sort 传入一个List对象以及一个比较器来按指定顺序排列。通常做法都是创建一个匿名的比较器对象然后将其传递给sort方法。
在Java 8 中提供了更简洁的语法,Lambda表达式:

Collections.sort(names, (String a, String b) -> {    return b.compareTo(a);});

实际上还可以写得更短,只有一行代码的,省略大括号,省略return:

Collections.sort(names, (String a, String b) -> b.compareTo(a));

但是还可以写得更短点,嗯,省略掉参数类型:

Collections.sort(names, (a, b) -> b.compareTo(a));

简直短到爆。

怎么来的?——函数式接口

Lambda 表达式是如何在java的类型系统中表示的呢?
其实说白了,Lambda 表达式就是只有一个抽象方法的接口的使用上的语法糖。
对于一个接口类,如果这个接口类中只有一个方法时,那它就可以使用Lambda 表达式来简化写法。
“函数式接口”是指仅仅只包含一个抽象方法的 接口,lambda表达式可以当作任意只包含一个抽象方法的接口类型,确保你的接口一定达到这个要求,你只需要给你的接口添加 @FunctionalInterface 注解(即函数式接口),编译器如果发现你标注了这个注解的接口有多于一个抽象方法的时候会报错的。不过@FunctionalInterface要在API24之后才支持。

Lambda的作用域

1.在lambda表达式中访问外层的局部变量:

final  int num = 1;Converter<Integer, String> stringConverter = (from) -> String.valueOf(from + num);stringConverter.convert(2);     // 3

这里的变量num可以不用声明为final,
不过这里的num必须不可被后面的代码修改(即隐性的具有final的语义)

2.无法访问接口中的default方法
这里只好先介绍一下,Java8中的接口可以写默认方法,即允许我们给接口添加一个非抽象的方法实现(感觉像个抽象类了),只需要使用 default关键字即可,这个特征又叫做扩展方法,示例如下:

interface JDK8_Interface{        double method1(int a);          default double sqrt(int a) {            return Math.sqrt(a);        }}

在例子中的接口类JDK8_Interface 中,在拥有method1方法之外同时还定义了sqrt方法,实现了JDK8_Interface接口的子类只需要实现一个method1方法,默认方法sqrt将在子类上可以直接使用。
而这里定义的默认方法default sqrt(),在Lambda表达式中是无法访问的。

使用Lambda表达式

之前,可以使用useJack来构建Lambda表达式:

1.compileSdkVersion  24及以上2.Gradle配置:defaultConfig {    useJack(true)}compileOptions {   sourceCompatibility JavaVersion.VERSION_1_8   targetCompatibility JavaVersion.VERSION_1_8}

Android Studio2.4发布之后,只用写compileOptions就可以了。

方法引用(Method References)

Java8允许传递方法的引用,可以理解为指针,用类名或实例去调用方法。通过::关键字来使用。
看个例子:

//定义一个支持lambda表达式的接口:@FunctionalInterface interface Converter<F, T> {    T convert(F from);//把F类型的数据转换成T类型的数据}//lambda表达式Converter<String, Integer> stringConverter = (from) -> Integer.valueOf(from);//使用::关键字Converter<String, Integer> converter = Integer::valueOf; 

很明显,使用::关键字相当于省略参数和括号,并把“.”改成“::”在Lambda表达式中显得更简洁。
::关键字左侧可以为类名,也可以是一个实例对象。

类型注解(Type Annotations)

Java8允许编写一种类型检查框架,该框架实现为与Java编译器结合使用的一个或多个可插拔模块。例子:@NonNull String str;
嗯,有Android里的注解的样子,什么@ColorInt之类的注解就是这种了。

默认方法(Default and static interface methods)

这个在上边Lambda表达式的作用范围的时候提前说过了,没仔细看的翻回去瞧瞧。

多重注解(Repeating annotations)

Java8中的注解允许使用多重注解,例子:

//老方法,两个注解值使用这种方式。@Colors({@Color("red"), @Color("green")})class Car{}//新方法,写两个注解即可@Color("red")@Color("green")class Car {}

那么,多重注解是怎么定义的呢?以及怎么获取注解值,在下边介绍:

//定义方式@interface Colors {    Color[] value();}@Repeatable(Colors.class)@interface Color {    String value();}//获取方式Color color= Car.class.getAnnotation(Color.class);System.out.println(color);// nullColors colors1 =Car.class.getAnnotation(Colors.class);//先获取Hints注解内容System.out.println(colors1.value().length);// 2Color[] colors2 =Car.class.getAnnotationsByType(Color.class);System.out.println(colors2.length);// 2

此外,Java8注解还新增了两种新的target

@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})@interface JavaAnnotation {}

还没结束

感觉篇幅太长看起来有点累,下一篇才是重点,介绍Java8中的流(Stream)和函数式接口(FunctionalInterface),休息一下接着看。

2 1
原创粉丝点击