Jdk版本新特性

2016/08/29 Java

JDK各版本新特性总结

JDK1.4

NIO

JDK 1.5

静态导入

  • 被导入方法必须是静态的
  • 如果有多个同名的静态方法,容易不知道使用谁?这个时候要使用,必须加前缀。由此可见,意义不大,所以一般不用,但是要能看懂。
import static java.lang.Math.abs;
import static java.lang.Math.pow;
import static java.lang.Math.max;

//错误
//import static java.util.ArrayList.add;

public class test {
    public static void main(String[] args) {
        // System.out.println(java.lang.Math.abs(-100));
        // System.out.println(java.lang.Math.pow(2, 3));
        // System.out.println(java.lang.Math.max(20, 30));
        // 太复杂,我们就引入到import

        // System.out.println(Math.abs(-100));
        // System.out.println(Math.pow(2, 3));
        // System.out.println(Math.max(20, 30));
        // 太复杂,有更简单

//      System.out.println(abs(-100));
        System.out.println(java.lang.Math.abs(-100));
        System.out.println(pow(2, 3));
        System.out.println(max(20, 30));
    }
    
    public static void abs(String s){
        System.out.println(s);
    }
}

自动装箱、拆箱

Integer i = 1;//装箱
int j = i;//拆箱

// ==比较时候也会自动拆箱
Integer localInteger = Integer.valueOf(1);
if (localInteger.intValue() == 1) {
}

switch可以使用枚举值

增强for循环

public static int add(int x,int ...args) {
    int sum = x;
    for(int arg:args) {
        sum += arg;
    }
    return sum;
}

注意

  • 集合变量可以是数组或实现了Iterable接口的集合类

可变参数

public void game(int a,String ...args){
}
  • 只能出现在参数列表的最后
  • …位于变量类型和变量名之间,前后有无空格都可以
    • String...args
    • String ...args
    • String... args
    • String ... args
  • 这里的变量其实是一个数组,调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法体中以数组的形式访问可变参数。
  • 如果一个方法有可变参数,并且有多个参数,那么,可变参数肯定是最后一个
  • Arrays.asList()虽然可以把数组转成集合,但是集合的长度不能改变。
List<String> list = Arrays.asList("hello", "world", "java");
// UnsupportedOperationException
// list.add("javaee");
// UnsupportedOperationException
// list.remove(1);

枚举

枚举就是要让某个类型的变量的取值只能为若干个固定值中的一个,否则,编译器就会报错。枚举可以让编译器在编译时就可以控制源程序中填写的非法值,普通变量的方式在开发阶段无法实现这一目标。

注意

  • 所有枚举类都是Enum的子类
  • 枚举类的第一行上必须是枚举项,最后一个枚举项后的分号是可以省略的,但是如果枚举类有其他的东西,这个分号就不能省略。建议不要省略
  • 枚举类可以有构造器,但必须是private的,它默认的也是private的
  • 枚举类也可以有抽象方法,但是枚举项必须重写该方法
  • 枚举可以在switch语句中使用
public enum Direction3 {
    FRONT("前") {
        @Override
        public void show() {
            System.out.println("前");
        }
    },
    BEHIND("后") {
        @Override
        public void show() {
            System.out.println("后");
        }
    },
    LEFT("左") {
        @Override
        public void show() {
            System.out.println("左");
        }
    },
    RIGHT("右") {
        @Override
        public void show() {
            System.out.println("右");
        }
    };

    private String name;

    private Direction3(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public abstract void show();
}
Direction3.RIGHT.getClass().getName();// Direction3

枚举的常用方法

Direction d1 = Direction.FRONT;
Direction d2 = Direction.BEHIND;
Direction d3 = Direction.LEFT;
Direction d4 = Direction.RIGHT;

// int compareTo() 比较 根据编号 self.ordinal - other.ordinal
System.out.println(d1.compareTo(d1));

// String name() //获取枚举名称
System.out.println(d1.name());

// int ordinal() //获取编号
System.out.println(d1.ordinal());

// String toString() 默认返回枚举名称
System.out.println(d1.toString());

// <T> T valueOf(Class<T> type,String name) 通过name获取枚举对象
Direction d = Enum.valueOf(Direction.class, "FRONT");
System.out.println(d.getName());

// values() 遍历枚举对象
// 此方法虽然在JDK文档中查找不到,但每个枚举类都具有该方法,它遍历枚举类的所有枚举值非常方便
Direction[] dirs = Direction.values();
for (Direction d : dirs) {
    System.out.println(d);
    System.out.println(d.getName());
}

泛型

元数据

Scanner类处理用户录入

Lock

// 定义票
private int tickets = 100;

// 定义锁对象
private Lock lock = new ReentrantLock();// ReentrantLock是Lock的实现类

@Override
public void run() {
    while (true) {
        try {
            // 加锁
            lock.lock();
            if (tickets > 0) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()
                        + "正在出售第" + (tickets--) + "张票");
            }
        } finally {
            // 释放锁
            lock.unlock();
        }
    }
}

