java 7 的新特性

231 阅读9分钟

java 7 的新特性

二进制前缀0b或者0B

 Java SE 7中, 整数类型(byteshortint以及long) 可以使用二进制数系来表示。要指定一个二进制字面量,可以给二进制数字添加前缀 0b 或者 0B

     public static void main(String[] args)
     {
         byte a = 0b11; 
         short b = 0b11;  
         int c = 0b11;  
         long d = 0b11;
         System.out.println(a); 
         System.out.println(b);
         System.out.println(c); 
         System.out.println(d);
     }

字面常量数字的下划线

用下划线连接整数提升其可读性,自身无含义,不可用在数字的起始末尾

     public static void main(String[] args)
     {
         long a = 2_147_483_648L;
         int b =0b0001_0010_0110;
         
         System.out.println(a);
         System.out.println(b); 
     }

捕获多个异常

单个catch中捕获多个异常类型(用|分割)并通过改进的类型检查重新抛出异常)。

Java 7之前的版本

 try{
     ......   
 }catch (IOException ex) {
      logger.error(ex);
      throw new MyException(ex.getMessage());
 }catch (SQLException ex) {
      logger.error(ex);
      throw new MyException(ex.getMessage());
 }catch (Exception ex) {
      logger.error(ex);
      throw new MyException(ex.getMessage());
 }

Java 7 的版本

 try{
     ......    
 }catch(IOException | SQLException | Exception ex){
      logger.error(ex);
      throw new MyException(ex.getMessage());
 }

【摘自】 www.importnew.com/7015.html

try-with-resources

不需要使用finally来保证打开的流被正确关闭。

传统的资源关闭方式

为了确保外部资源一定要被关闭,通常关闭代码被写入finally代码块中,当然我们还必须注意到关闭资源时可能抛出的异常,于是变有了下面的经典代码:

 public static void main(String[] args) {
     FileInputStream inputStream = null;
     try {
         inputStream = new FileInputStream(new File("E:\test.txt"));
         ...
     } catch (IOException e) {
         throw new RuntimeException(e.getMessage(), e);
     } finally {
         if (inputStream != null) {
             try {
                 inputStream.close();//关闭资源时可能抛出的异常
             } catch (IOException e) {
                 throw new RuntimeException(e.getMessage(), e);
             }
         }
     }
 }

Java 7 的资源关闭方式

将外部资源的句柄对象的创建放在try关键字后面的括号中,当这个try-catch代码块执行完毕后,Java会确保外部资源的close方法被调用。

 public static void main(String[] args) {
     try (FileInputStream inputStream = new FileInputStream(new File("E:\test.txt"))) {
         ...
     } catch (IOException e) {
         throw new RuntimeException(e.getMessage(), e);
     }
 }

【摘自】 www.cnblogs.com/itZhy/p/763…

switch 支持String类型

在Java 7 之前,switch 只能支持 byte、short、char、int 这几个基本数据类型和其对应的封装类型。switch后面的括号里面只能放int类型的值,但由于byte,short,char类型,它们会 自动 转换为int类型(精精度小的向大的转化),所以它们也支持 。

**注意: **对于精度比int大的类型,比如long、float,doulble,不会自动转换为int,如果想使用,就必须强转为int,如(int)float。

Java 7 后,整形、枚举类型、boolean和字符串都可以。

 public class TestString {
     static String string = "123";
     public static void main(String[] args) {
         switch (string) {
         case "123":
             System.out.println("123");
             break;
         case "abc":
             System.out.println("abc");
             break;
         default:
             System.out.println("defauls");
             break;
         }
     }
 }

【摘自】 www.cnblogs.com/lchzls/p/67…

泛型实例化类型自动推断

Java 7 以前的版本

 Map<String, String> myMap = new HashMap<String, String>();

Java 7 的版本

 Map<String, String> myMap = new HashMap<>();    //注意后面的"<>"

在这条语句中,编译器会根据变量声明时的泛型类型自动推断出实例化HashMap时的泛型类型。再次提醒一定要注意new HashMap后面的 <> ,只有加上这个 <> 才表示是自动类型推断。

【摘自】 blog.csdn.net/u011240877/…

Files工具类和Path接口

java 7 引入了 FIles 类和 Path 接口。他们两封装了用户对文件的所有可能的操作,相比于之前的File类来说,使用起来方便很多。但是其实一些本质的操作还是很类似的。主要需要知道的是,Path表示路径可以使文件的路径也可以是目录的路径,Files中所有成员都是静态方法,通过路径实现了对文件的基本操作。

