Java 5到Java8 的发展

Java 5到Java8 的发展

JDK 5

自动装箱与拆箱

JDK1.5 为每个基本数据类型定义了一个封装类。使 java 中的基本数据类型也有本身的对象javascript

int -->Integer
double --> Double
long --> Long
char --> Character
float --> Float
boolean --> Boolean
short --> Short
byte -- > Byte
  • 自动装包:将基本类型转换成为对象,例如:int --> Integer
  • 自动拆包:将对象转换成为基本数据类型,例如:Integer --> int

对于 JDK1.5 以前集合总不能存放基本数据类型的问题,如今也可以解决。java

枚举

枚举是 JDK1.5 推出的一个比较重要的特性。其关键字为 enum
例如:定义表明交通灯的枚举程序员

public enum MyEnum{    
    RED,GREEN,YELLOW
}

静态导入

  • 优势:使用静态导入可使被导入类的全部静态变量和静态方法在当前类直接可见,使用这些静态成员无需再给出他们的类名。
  • 缺点:过分使用会下降代码的可读性

可变参数

在 JDK1.5 之前,当咱们要为一个方法传递多个类型相同的参数时,
咱们有两种方法解决编程

  1. 直接传递一个数组过去
  2. 有多少个参数就传递多少个参数。

例如:数组

public void printColor(String red,String green,String yellow){ 
}

或者浏览器

public void printColor(String[] colors){}

这样编写方法参数虽然可以实现咱们想要的效果,可是,这样是否是有点麻烦呢?
再者,若是参数个数不肯定,咱们怎么办呢?Java JDK1.5 为咱们提供的可变参数就可以完美的解决这个问题.ruby

例如:微信

public void printColor(String... colors){}

若是参数的类型相同,那么可使用 类型+三个点 ,后面跟一个参数名称的形式。
这样的好处就是,只要参数类型相同,不管传递几个参数都没有限制
注意:可变参数必须是参数列表的最后一项(该特性对对象和基本数据类型都适用)多线程

泛型

//给集合指定存入类型,上面这个集合在存入数据的时候必须存入String类型的数据,不然编译器会报错List<String> strs = new ArrayList<String>();

“泛型” 意味着编写的代码能够被不一样类型的对象所重用。闭包

可见泛型的提出是为了编写重用性更好的代码。

泛型的本质是参数化类型,也就是说所操做的数据类型被指定为一个参数。

好比常见的集合类 LinkedList,其实现的接口名后有个特殊的部分 <>,并且它的成员的类型 Link 也包含一个 <>,这个符号的就是类型参数,它使得在运行中,建立一个 LinkedList 时能够传入不一样的类型,好比 new LinkedList,这样它的成员存放的类型也是 String

For-Each 循环

例如上面这个集合咱们能够经过 for-each 遍历,这样更加简单清晰。

for(String s : strs){      
    System.out.println(s); 
}
注意:使用 for-each 遍历集合时,要遍历的集合必须实现了 Iterator 接口

线程并发库

线程并发库是 Java1.5 提出的关于多线程处理的高级功能,所在包:java.util.concurrent 包括

  1. 线程互斥工具类:LockReadWriteLock
  2. 线程通讯:Condition
  3. 线程池:ExecutorService
  4. 同步队列:ArrayBlockingQueue
  5. 同步集合:ConcurrentHashMapCopyOnWriteArrayList
  6. 线程同步工具:Semaphore

JDK 6

Desktop 类和 SystemTray 类

前者能够用来打开系统默认浏览器浏览指定的 URL,打开系统默认邮件客户端给指定的邮箱发邮件,用默认应用程序打开或编辑文件 (好比,用记事本打开以 txt 为后缀名的文件),用系统默认的打印机打印文档;后者能够用来在系统托盘区建立一个托盘程序。

使用 Compiler API

如今咱们能够用 JDK1.6 的 Compiler API(JSR 199) 去动态编译 Java 源文件,Compiler API 结合反射功能就能够实现动态的产生 Java 代码并编译执行这些代码,有点动态语言的特征。