线程并发库

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

  • public static ExecutorService newCachedThreadPool() 创建一个具有缓存功能的线程池
  • public static ExecutorService newFixedThreadPool(int nThreads) 创建一个可重用的,具有固定线程数的线程池
  • public static ExecutorService newSingleThreadExecutor() 创建一个只有单线程的线程池,相当于上个方法的参数是1

1.线程互斥 工具类描述:Lock,RedWriteLock 2.线程通信 描述:Condition 3.线程池 ExecutorService 3.同步队列 ArrayBlockingQueue 4.同步集合 ConcurrentHashMap,CopyOnWriteArrayList 5.线程同步工具 Semaphore

注解

JDK默认提供的注解:

  • Deprecated
  • Override
  • SuppressWarnings

元注解(注解的注解)

  • @Retention 保留
    • RetetionPolicy.SOURCE java源文件
    • RetetionPolicy.CLASS class文件 (默认)
    • RetetionPolicy.RUNTIME 内存中的字节码
  • @Target
    • ElementType.TYPE 类型 包括Class、Interface、Enum等的父,对类、接口和枚举等对象生效
    • ElementType.FIELD 成员变量
    • ElementType.METHOD 方法
    • ElementType.PARAMETER 参数
    • ElementType.CONSTRUCTOR 构造方法
    • ElementType.LOCAL_VARIABLE 局部变量
    • ElementType.ANNOTATION_TYPE 注解
    • ElementType.PACKAGE 包

注解属性

枚举的属性类型包括:基本数据类型,String,Class,枚举,其他注解,以及这些类型的数组。

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface MyAnnotation {
    // 注解属性
    String color() default "blue"; //String类型并指定默认值
    String value();//特殊字段value
    int[] arrayAttr() default {3,4,4};//数组类型字段
    TrafficLamp lamp() default TrafficLamp.RED;//枚举类型
    MetaAnnotation annotationAttr() default @MetaAnnotation("test");//注解类型
    Class classValue() default String.class;//class类型
}
public @interface MetaAnnotation {
    String value();
}
public enum TrafficLamp{
    RED(30){
        public  TrafficLamp nextLamp(){
            return GREEN;
        }
    },
    GREEN(45){
        public  TrafficLamp nextLamp(){
            return YELLOW;
        }
    },
    YELLOW(5){
        public  TrafficLamp nextLamp(){
            return RED;
        }
    };
    public abstract TrafficLamp nextLamp();
    private int time;
    private TrafficLamp(int time){this.time = time;}
}
@MyAnnotation(annotationAttr=@MetaAnnotation("test"),color="red",value="abc",arrayAttr=1)//数组类型只有一个值可以省略花括号
public class AnnotationTest {
    @MyAnnotation("xyz")//只有value字段可以省略字段名和等号
    public static void main(String[] args) throws Exception{
        if(AnnotationTest.class.isAnnotationPresent(MyAnnotation.class)){
            MyAnnotation annotation = (MyAnnotation)AnnotationTest.class.getAnnotation(MyAnnotation.class);
            System.out.println(annotation.color());// red
            System.out.println(annotation.value());// abc
            System.out.println(annotation.arrayAttr()[0]);// 1
            System.out.println(annotation.lamp().nextLamp().name());// GREEN
            System.out.println(annotation.annotationAttr().value());// test
            System.out.println(annotation.classValue().getName());// java.lang.String
        }
    }
}

@Override、@SuppressWarnings和@Deprecated这三个注解的属性值分别是什么?

@Override、@SuppressWarnings是SOURCE
@Deprecated是RUNTIME,因为编译器拿到class文件加载到内存后才能检查是否已经过时,所以是RUNTIME

JDK 1.6

https://www.ibm.com/developerworks/cn/java/j-lo-jse61/index.html

Instrumentation新功能(Java Agent)

instrumentation包被赋予了更强大的功能:

  • 启动后的instrument
  • 本地代码(native code)instrument
  • 以及动态改变classpath 等等