Files的简介

Files类是非常好用的io操作工具类,它提供了很多方法进行一些常用的io操作,例如文件复制,移动,删除,读取文件内容,写入文件内容等 。这里对Files不再赘述,读者可查阅相关的文档:docs.oracle.com/javase/7/do…

Path和File的对比

  1. 在错误处理方面

java.io.File类里面很多方法失败时没有异常处理,或抛出异常,例如:

 public static void main(String[] args) {  
     File file = new File("H://afile"); //This path does not exsit in file system.
     if(!file.delete()){
         System.out.println("删除失败");
     }
 }

运行结果:

 删除失败

java.io.File.delete()方法返回一个布尔值指示成功或失败但是没有失败原因。而java.nio.file.Files.delete(Path)会抛出:NoSuchFileException,DirectoryNotEmptyException,IOException,SecurityException,这样当删除一个文件失败时可以根据异常来查找失败原因。例如:

 public static void main(String[] args) throws IOException {  
     Path path = Paths.get("H://afile"); //This path does not exsit in file system.  
     Files.delete(path); 
 }

 运行结果:

 Exception in thread "main" java.nio.file.NoSuchFileException: H:\afile
     at sun.nio.fs.WindowsException.translateToIOException(Unknown Source)
     at sun.nio.fs.WindowsException.rethrowAsIOException(Unknown Source)
     at sun.nio.fs.WindowsException.rethrowAsIOException(Unknown Source)
     at sun.nio.fs.WindowsFileSystemProvider.implDelete(Unknown Source)
     at sun.nio.fs.AbstractFileSystemProvider.delete(Unknown Source)
     at java.nio.file.Files.delete(Unknown Source)
     at bin.main(bin.java:10
  1. 读取文件属性相关

File类中读取文件属性都是一个方法返回一个属性值,而没有能够直接一次返回很多属性的方法,造成访问文件属性时效率的问题。例如:

 public static void main(String[] args) throws IOException {  
         File file = new File("C:\Users\liutaigang\Desktop\java各个版本的新特性\javacode\test.txt");  
         System.out.println("isDirectory:" + file.isDirectory());  
         System.out.println("isHidden:" + file.isHidden());  
         System.out.println("canRead:" + file.canRead());  
         System.out.println("canWrite:" + file.canWrite());  
         System.out.println("lastModified:" + file.lastModified());  
         System.out.println("length:" + file.length());  
   }

打印结果:

 isDirectory:false
 isHidden:false
 canRead:true
 canWrite:true
 lastModified:1534155733866
 length:0

但是对于Java 7中可以批量读取文件属性,而且可以访问到文件更详细的属性。例如:

     public static void main(String[] args) throws IOException {  
         Path path = Paths.get("C:\Users\liutaigang\Desktop\java各个版本的新特性\javacode\test.txt");   
         Map<String, Object> map = Files.readAttributes(path, "*", LinkOption.NOFOLLOW_LINKS);  
         for (String s : map.keySet()) {  
             System.out.println(s + ":" + map.get(s));  
         };
     }

打印结果:

 lastAccessTime:2018-08-13T10:22:13.866759Z
 lastModifiedTime:2018-08-13T10:22:13.866759Z
 size:0
 creationTime:2018-08-13T10:22:13.866759Z
 isSymbolicLink:false
 isRegularFile:true
 fileKey:null
 isOther:false
 isDirectory:false

【部分摘自】 blog.csdn.net/qq_35326718…

DirectoryStream

使用DirectoryStream,我们可以方便的使用for-each语句迭代出一个目录下的所有条目(包括文件和目录),也可以迭代出指定的文件。例如:

     public static void main(String[] args) throws IOException {
         Path path = Paths.get("");
         //get files of all
         try (DirectoryStream<Path> stream = Files.newDirectoryStream(path)) {
             for (Path entry: stream) {
                 System.out.println(entry);
             }
         }
         
         System.out.println("=======================================================");
         
         //get the file that you need
         try (DirectoryStream<Path> stream = Files.newDirectoryStream(path, "*.{c,h,class,java}")) {
             for (Path entry: stream) {
                 System.out.println(entry);
             }
         }
     }

而在Java 7 之前,要在某个目录下获得指定后缀的文件,就有点繁琐了,例如:

     public static void main(String[] args) throws IOException {
         File file = new File(".");
         File[] fs = file.listFiles();
         for (File f : fs) {         
             if(f.isFile() && ( f.getName().endsWith(".c") 
                     || f.getName().endsWith(".h")
                     || f.getName().endsWith(".class")
                     || f.getName().endsWith(".java") )
                     ){
                 System.out.println(f);
             }
         }
     }

【部分摘自】 docs.oracle.com/javase/7/do…

WatchService

Java 7 中新增WatchService可以监控文件的变动信息(监控到文件是修改,新增、删除等事件;)

其中注册事件需要的是:

 StandardWatchEventKinds.ENTRY_MODIFY,//更新
 StandardWatchEventKinds.ENTRY_DELETE,//删除
 StandardWatchEventKinds.ENTRY_CREATE,//创建

示例代码:

 ​
 public static void main(String[] args) 
             throws Exception{
 ​
         String filePath = ("E:");
 ​
         // 获取文件系统的WatchService对象
         WatchService watchService = FileSystems.getDefault().newWatchService();
         Paths.get(filePath).register(watchService 
                 , StandardWatchEventKinds.ENTRY_CREATE
                 , StandardWatchEventKinds.ENTRY_MODIFY
                 , StandardWatchEventKinds.ENTRY_DELETE);//注册事件
 ​
         while(true)
         {
             // 获取下一个文件改动事件
             WatchKey key = watchService.take();
             for (WatchEvent<?> event : key.pollEvents()) 
             {
                 System.out.println(event.context() +" --> " + event.kind());
             }
             // 重设WatchKey
             boolean valid = key.reset();
             // 如果重设失败,退出监听
             if (!valid)  break;
         }
     }

当你在 E: 盘下新建一个目录,并改名为 “test” 后,再删除时,会有打印如下信息:

 新建文件夹 --> ENTRY_CREATE
 新建文件夹 --> ENTRY_DELETE
 test --> ENTRY_CREATE
 test --> ENTRY_DELETE

【摘自】 www.cnblogs.com/hwaggLee/p/…

FileChannel通道获取

Java 7 的FileChannel类中新增了静态方法 open(),用于创建一个访问文件的通道。例如:

     public static void main(String[] args) {
         try {
             Path file = Paths.get("E:\test.txt");
 ​
             FileChannel channel = FileChannel.open(file, StandardOpenOption.READ);
 ​
             ByteBuffer buffer = ByteBuffer.allocate(1024);
             channel.read(buffer);
 ​
             for(byte b : buffer.array())
             {
                 System.out.print((char)b);
             }
         } catch (IOException e) {
             System.out.println(e.getMessage());
         }
     }

【详情请看】 docs.oracle.com/javase/8/do…

AsynchronousFileChannel

在 Java 7 中AsynchronousFileChannel被添加到Java NIO。AsynchronousFileChannel使读取数据,使异步地读写文件成为可能。

     public static void main(String[] args) throws IOException, InterruptedException {
 ​
         Path path = Paths.get("E:\test.txt");
 ​
         AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(path, StandardOpenOption.READ);
 ​
         ByteBuffer buffer = ByteBuffer.allocate(1024);
         long position = 0;
 ​
         Future<Integer> operation = fileChannel.read(buffer, position);//异步读取,不在主线程中
 ​
         while (true)
         {
             if(operation.isDone())//在主线程中判断是否读取完成
             {
                 buffer.flip();
                 byte[] data = new byte[buffer.limit()];
                 buffer.get(data);
                 System.out.println(new String(data));
                 buffer.clear();
                 break;
             }
             else
             {
                 System.out.println("loading...");
             }
         }
     }

如果使用传统的方法(java 7 之前) 实现上述的功能,会比较复杂。请看示例:

 /*
  * 回调接口的定义,由需要异步回调的类实现
  */
 public interface CallBack {
     // 当异步线程完成时,调用此方法
     public void Done();
 }
 public class MainThread implements CallBack {
     private ReadThread readThread;
     
     public Boolean isDone = false;//异步线程的完成标识,false--未完成,true--已完成
     
     public MainThread(ReadThread readThread) {
         this.readThread = readThread;
     }
  
     public void readFile(){
         new Thread(new Runnable() {
             @Override
             public void run() {
                 readThread.readFileContent(MainThread.this);
             }
         }).start();
     }
  
     @Override
     public void Done() {
         this.isDone = true;
     }  
 }
 public class ReadThread {
     private File file;
     private byte[] buf;
     
     public ReadThread(File file, byte[] buf)
     {
         this.file = file;
         this.buf = buf;
     }
     
     public void readFileContent(CallBack callBack) {
         InputStream input = null;
         try {
             input = new FileInputStream(file);
             input.read(buf);
         } catch (IOException e) {
             e.printStackTrace();
         } finally
         {
             try {
                 if(null != input) input.close();
             } catch (IOException e) {
                 e.printStackTrace();
             }
         }
         
         callBack.Done();//通知已完成
     }
 }
 public class Test {
     public static void main(String[] args) {
         File file = new File("E:\test.txt");
         byte[] buf = new byte[1024];
         
         ReadThread readThread = new ReadThread(file, buf);
         MainThread mainThread = new MainThread(readThread);
         mainThread.readFile();
         
         //等待异步线程完成
         while(true)
         {
             if(mainThread.isDone)
             {
                 for(byte b : buf)
                 {
                     System.out.print((char)b);
                 }
                 break;
             }
             else
             {
                 System.out.println("loading...");
             }
         }
     }
 }

【部分摘自】

www.jianshu.com/p/b38f8c596…

blog.csdn.net/wanglha/art…

NetworkChannel接口

NetworkChannel是 Java 7 中新增的NIO.2中的接口,ServerSocketChannel,SocketChannel和DatagramChannel 都实现了这个接口。NetworkChannel加入让我们对channel控制的更细腻,可以对本地网卡做详细的检索。

 public static void main(String[] args) throws IOException {
         SelectorProvider provider = SelectorProvider.provider();
         try {
             NetworkChannel socketChannel = provider.openSocketChannel();
             SocketAddress address = new InetSocketAddress(3080);
             socketChannel = socketChannel.bind(address);
 ​
             Set<SocketOption<?>> socketOptions = socketChannel.supportedOptions();
             System.out.println(socketOptions.toString());
 ​
             socketChannel.setOption(StandardSocketOptions.IP_TOS, 3);
             System.out.println(socketChannel.getOption(StandardSocketOptions.IP_TOS));
             Boolean keepAlive = socketChannel.getOption(StandardSocketOptions.SO_KEEPALIVE);
             System.out.println(keepAlive);
 ​
         } catch (IOException e) {
             System.out.println(e.getMessage());
         }
     }

【部分摘自】 www.cnblogs.com/pony1223/p/…

新增Fork/Join框架

什么是Fork/Join框架

java 7 加入了并行计算的框架Fork/Join,Fork/Join采用的是分治法。所谓分治法就是将一个大任务切分成N个小任务并行执行,并最终聚合结果。 在实际情况中,很多时候我们都需要面对经典的“分治”问题。要解决这类问题,主要任务通常被分解为多个任务块(分解阶段),其后每一小块任务被独立并行计算。一旦计算任务完成,每一块的结果会被合并或者解决(解决阶段) 。

请看图:

Fork/Join框架的核心类

ForkJoinPool

这个类实现了ExecutorService接口工作窃取算法(Work-Stealing Algorithm) 。它管理工作者线程,并提供任务的状态信息,以及任务的执行信息。

ForkJoinTask

这个类是一个在ForkJoinPool中执行的任务的基类。ForkJoinTask 提供了在一个任务里执行 fork() 和 join() 操作的机制和控制任务状态的方法。通常,为了实现Fork/Join任务,需要实现它的子类:RecursiveAction、RecursiveTask。

  • RecursiveAction:用于任务没有返回结果的场景。
  • RecursiveTask:用于任务有返回结果的场景。

它们的继承(实现)关系图:

简单的例子

在这个例子中,会使用ExecutorService的方法Fork/Join的方法来共同实现一个任务——1~1000的累加和

Java 7 之前——ExecutorService

 public class ExecutorServiceCalculator {
     private int parallism;
     private ExecutorService pool;
 
     public ExecutorServiceCalculator() {
         parallism = Runtime.getRuntime().availableProcessors(); // 获取CPU的核心数
         pool = Executors.newFixedThreadPool(parallism);
     }
 
     private class SumTask implements Callable<Integer> {
         private Integer[] numbers;
         private int from;
         private int to;
 
         public SumTask(Integer[] numbers, int from, int to) {
             this.numbers = numbers;
             this.from = from;
             this.to = to;
         }
 
         @Override
         public Integer call() throws Exception {
             int total = 0;
             for (int i = from; i <= to; i++) {
                 total += numbers[i];
             }
             return total;
         }
     }
 
     /**
      * 计算入口
      * @param numbers 用于计算的数组
      * @return 最终的计算结果
      */
     public int sumUp(Integer[] numbers) {
         List<Future<Integer>> results = new ArrayList<>();
 
         // 把任务分解为 n 份,交给 n 个线程处理
         int part = numbers.length / parallism;
         for (int i = 0; i < parallism; i++) {
             int from = i * part;
             int to = (i == parallism - 1) ? numbers.length - 1 : (i + 1) * part - 1;
             results.add(pool.submit(new SumTask(numbers, from, to)));
         }
 
         // 把每个线程的结果相加,得到最终结果
         int total = 0;
         for (Future<Integer> f : results) {
             try {
                 total += f.get();
             } catch (Exception ignore) {}
         }
         return total;
     }
     
     /**
      * 当所有线程任务完成时,关闭计算器(Calculator)
      */
     public void shutDown(){
         this.pool.shutdown();
     };
 }
 public class Test {
 
     static final int TOTAL = 1000;
     
     public static void main(String[] args) {
         
         ExecutorServiceCalculator esc = new ExecutorServiceCalculator();
         
         Integer[] numbers = new Integer[TOTAL];
         for(int i=0; i<TOTAL; i++){
             numbers[i] = Integer.valueOf(i+1);
         }
         
         int sum = 0;
         sum = esc.sumUp(numbers);
         esc.shutDown();
         System.out.println("ExecutorServiceCalculator's result :" + sum);   
     }
 }

java 7的版本 ——Fork/Join

 public class ForkJoinCalculator {
     private ForkJoinPool pool;
 ​
     public ForkJoinCalculator() {
         pool = new ForkJoinPool();//会以Runtime.avaliableProcessors()方法的返回值作为并行线程数量参数
     }
     
     private class SumTask extends RecursiveTask<Integer> {
         private Integer[] numbers;
         private int from;
         private int to;
         private int threshold;//最小任务的计算量(临界值)
 
         public SumTask(Integer[] numbers, int from, int to, int threshold) {
             this.numbers = numbers;
             this.from = from;
             this.to = to;
             this.threshold = threshold;
         }
 
         @Override
         protected Integer compute() {
             // 当需要计算的数字小于threshold时,直接计算结果
             if (to - from < threshold) {
                 int total = 0;
                 for (int i = from; i <= to; i++) {
                     total += numbers[i];
                 }
                 return total;
             // 否则,把任务一分为二,递归计算
             } else {
                 int middle = (from + to) / 2;
                 SumTask taskLeft = new SumTask(numbers, from, middle, threshold);
                 SumTask taskRight = new SumTask(numbers, middle+1, to, threshold);
                 taskLeft.fork();
                 taskRight.fork();
                 return taskLeft.join() + taskRight.join();
             }
         }
     }
 
 
     /**
      * 计算入口
      * @param numbers 用于计算的数组
      * @param threshold 最小任务的计算量(临界值)
      * @return 最终的计算结果
      * @throws InterruptedException
      * @throws ExecutionException
      */
     public int sumUp(Integer[] numbers, int threshold) 
             throws InterruptedException, ExecutionException {
         
         return pool.submit(new SumTask(numbers, 0, numbers.length-1, threshold)).get();
     }
     
     /**
      * 当所有线程任务完成时,关闭计算器(Calculator)
      */
     public void shutDown(){
         this.pool.shutdown();
     }
 }
 public class Test {
 
     static final int TOTAL = 1000;
     
     public static void main(String[] args) throws InterruptedException, ExecutionException {
         
         ForkJoinCalculator fjc = new ForkJoinCalculator();
         
         Integer[] numbers = new Integer[TOTAL];
         for(int i=0; i<TOTAL; i++){
             numbers[i] = Integer.valueOf(i+1);
         }
         
         int sum = 0;
         sum = fjc.sumUp(numbers, 50);
         fjc.shutDown();
         System.out.println("ForkJoinCalculator's result :" + sum);  
     }
 }

【摘自】

blog.csdn.net/caicongyang…

www.importnew.com/2279.html

blog.csdn.net/al_assad/ar…

blog.dyngr.com/blog/2016/0…