这个特性对于某些须要用到动态编译的应用程序至关有用,好比 JSP Web Server,当咱们手动修改 JSP 后,是不但愿须要重启 Web Server 才能够看到效果的,这时候咱们就能够用 Compiler API 来实现动态编译 JSP 文件。

固然,如今的 JSP Web Server 也是支持 JSP 热部署的,如今的 JSP Web Server 经过在运行期间经过 Runtime.exec 或 ProcessBuilder 来调用 javac 来编译代码,这种方式须要咱们产生另外一个进程去作编译工做,不够优雅并且容易使代码依赖与特定的操做系统;

Compiler API 经过一套易用的标准的 API 提供了更加丰富的方式去作动态编译,并且是跨平台的。

轻量级 Http Server API

JDK1.6 提供了一个简单的 Http Server API,据此咱们能够构建本身的嵌入式 Http Server,它支持 Http 和 Https 协议,提供了 HTTP1.1 的部分实现,没有被实现的那部分能够经过扩展已有的 Http Server API 来实现,程序员必须本身实现 HttpHandler 接口,HttpServer 会调用 HttpHandler 实现类的回调方法来处理客户端请求,在这里,咱们把一个 Http 请求和它的响应称为一个交换,包装成 HttpExchange 类,HttpServer 负责将 HttpExchange 传给 HttpHandler 实现类的回调方法。

用 Console 开发控制台程序

JDK1.6 中提供了 java.io.Console 类专用来访问基于字符的控制台设备。
你的程序若是要与 Windows 下的 cmd 或者 Linux 下的 Terminal 交互,就能够用 Console 类代劳。
但咱们不老是能获得可用的 Console,一个 JVM 是否有可用的 Console 依赖于底层平台和 JVM 如何被调用。
若是 JVM 是在交互式命令行 (好比 Windows 的 cmd) 中启动的,而且输入输出没有重定向到另外的地方,那么就能够获得一个可用的 Console 实例。

对脚本语言的支持

如:ruby,groovy,javascript。

JDK 7

数字变量对下滑线的支持

JDK1.7 能够在数值类型的变量里添加下滑线。

例如:

int num = 1234_5678_9; 
float num2 = 222_33F; 
long num3 = 123_000_111L;

注意,有几个地方是不能添加的:

  1. 数字的开头和结尾
  2. 小数点先后
  3. F 或者 L 前

switch 对 String 的支持

String status = "orderState";     
switch (status) {   
    case "ordercancel":   
        System.out.println("订单取消");   
        break;   
    case "orderSuccess":   
        System.out.println("预订成功");   
        break;   
    default:   
        System.out.println("状态未知");   
}

try-with-resource

  • try-with-resources 是一个定义了一个或多个资源的 try 声明,这个资源是指程序处理完它以后须要关闭它的对象。
  • try-with-resources 确保每个资源在处理完成后都会被关闭。

可使用 try-with-resources 的资源有: 任何实现了 java.lang.AutoCloseable 接口 java.io.Closeable 接口的对象。

例如:

public static String readFirstLineFromFile(String path) throws IOException {   

    try (BufferedReader br = new BufferedReader(new FileReader(path))) {   
        return br.readLine();   
    }   
}

在 java 7 以及之后的版本里,BufferedReader 实现了 java.lang.AutoCloseable 接口。
因为 BufferedReader 定义在 try-with-resources 声明里,不管 try 语句正常仍是异常的结束,
它都会自动的关掉。而在 java7 之前,你须要使用 finally 块来关掉这个对象。

捕获多种异常并用改进后的类型检查来从新抛出异常

public static void first(){   
    try {   
        BufferedReader reader = new BufferedReader(new FileReader(""));   
        Connection con = null;   
        Statement stmt = con.createStatement();   
    } catch (IOException | SQLException e) {   
        //捕获多个异常,e就是final类型的   
        e.printStackTrace();   
    }   
}

优势:用一个 catch 处理多个异常,比用多个 catch 每一个处理一个异常生成的字节码要更小更高效。

建立泛型时类型推断

只要编译器能够从上下文中推断出类型参数,你就能够用一对空着的尖括号 <> 来代替泛型参数。
这对括号私下被称为菱形 (diamond)。 在 Java SE 7 以前,你声明泛型对象时要这样