HTTP增强

  • NTLM 认证提供了一种 Window 平台下较为安全的认证机制;
  • JDK 当中提供了一个轻量级的 HTTP 服务器;
  • 提供了较为完善的 HTTP Cookie 管理功能;
  • 更为实用的 NetworkInterface;DNS 域名的国际化支持等等。

JMX增强

https://www.ibm.com/developerworks/cn/java/j-lo-jse63/index.html

编译器API

  • 老版本的编程接口并不是标准 API 的一部分,而是作为 Sun 的专有实现提供的,而新版则带来了标准化的优点
  • 可以编译抽象文件,理论上是任何形式的对象 —— 只要该对象实现了特定的接口。
  • 第三个新特性是可以收集编译时的诊断信息
import java.util.Date;
public class Target {
    public void doSomething(){
        Date date = new Date(10, 3, 3); 
        // 这个构造函数被标记为deprecated, 编译时会
        // 向错误输出输出信息。
        System.out.println("Doing...");
    }
}

import javax.tools.*;
import java.io.FileOutputStream;
public class Compiler {
    public static void main(String[] args) throws Exception{
        String fullQuanlifiedFileName = "compile" + java.io.File.separator +
        "Target.java"; 
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        FileOutputStream err = new FileOutputStream("err.txt");
        int compilationResult = compiler.run(null, null, err, fullQuanlifiedFileName);
        if(compilationResult == 0){
            System.out.println("Done");
        } else {
            System.out.println("Fail");
        }
    }
}
package math;
import javax.tools.*;
import java.io.FileOutputStream;
import java.util.Arrays;
public class AdvancedCompiler {
    public static void main(String[] args) throws Exception{
        // Steps used to compile Calculator
        // Steps used to compile StringObject
        // construct CalculatorTest in memory
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager fileManager  =
        compiler.getStandardFileManager(null, null, null);
        JavaFileObject file = constructTestor();
        Iterable<? extends JavaFileObject> files = Arrays.asList(file);
        DiagnosticCollector<JavaFileObject> collector = new DiagnosticCollector<JavaFileObject>(); 
        JavaCompiler.CompilationTask task = compiler.getTask (
            null, fileManager, collector, null, null, files);

        Boolean result = task.call();
        if( result == true ) {
            System.out.println("Succeeded");
        }
    }
    private static SimpleJavaFileObject constructTestor() {
        StringBuilder contents = new StringBuilder(
            "package math;" +
            "class CalculatorTest {\n" +
            "  public void testMultiply() {\n" +
            "    Calculator c = new Calculator();\n" +
            "    System.out.println(c.multiply(2, 4));\n" +
            "  }\n" +
            "  public static void main(String[] args) {\n" +
            "    CalculatorTest ct = new CalculatorTest();\n" +
            "    ct.testMultiply();\n" +
            "  }\n" +
            "}\n");
        StringObject so = null;
        try {
            so = new StringObject("math.CalculatorTest", contents.toString());
        } catch(Exception exception) {
            exception.printStackTrace();
        }
        return so;
    }
}

Derby和JDBC 4.0

JDBC 4.0

  • 自动加载驱动
    • 所有 JDBC 4.0 的驱动 jar 文件必须包含一个 java.sql.Driver,它位于 jar 文件的 META-INF/services 目录下
  • RowId类型
  • SQLXML
  • SQLExcpetion 的增强

Derby

try { // load the driver
    Class.forName("org.apache.derby.jdbc.EmbeddedDriver").newInstance();
    System.out.println("Load the embedded driver");
    Connection conn = null;
    Properties props = new Properties();
    props.put("user", "user1");
    props.put("password", "user1");
    //create and connect the database named helloDB
    conn = DriverManager.getConnection("jdbc:derby:helloDB;create=true", props);
    System.out.println("create and connect to helloDB");
    conn.setAutoCommit(false);

    // create a table and insert two records
    Statement s = conn.createStatement();
    s.execute("CREATE TABLE hellotable(name VARCHAR(40), score INT)");
    System.out.println("Created table hellotable");
    s.execute("INSERT INTO hellotable VALUES('Ruth Cao', 86)");
    s.execute("INSERT INTO hellotable VALUES ('Flora Shi', 92)");
    // list the two records
    ResultSet rs = s.executeQuery(
            "SELECT name, score FROM hellotable ORDER BY score");
    System.out.println("name\t\tscore");
    while (rs.next()) {
        StringBuilder builder = new StringBuilder(rs.getString(1));
        builder.append("\t");
        builder.append(rs.getInt(2));
        System.out.println(builder.toString());
    }
    // delete the table
    s.execute("DROP TABLE hellotable");
    System.out.println("Dropped table hellotable");

    rs.close();
    s.close();
    System.out.println("Closed result set and statement");
    conn.commit();
    conn.close();
    System.out.println("Committed transaction and closed connection");

    try { // perform a clean shutdown all
        DriverManager.getConnection("jdbc:derby:;shutdown=true");
        // shutdown current connection
        //DriverManager.getConnection("jdbc:derby:helloDB;shutdown=true ");
    } catch (SQLException se) {
        System.out.println("Database shut down normally");
    }
} catch (Throwable e) {
    // handle the exception
    e.printStackTrace();
}
System.out.println("SimpleApp finished");

