JAVA8增加的特性
Java 8 (又称为 jdk 1.8) 是 Java 语言开发的一个主要版本。 Oracle 公司于 2014 年 3 月 18 日发布 Java 8 ,它支持函数式编程,新的 JavaScript 引擎,新的日期 API,新的Stream API 等。
java8距今已经有五年时间,很多项目早已经在使用java8,相比较于java7,java8多了很多让人舒服的增强。
1、lambda表达式
lambda表达式(闭包)是java8版本中最大的一个特性,允许我们将函数作为参数传递给某个方法,或者直接把代码本身作为数据去处理。
Arrays.asList("a","b","d").forEach((String s) -> System.out.println(s));
Arrays.asList("a","b","d").forEach(s -> System.out.println(s));
函数接口,指的就是只有一个方法签名的接口,这样的接口可以转换成lambda表达式,为了保护这个函数接口,java8特出了一个注解,@FunctionalInterface
此注解方法接口上,如果接口声明第二个方法,则会报错,当然默认方法或者静态方法除外。
@FunctionalInterface
public interface functionDemo {
void method();
default void method2(){
System.out.println("123");
}
static void method3(){
System.out.println("123");
}
}
2、静态方法和默认方法
在java8中提供了静态方法和默认方法,默认方法的目的是为了开发者在不破坏实现类的情况下,对原有接口进行改造,不强制那些已经实现了接口的实现类再实现新的方法。注意,默认方法可以添加多个,没有限制。有了这个默认方法,接口在使用上则越来越靠近了抽象类。@FunctionalInterface
public interface functionDemo {
void method();
default void method2(){
System.out.println("123");
}
default void method4(){
System.out.println("123");
}
static void method3(){
System.out.println("123");
}
}
3、方法引用
方法引用使得开发者可以直接引用现存的方法、Java类的构造方法或者实例对象。方法引用和Lambda表达式配合使用,使得java类的构造方法看起来紧凑而简洁,没有很多复杂的模板代码。
Arrays.sort(stringsArray,(s1,s2)->s1.compareToIgnoreCase(s2));
Arrays.sort(stringsArray, String::compareToIgnoreCase);
方法引用大致上可以分为四种:
类型 | 示例 |
---|---|
引用静态方法 | ContainingClass::staticMethodName |
引用某个对象的实例方法 | containingObject::instanceMethodName |
引用某个类型的任意对象的实例方法 | ContainingType::methodName |
引用构造方法 | ClassName::new |
4、重复注解
在java8之前,一个类,方法,属性上同种注解使用使用一个,java之后可以使用多个,首先,要对注解类进行修饰
使用@Repeatable注解定义重复注解。在使用的时候就可以定义多个注解,
@Target( ElementType.TYPE )
@Retention( RetentionPolicy.RUNTIME )
@Repeatable( Filters.class )
public @interface Filter {
String value();
};
@Filter( "filter1" )
@Filter( "filter2" )
public interface Filterable {
}
public static void main(String[] args) {
for( Filter filter: Filterable.class.getAnnotationsByType( Filter.class ) ) {
System.out.println( filter.value() );
}
}
5、Optional
Java应用中最常见的bug就是空值异常。在Java 8之前,Google Guava引入了Optionals类来解决NullPointerException,从而避免源码被各种null检查污染,以便开发者写出更加整洁的代码。Java 8也将Optional加入了官方库。Optional仅仅是一个容易:存放T类型的值或者null。它提供了一些有用的接口来避免显式的null检查。
Optional<String> test = Optional.ofNullable(null);
System.out.println(test.isPresent());
String zz =test.map(s -> s+="123").orElse("testset");
System.out.println(zz);
--------结果-----
false
testset
6、Stream
新增的Stream API(java.util.stream)将生成环境的函数式编程引入了Java库中。这是目前为止最大的一次对Java库的完善,以便开发者能够写出更加有效、更加简洁和紧凑的代码。Steam API极大得简化了集合操作。
Arrays.asList(4,2,5,1,7,9).stream().sorted().forEach(i -> System.out.println(i));
Stream(流)是一个来自数据源的元素队列并支持聚合操作
- 元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。
- 数据源 流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。
- 聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。
和以前的Collection操作不同, Stream操作还有两个基础的特征:
- Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
- 内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。
Stream分为两种:
- stream() − 为集合创建串行流。
- parallelStream() − 为集合创建并行流。
Stream到底给我们带来了多少便利?
- forEach 排序操作,迭代流中的每个数据。
random.ints().limit(10).forEach(System.out::println);
- map 映射每个元素到对应的结果,
List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
- filter 过滤,符合添加的过滤掉 ` strings.stream().filter(string -> string.isEmpty())`
- limit 获取指定数量的流
random.ints().limit(10).forEach(System.out::println);
- sorted 对流进行排序
andom.ints().limit(10).sorted().forEach(System.out::println);
- paraller 并行流
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); // 获取空字符串的数量 int count = strings.parallelStream().filter(string -> string.isEmpty()).count();
- 统计
7、Date 和Time的API
Java 8引入了新的Date-Time API(JSR 310)来改进时间、日期的处理。时间和日期的管理一直是最令Java开发者痛苦的问题。因为上面这些原因,诞生了第三方库Joda-Time,可以替代Java的时间管理API。Java 8中新的时间和日期管理API深受Joda-Time影响,并吸收了很多Joda-Time的精华。新的java.time包包含了所有关于日期、时间、时区、Instant(跟日期类似但是精确到纳秒)、duration(持续时间)和时钟操作的类。新设计的API认真考虑了这些类的不变性。
8、Nashorn JavaScript引擎
Java 8提供了新的Nashorn JavaScript引擎,使得我们可以在JVM上开发和运行JS应用。
9、Base64
-
对Base64编码的支持已经被加入到Java 8官方库中,这样不需要使用第三方库就可以进行Base64编码。
String encoded = Base64 .getEncoder() .encodeToString( text.getBytes( StandardCharsets.UTF_8 ) ); String decoded = new String( Base64.getDecoder().decode( encoded ), StandardCharsets.UTF_8 );
10、新的命令行工具Jdeps
jdeps是一个相当棒的命令行工具,它可以展示包层级和类层级的Java类依赖关系,它以.class文件、目录或者Jar文件为输入,然后会把依赖关系输出到控制台。简单测试一下:
jdeps DemoApplication.class
DemoApplication.class -> E:\program files\Java\jdk1.8\jre\lib\rt.jar
DemoApplication.class -> 找不到
com.example.demo (DemoApplication.class)
-> java.lang
-> org.springframework.boot 找不到
-> org.springframework.boot.autoconfigure 找不到
-> org.springframework.context 找不到
在学习新的框架,找类依赖关系可以试试这个,比如spring-core包
jdeps spring-core-2.5.6.SEC03.jar
spring-core-2.5.6.SEC03.jar -> E:\program files\Java\jdk1.8\jre\lib\rt.jar
spring-core-2.5.6.SEC03.jar -> 找不到
org.springframework.asm (spring-core-2.5.6.SEC03.jar)
-> java.io
-> java.lang
-> java.lang.reflect
org.springframework.asm.commons (spring-core-2.5.6.SEC03.jar)
-> java.io
-> java.lang
-> java.security
-> java.util
-> org.springframework.asm spring-core-2.5.6.SEC03.jar
org.springframework.asm.signature (spring-core-2.5.6.SEC03.jar)
-> java.lang
org.springframework.core (spring-core-2.5.6.SEC03.jar)
-> edu.emory.mathcs.backport.java.util.concurrent 找不到
-> java.io
-> java.lang
-> java.lang.ref
-> java.lang.reflect
-> java.util
-> java.util.concurrent
-> org.apache.commons.collections 找不到
-> org.apache.commons.collections.map 找不到
-> org.apache.commons.logging 找不到
-> org.springframework.asm spring-core-2.5.6.SEC03.jar
-> org.springframework.asm.commons spring-core-2.5.6.SEC03.jar
-> org.springframework.util spring-core-2.5.6.SEC03.jar
org.springframework.core.annotation (spring-core-2.5.6.SEC03.jar)
...