List<String> list = new ArrayList<String>();

而在 Java SE7 之后,你能够这样

List<String> list = new ArrayList<>();

由于编译器能够从前面 (List) 推断出推断出类型参数,因此后面的 ArrayList 以后能够不用写泛型参数了,只用一对空着的尖括号就行。
固然,你必须带着菱形 <>,不然会有警告的。
Java SE7 只支持有限的类型推断:只有构造器的参数化类型在上下文中被显著的声明了,你才可使用类型推断,不然不行。

List<String> list = new ArrayList<>();
list.add("A"); 
//这个不行 
list.addAll(new ArrayList<>()); 
// 这个能够 
List<? extends String> list2 = new ArrayList<>(); 
list.addAll(list2);

JDK 8

Lambda 表达式和函数式接口

Lambda 表达式(也称为闭包)是 Java 8 中最大和最使人期待的语言改变。它容许咱们将函数当成参数传递给某个方法,或者把代码自己看成数据处理:函数式开发者很是熟悉这些概念。不少 JVM 平台上的语言(Groovy、Scala 等)从诞生之日就支持 Lambda 表达式,可是 Java 开发者没有选择,只能使用匿名内部类代替 Lambda 表达式。

Lambda 的设计耗费了不少时间和很大的社区力量,最终找到一种折中的实现方案,能够实现简洁而紧凑的语言结构。最简单的 Lambda 表达式可由逗号分隔的参数列表、-> 符号和语句块组成。

Lambda 的设计者们为了让现有的功能与 Lambda 表达式良好兼容,考虑了不少方法,因而产生了函数接口这个概念。函数接口指的是只有一个函数的接口,这样的接口能够隐式转换为 Lambda 表达式。java.lang.Runnable 和java.util.concurrent.Callable 是函数式接口的最佳例子。在实践中,函数式接口很是脆弱:只要某个开发者在该接口中添加一个函数,则该接口就再也不是函数式接口进而致使编译失败。为了克服这种代码层面的脆弱性,并显式说明某个接口是函数式接口,Java 8 提供了一个特殊的注解 @FunctionalInterface(Java 库中的全部相关接口都已经带有这个注解了)。

接口的默认方法和静态方法

Java 8 使用两个新概念扩展了接口的含义:默认方法和静态方法。默认方法使得接口有点相似 traits,不过要实现的目标不同。默认方法使得开发者能够在 不破坏二进制兼容性的前提下,往现存接口中添加新的方法,即不强制那些实现了该接口的类也同时实现这个新加的方法。

默认方法和抽象方法之间的区别在于抽象方法须要实现,而默认方法不须要。接口提供的默认方法会被接口的实现类继承或者覆写。

因为 JVM 上的默认方法的实如今字节码层面提供了支持,所以效率很是高。默认方法容许在不打破现有继承体系的基础上改进接口。该特性在官方库中的应用是:给 java.util.Collection 接口添加新方法,如 stream()、parallelStream()、forEach() 和 removeIf() 等等。

尽管默认方法有这么多好处,但在实际开发中应该谨慎使用:在复杂的继承体系中,默认方法可能引发歧义和编译错误。若是想了解更多细节,能够参考官方文档。

更好的类型推断

Java 8 编译器在类型推断方面有很大的提高,在不少场景下编译器能够推导出某个参数的数据类型,从而使得代码更为简洁。

参数 Value.defaultValue() 的类型由编译器推导得出,不须要显式指明。在 Java 7 中这段代码会有编译错误,除非使用 Value.defaultValue()

Optional

Java 应用中最多见的 bug 就是空指针异常。在 Java 8 以前,Google Guava 引入了 Optionals 类来解决 NullPointerException,从而避免源码被各类 null 检查污染,以便开发者写出更加整洁的代码。Java 8 也将 Optional 加入了官方库。
Optional 仅仅是一个容易存放 T 类型的值或者 null。它提供了一些有用的接口来避免显式的 null 检查,能够参考 Java 8 官方文档了解更多细节。