对脚本语言的支持

  • 获取脚本程序输入,通过脚本引擎运行脚本并返回运行结果,这是最核心的接口。
  • 发现脚本引擎,查询脚本引擎信息。
  • 通过脚本引擎的运行上下文在脚本和 Java 平台间交换数据。
  • 通过 Java 应用程序调用脚本函数。
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("JavaScript");
ScriptObjectMirror eval = (ScriptObjectMirror) engine.eval(" 'Hello World'.split(' ')");
Set<Map.Entry<String, Object>> entries = eval.entrySet();
for (Map.Entry<String, Object> entry : entries) {
    System.out.println(entry.getKey());
    System.out.println(entry.getValue());
}

XML API 与 Web 服务

  • 对 XML 处理技术进行了扩展。包括新加入的 StAX 和 JAXB。
  • 和较早的 JDK 5 相比,新版本的 JDK Web 服务功能更改了名称 —— 从 JAX-RPC 变成 JAX-WS。JDK 5 只支持基于 remote-procedure-call 的 Web 服务,JDK 6 在此基础上,还支持基于 SOAP message 的 Web 服务实现

JDK 1.7

https://www.ibm.com/developerworks/cn/java/j-lo-jdk7-1/index.html

switch可以使用String

switch语句的表达式可以是byte吗?可以是long吗?可以是String吗

可以,不可以,JDK7以后可以

异常的多个catch合并

  • 处理方式是一致的。(实际开发中,好多时候可能就是针对同类型的问题,给出同一个处理)
  • 多个异常间必须是平级关系。
// JDK7的处理方案
try {
    System.out.println(a / b);
    System.out.println(arr[3]);
} catch (ArithmeticException | ArrayIndexOutOfBoundsException e) {
    System.out.println("出问题了");
}

try-with-resources 语句

好处

  • 资源自动释放,不需要close()了
  • 把需要关闭资源的部分都定义在这里就ok了
  • 主要是流体系的对象是这个接口的子类(看JDK7的API)
// try-with-resources 语句
// try(必须是java.lang.AutoCloseable的子类对象){…}

try {
    FileReader fr = new FileReader("a.txt");
    FileWriter fw = new FileWriter("b.txt");
    int ch = 0;
    while ((ch = fr.read()) != -1) {
        fw.write(ch);
    }
    fw.close();
    fr.close();
} catch (IOException e) {
    e.printStackTrace();
}

// 改进版的代码
try (FileReader fr = new FileReader("a.txt");
        FileWriter fw = new FileWriter("b.txt");) {
    int ch = 0;
    while ((ch = fr.read()) != -1) {
        fw.write(ch);
    }
} catch (IOException e) {
    e.printStackTrace();
}//自动释放资源 不用手动关闭

NIO改进

NIO2 主要包括了 3 个方面的改进:

  • 新的文件系统 API 支持大量文件属性的访问、文件系统监控服务、平台相关的 API,如 DosFileAttributes 和 PosixFileAttributes 等,以及一个可插拔文件系统的 SPI。
  • Socket 和文件的异步 IO。
  • Socket channel 的功能完善,支持 binding、多播等。

  • Path:与平台无关的路径。
  • Paths:包含了返回Path的静态方法。
  • Files:操作文件的工具类。提供了大量的方法

二进制的表现形式(二进制字面量)

JDK7开始,终于可以用二进制来表示整数(byte,short,int和long)。使用二进制字面量的好处是,可以使代码更容易被理解。语法非常简单,只要在二进制数值前面加 0b或者0B

// 二进制字面量
int x = 0b100101;

用_分隔数据

为了增强对数值的阅读性,如我们经常把数据用逗号分隔一样。JDK7提供了_对数据分隔。

