从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今天没打算说,毕竟暂时肯定用不上。
恩,这是个无所谓的东东。
主要是内部的一些更新:
List tempList = new ArrayList<>();
int one_million = 1_000_000;
int binary = 0b1001_1001;
在try catch异常扑捉中,一个catch可以写多个异常类型,用”|”隔开:
try {
...
} catch(ClassNotFoundException | SQLException ex){
ex.printStackTrace();
}
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
自动关闭类
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 list=["item"]; //向List集合中添加元素
String item=list[0]; //从List集合中获取元素
Set set={"item"}; //向Set集合对象中添加元素
Map 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 Booleans.negate(Boolean booleanObj)//True => False , False => True, Null => Null
boolean Booleans.and(boolean[] array)
boolean Booleans.or(boolean[] array)
boolean Booleans.xor(boolean[] array)
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 = {name:"xxx",age:18};
这些用不到,看看不犯罪。
恩,正式说的Java8了。
先瞅一眼Android Studio2.4支持的Java8新特性有哪些吧,上图:
那就先按照这个顺序说吧。一篇感觉说不完,分两篇说了。
在 C# 1.0 时,C#中就引入了委托(delegate)类型的概念。通过使用这个类型,我们可以将函数作为参数进行传递。在某种意义上,委托可理解为一种托管的强类型的函数指针。
通常情况下,使用委托来传递函数需要一定的步骤:
可能这听起来有些复杂,不过本质上说确实是这样。上面的第 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 product = (x, y) => x * y;
Funcdouble square = x => x * x;
Actiondouble printProduct = (x, y) => { Console.WriteLine(x * y); };
从这些语句中可以看出:
- 如果仅有一个入参,则可省略圆括号。
- 如果仅有一行语句,并且在该语句中返回,则可省略大括号,并且也可以省略 return 关键字。
首先来看一段代码:
对字符串的比较排序问题:
List names = Arrays.asList("aaa", "eee", "sss", "ccc");
Collections.sort(names, new Comparator() {
@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之后才支持。
1.在lambda表达式中访问外层的局部变量:
final int num = 1;
Converter 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表达式中是无法访问的。
之前,可以使用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就可以了。
Java8允许传递方法的引用,可以理解为指针,用类名或实例去调用方法。通过::关键字来使用。
看个例子:
//定义一个支持lambda表达式的接口:
@FunctionalInterface
interface Converter {
T convert(F from);//把F类型的数据转换成T类型的数据
}
//lambda表达式
Converter stringConverter = (from) -> Integer.valueOf(from);
//使用::关键字
Converter converter = Integer::valueOf;
很明显,使用::关键字相当于省略参数和括号,并把“.”改成“::”在Lambda表达式中显得更简洁。
::关键字左侧可以为类名,也可以是一个实例对象。
Java8允许编写一种类型检查框架,该框架实现为与Java编译器结合使用的一个或多个可插拔模块。例子:@NonNull String str;
嗯,有Android里的注解的样子,什么@ColorInt之类的注解就是这种了。
这个在上边Lambda表达式的作用范围的时候提前说过了,没仔细看的翻回去瞧瞧。
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);// null
Colors colors1 =Car.class.getAnnotation(Colors.class);//先获取Hints注解内容
System.out.println(colors1.value().length);// 2
Color[] 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),休息一下接着看。