若是 Optional 实例持有一个非空值,则 isPresent() 方法返回 true,不然返回 false;orElseGet() 方法,Optional 实例持有 null,则能够接受一个 lambda 表达式生成的默认值;map() 方法能够将现有的 Optional 实例的值转换成新的值;orElse() 方法与 orElseGet() 方法相似,可是在持有 null 的时候返回传入的默认值。

Stream

新增的 Stream API(java.util.stream)将生成环境的函数式编程引入了 Java 库中。这是目前为止最大的一次对 Java 库的完善,以便开发者可以写出更加有效、更加简洁和紧凑的代码。

Task 类有一个分数(或伪复杂度)的概念,另外还有两种状态:OPEN 或者 CLOSED。如今假设有一个 task 集合,首先看一个问题:在这个 task 集合中一共有多少个 OPEN 状态的点?

在 Java 8 以前,要解决这个问题,则须要使用 foreach 循环遍历 task 集合;可是在 Java 8 中能够利用 steams 解决:包括一系列元素的列表,而且支持顺序和并行处理。

final Collection<Task> tasks = Arrays.asList(
        new Task(Status.OPEN, 5),
        new Task(Status.OPEN, 13),
        new Task(Status.CLOSED, 8)
);

// 使用sum()计算全部 OPEN 任务
final long totalPointsOfOpenTasks = tasks
        .stream()
        .filter(task -> task.getStatus() == Status.OPEN)
        .mapToInt(Task::getPoints)
        .sum();

System.out.println("Total points: " + totalPointsOfOpenTasks);

首先,tasks 集合被转换成 steam 表示;其次,在 steam 上的 filter 操做会过滤掉全部 CLOSED 的 task;第三,mapToInt 操做基于每一个 task 实例的Task::getPoints方法将 task 流转换成 Integer 集合;最后,经过 sum 方法计算总和,得出最后的结果。

新的日期时间 API

Java 8 引入了新的 Date-Time API(JSR 310) 来改进时间、日期的处理。时间和日期的管理一直是最令 Java 开发者痛苦的问题。java.util.Date 和后来的 java.util.Calendar 一直没有解决这个问题(甚至令开发者更加迷茫)。由于上面这些缘由,诞生了第三方库 Joda-Time,能够替代 Java 的时间管理 API。

Java 8 中新的时间和日期管理 API 深受 Joda-Time 影响,并吸取了不少 Joda-Time 的精华。

第一,新的 java.time 包包含了全部关于日期、时间、时区、Instant(跟日期相似可是精确到纳秒)、duration(持续时间)和时钟操做的类。新设计的 API 认真考虑了这些类的不变性(从 java.util.Calendar 吸收的教训),若是某个实例须要修改,则返回一个新的对象。

第二,关注下 LocalDate 和 LocalTime 类。LocalDate 仅仅包含 ISO-8601 日历系统中的日期部分;LocalTime 则仅仅包含该日历系统中的时间部分。这两个类的对象均可以使用 Clock 对象构建获得。

第三,LocalDateTime 类包含了 LocalDate 和 LocalTime 的信息,可是不包含 ISO-8601 日历系统中的时区信息。这里有一些关于 LocalDate 和 LocalTime 的例子:

若是你须要特定时区的 data/time 信息,则可使用 ZoneDateTime,它保存有 ISO-8601 日期系统的日期和时间,并且有时区信息。

Nashorn JavaScript 引擎

Java 8 提供了新的 Nashorn JavaScript 引擎,使得咱们能够在 JVM 上开发和运行 JS 应用。
Nashorn JavaScript 引擎是 javax.script.ScriptEngine 的另外一个实现版本,这类 Script 引擎遵循相同的规则,容许 Java 和 JavaScript 交互使用。

Base64

对 Base64 编码的支持已经被加入到 Java 8 官方库中,这样不须要使用第三方库就能够进行 Base64 编码。

欢迎转载,转载请注明出处! 独立域名博客:flywill.cn 欢迎关注公众微信号:Java小镇V 分享本身的学习 & 学习资料 & 生活 想要交流的朋友也能够加微信号备注入群:EscUpDn
相关文章
相关标签/搜索