注意

  • 不能出现在进制标识和数值之间
  • 不能出现在数值开头和结尾
  • 不能出现在小数点旁边
// 数字字面量可以出现下划线
int y = 1_1123_1000;
// 不能出现在进制标识和数值之间
int z = 0x111_222;
// 不能出现在数值开头和结尾
int a = 0x11_22;
// 不能出现在小数点旁边
double d = 12.3_4;

泛型推断(菱形泛型)

泛型简化

ArrayList<String> array = new ArrayList<>();

JSR292:支持动态类型语言(InvokeDynamic)

动态类型语言在 JVM 上的执行速度得到了大大提升

G1 垃圾回收器

G1 在堆上分配一系列相同大小的连续区域,然后在回收时先扫描所有的区域,按照每块区域内存活对象的大小进行排序,优先处理存活对象小的区域,即垃圾对象最多的区域,这也是 Garbage First 这个名称的由来。G1 把要收集的区域内的存活对象合并并且复制到其他区域,从而避免了 CMS 遇到的内存碎片问题。此外,G1 采用了一个可预测暂停时间模型来达到软实时的要求。

JDK 1.8

https://www.ibm.com/developerworks/cn/java/j-lo-jdk8newfeature/index.html

函数式接口(Functional Interfaces)

Functional Interface(函数式接口,以下简称FI)FI的定义:任何接口,如果只包含 唯一一个抽象方法,那么它就是一个FI。为了让编译器帮助我们确保一个接口满足FI的要求(也就是说有且仅有一个抽象方法),Java8提供了@FunctionalInterface注解。

函数式接口的重要属性是:我们能够使用 Lambda 实例化它们,Lambda 表达式让你能够将函数作为方法参数,或者将代码作为数据对待。

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

Lamba

好处

  • 在 Java 8 之前,匿名内部类,监听器和事件处理器的使用都显得很冗长,代码可读性很差,Lambda 表达式的应用则使代码变得更加紧凑,可读性增强;
  • Lambda 表达式使并行操作大集合变得很方便,可以充分发挥多核 CPU 的优势,更易于为多核处理器编写代码;

组成

  1. 第一部分为一个括号内用逗号分隔的形式参数,参数是函数式接口里面方法的参数
  2. 第二部分为一个箭头符号:->
  3. 第三部分为方法体,可以是表达式和代码块
// 方法体为表达式,该表达式的值作为返回值返回。
(parameters) -> expression
// 方法体为代码块,必须用 {} 来包裹起来,且需要一个 return 返回值
// 但若函数式接口里面方法返回值是 void,则无需返回值。
(parameters) -> { statements; }

为了减少过量的函数式接口,Java 8 在 java.util.function 中增加了不少新的函数式通用接口

  • Function<T, R>:将 T 作为输入,返回 R 作为输出,他还包含了和其他函数组合的默认方法。
  • Predicate<T> :将 T 作为输入,返回一个布尔值作为输出,该接口包含多种默认方法来将 Predicate 组合成其他复杂的逻辑(与、或、非)。
  • Consumer<T> :将 T 作为输入,不返回任何内容,表示在单个参数上的操作。
//run 没有参数传入,所以用 (), 后面用 {} 包起方法体
Thread thread = new Thread(
        () -> {
            System.out.println("Hello from a thread in run");
        }
);
// 使用内部类
Function<Integer, String> f = new Function<Integer, String>() {
    @Override
    public String apply(Integer integer) {
        return String.valueOf(integer);
    }
};
// 使用 Lambda 表达式
Function<Integer, String> f3 = (integer) -> String.valueOf(integer);
// 省去括号
Function<Integer, String> f2 = integer -> String.valueOf(integer);
// 使用方法引用的方式
Function<Integer, String> f1 = String::valueOf;
// lambda排序
list.sort((String o, String o1) -> {
    return Double.valueOf(o).compareTo(Double.valueOf(o1));
});
// 简化
list.sort(Comparator.comparing(Double::valueOf));
class People {
    private List<Person> persons = new ArrayList<>();
    public List<Person> getMaleList(Predicate<Person> predicate) {
        List<Person> res = new ArrayList<>();
        persons.forEach(// Iterable新增默认方法,接收一个Consumer对象
                person -> {
                    if (predicate.test(person)) {//调用 Predicate 的抽象方法 test
                        res.add(person);
                    }
                });
        return res;
    }
}

接口的增强

Java 8 对接口做了进一步的增强。在接口中可以添加使用 default 关键字修饰的非抽象方法(扩展方法)。还可以在接口中定义静态方法。

