所有示例代码打包下载 : 点击打开链接
Java8新特性 :
- 接口新增默认方法和静态方法
- Optional类
- Lambda表达式
- 方法引用
- Stream API - 函数式操作流元素集合
- Date/Time API
- 新API和工具
- Nashorn , JavaScript引擎
7 . 新API和工具
7.1 重复注解
Java8之前 , 注解在同一位置只能声明一次 . 在Java8中 , 允许同一个位置声明多次注解 .
重复注解机制本身必须用@Repetable注解 , 事实上 , 这并不是语言层面上的改变 , 更多的是编译器的技巧 , 底层的原理保持不变package com.xbz.java8.newApi;
import java.lang.annotation.*;
public class RepeatingAnnotationDemo {
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Filters {
Filter[] value();
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Filters.class)
public @interface Filter {
String value();
}
@Filter("filter1")
@Filter("filter2")
interface Filterable {
}
public static void main(String[] args) {
for (Filter filter : Filterable.class.getAnnotationsByType(Filter.class)) {
System.out.println(filter.value());
}
}
}
正如我们看到的,这里有个使用@Repeatable( Filters.class )注解的注解类Filter,Filters仅仅是Filter注解的数组,但Java编译器并不想让程序员意识到Filters的存在。这样,接口Filterable就拥有了两次Filter(并没有提到Filter)注解。
同时,反射相关的API提供了新的函数getAnnotationsByType()来返回重复注解的类型(请注意Filterable.class.getAnnotation( Filters.class )经编译器处理后将会返回Filters的实例)。
7.2 Base64
Base64在java8中转正了,不需要再使用sun.misc.BASE64Encoder和sun.misc.BASE64Decoder了, 而是java.util.Base64,这是一个工厂类,它用来创建两个内部实现类,即Base64 编码的编码器和解码器。
Base64工具类提供了一套静态方法获取下面三种BASE64编解码器:
- 基本:输出被映射到一组字符A-Za-z0-9+/,编码不添加任何行标,输出的解码仅支持A-Za-z0-9+/。
- URL:输出映射到一组字符A-Za-z0-9+_,输出是URL和文件。
- MIME:输出隐射到MIME友好格式。输出每行不超过76字符,并且使用'\r'并跟随'\n'作为分割。编码输出最后没有行分割。
序号 | 方法 | 描述 |
1 | static Base64.Decoder getDecoder() | 返回一个 Base64.Decoder ,解码使用基本型 base64 编码方案。 |
2 | static Base64.Encoder getEncoder() | 返回一个 Base64.Encoder ,编码使用基本型 base64 编码方案。 |
3 | static Base64.Decoder getMimeDecoder() | 返回一个 Base64.Decoder ,解码使用 MIME 型 base64 编码方案。 |
4 | static Base64.Encoder getMimeEncoder() | 返回一个 Base64.Encoder ,编码使用 MIME 型 base64 编码方案。 |
5 | static Base64.Encoder getMimeEncoder(int lineLength, byte[] lineSeparator) | 返回一个 Base64.Encoder ,编码使用 MIME 型 base64 编码方案,可以通过参数指定每行的长度及行的分隔符。 |
6 | static Base64.Decoder getUrlDecoder() | 返回一个 Base64.Decoder ,解码使用 URL 和文件名安全型 base64 编码方案。 |
7 | static Base64.Encoder getUrlEncoder() | 返回一个 Base64.Encoder ,编码使用 URL 和文件名安全型 base64 编码方案。 |
Base64.Encoder encoder = Base64.getEncoder();
String str = "abcd";
String enc = encoder.encodeToString(str.getBytes());
System.out.println(enc);
System.out.println(new String(Base64.getDecoder().decode(enc)));
7.3 try/catch 异常捕获的改变
新的try/catch可以自动关闭在try表达式中打开的对象 , 而无需开发者手动关闭 ,即不用再写finally了try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("p1.obj"))) {
System.out.println(TryCatchDemo.class.hashCode());
TryCatchDemo demo = (TryCatchDemo) in.readObject();
System.out.println(demo.getClass().getName());
} catch (Exception e) {
e.printStackTrace();
}
//自动关闭in对象 , 无需再写finally{in.close();}
7.4 并行(parallel)数组
Java 8增加了大量的新方法来对数组进行并行处理。可以说,最重要的是parallelSort()方法,因为它可以在多核机器上极大提高数组排序的速度实例:并行初始化一个20000的数组,并且填充1000000内的随机数,然后并行排序
package com.xbz.java8.newApi;
import java.time.Duration;
import java.time.LocalTime;
import java.util.Arrays;
import java.util.concurrent.ThreadLocalRandom;
public class ParallelArraysDemo {
public static void main(String[] args) {
LocalTime begin = LocalTime.now();
long[] arrayOfLong = new long[20000];
Arrays.parallelSetAll(arrayOfLong, index -> ThreadLocalRandom.current().nextInt(1000000));
Arrays.stream(arrayOfLong).limit(10).forEach(i -> System.out.print(i + " "));
System.out.println();
Arrays.parallelSort(arrayOfLong);
Arrays.stream(arrayOfLong).limit(10).forEach(i -> System.out.print(i + " "));
System.out.println();
System.out.println(Duration.between(begin, LocalTime.now()));
}
}
7.5 拓宽注解的应用场景
Java 8拓宽了注解的应用场景。现在,注解几乎可以使用在任何元素上:局部变量、接口类型、超类和接口实现类,甚至可以用在函数的异常定义上。下面是一些例子:package com.xbz.java8.newApi;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.Collection;
public class AnnotationsDemo {
@Retention( RetentionPolicy.RUNTIME )
@Target( { ElementType.TYPE_USE, ElementType.TYPE_PARAMETER } )
public @interface NonEmpty {
}
public static class Holder< @NonEmpty T > extends @NonEmpty Object {
public void method() throws @NonEmpty Exception {
}
}
@SuppressWarnings( "unused" )
public static void main(String[] args) {
final Holder< String > holder = new @NonEmpty Holder< String >();
@NonEmpty Collection< @NonEmpty String > strings = new ArrayList<>();
}
}
7.6 参数名称
为了在运行时获得Java程序中方法的参数名称,老一辈的Java程序员必须使用不同方法,例如Paranamer liberary。Java 8终于将这个特性规范化,在语言层面(使用反射API和Parameter.getName()方法)和字节码层面(使用新的javac编译器以及-parameters参数)提供支持。 Method method = ParameterNameDemo.class.getMethod("main", String[].class);
for (final Parameter parameter : method.getParameters()) {
System.out.println("Parameter: " + parameter.getName());
}
在Java 8中这个特性是默认关闭的,因此如果不带-parameters参数编译上述代码并运行,则会输出如下结果:Parameter: arg0
如果带-parameters参数,则会输出如下结果(正确的结果):Parameter: args