interface Inter {
    //抽象方法
    public abstract void show();
    //default方法
    public default void defaultPrint() {
        System.out.println("defaultPrint 我爱林青霞");
    }
    //static方法
    public static void staticPrint() {
        System.out.println("staticPrint 我爱林青霞");
    }
}
//实现类
class InterImpl implements Inter{
    public void show() {
        System.out.println("重写接口中的方法");
    }
}
//测试类
public class Demo01 {
    public static void main(String[] args) {
        //Inter.defaultPrint();  //非静态方法不能直接使用 
        Inter.staticPrint();
        Inter i = new InterImpl();
        i.defaultPrint();
        i.show();
    }
}

集合之流式操作

Java 8 引入了流式操作(Stream),可以实现对集合(Collection)的并行处理和函数式操作

根据操作返回的结果不同,流式操作分为中间操作最终操作
最终操作返回一特定类型的结果,而中间操作返回流本身,这样就可以将多个操作依次串联起来。
根据流的并发性,流又可以分为串行并行两种。
流式操作实现了集合的过滤、排序、映射等功能。

List<String> list = new ArrayList<String>();
for (int i = 0; i < 1000000; i++) {
    double d = Math.random() * 1000;
    list.add(d + "");
}
// array结果为排序后的结果,原list不变
list = list.stream().sequential().sorted().collect(Collectors.toList());
list = list.stream().parallel().sorted().collect(Collectors.toList());
// 串行输出为 1200ms,并行输出为 800ms
// 而传统排序要10S左右

中间操作

该操作会保持 stream 处于中间状态,允许做进一步的操作。它返回的还是的 Stream,允许更多的链式操作。常见的中间操作有:

  • filter():对元素进行过滤
  • sorted():对元素排序
  • map():元素的映射
  • distinct():去除重复元素
  • subStream():获取子 Stream 等

终止操作

该操作必须是流的最后一个操作,一旦被调用,Stream 就到了一个终止状态,而且不能再使用了。常见的终止操作有:

  • forEach():对每个元素做处理
  • toArray():把元素导出到数组
  • findFirst():返回第一个匹配的元素
  • anyMatch():是否有匹配的元素等
list.stream()
.filter((s) -> s.startsWith("s"))
.forEach(System.out::println);

注解的更新

主要有两点改进:类型注解重复注解

  • 现在几乎可以为任何东西添加注解:局部变量、类与接口,就连方法的异常也能添加注解
  • Java 8 引入了重复注解机制,这样相同的注解可以在同一地方声明多次。重复注解机制本身必须用 @Repeatable 注解

日期和时间

Java 8 吸收了 Joda-Time 的精华,以一个新的开始为 Java 创建优秀的 API

新的 java.time 中包含:

  • 时钟(Clock)
  • 本地日期(LocalDate)
  • 本地时间(LocalTime)
  • 本地日期时间(LocalDateTime)
  • 时区(ZonedDateTime)
  • 持续时间(Duration)
  • 历史悠久的 Date 类新增了 toInstant() 方法,用于把 Date 转换成新的表示形式。
//LocalDate
LocalDate localDate = LocalDate.now(); //获取本地日期
localDate = LocalDate.ofYearDay(2014, 200); // 获得 2014 年的第 200 天
System.out.println(localDate.toString());//输出:2014-07-19
localDate = LocalDate.of(2014, Month.SEPTEMBER, 10); //2014 年 9 月 10 日
System.out.println(localDate.toString());//输出:2014-09-10
//LocalTime
LocalTime localTime = LocalTime.now(); //获取当前时间
System.out.println(localTime.toString());//输出当前时间
localTime = LocalTime.of(10, 20, 50);//获得 10:20:50 的时间点
System.out.println(localTime.toString());//输出: 10:20:50
//Clock 时钟
Clock clock = Clock.systemDefaultZone();//获取系统默认时区 (当前瞬时时间 )
long millis = clock.millis();//获取毫秒数
System.out.println(millis);

ZonedDateTime zonedDateTime = Instant.ofEpochMilli(millis).atZone(ZoneId.systemDefault());
System.out.println(zonedDateTime.toLocalDate());
System.out.println(zonedDateTime.toLocalTime());
System.out.println(Arrays.toString(TimeZone.getAvailableIDs()));

// 2014-07-19
// 2014-09-10
// 17:50:49.322
// 10:20:50
// 1502963449323
// 2017-08-17
// 17:50:49.323
// [Africa/Abidjan, Africa/Accra, ....

Search

    Post Directory