二进制前缀0b或者0B
Java 7 中,整数类型(byte, short, int以及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());}
【摘自】
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); }}
【摘自】
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; } }}
【摘自】
泛型实例化类型自动推断
Java 7 以前的版本
MapmyMap = new HashMap ();
Java 7 的版本
MapmyMap = new HashMap<>(); //注意后面的"<>"
在这条语句中,编译器会根据变量声明时的泛型类型自动推断出实例化HashMap时的泛型类型。再次提醒一定要注意new HashMap后面的<>,只有加上这个<>才表示是自动类型推断。
【摘自】
Files工具类和Path接口
java 7 引入了 FIles 类和 Path 接口。他们两封装了用户对文件的所有可能的操作,相比于之前的File类来说,使用起来方便很多。但是其实一些本质的操作还是很类似的。主要需要知道的是,Path表示路径可以使文件的路径也可以是目录的路径,Files中所有成员都是静态方法,通过路径实现了对文件的基本操作。
Files的简介
Files类是非常好用的io操作工具类,它提供了很多方法进行一些常用的io操作,例如文件复制,移动,删除,读取文件内容,写入文件内容等 。这里对Files不再赘述,读者可查阅相关的文档:
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
2. 读取文件属性相关
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:falseisHidden:falsecanRead:truecanWrite:truelastModified:1534155733866length:0
但是对于Java 7中可以批量读取文件属性,而且可以访问到文件更详细的属性。例如:
public static void main(String[] args) throws IOException { Path path = Paths.get("C:\\Users\\liutaigang\\Desktop\\java各个版本的新特性\\javacode\\test.txt"); Mapmap = Files.readAttributes(path, "*", LinkOption.NOFOLLOW_LINKS); for (String s : map.keySet()) { System.out.println(s + ":" + map.get(s)); }; }
打印结果:
lastAccessTime:2018-08-13T10:22:13.866759ZlastModifiedTime:2018-08-13T10:22:13.866759Zsize:0creationTime:2018-08-13T10:22:13.866759ZisSymbolicLink:falseisRegularFile:truefileKey:nullisOther:falseisDirectory:false
【部分摘自】
DirectoryStream
使用DirectoryStream,我们可以方便的使用for-each语句迭代出一个目录下的所有条目(包括文件和目录),也可以迭代出指定的文件。例如:
public static void main(String[] args) throws IOException { Path path = Paths.get(""); //get files of all try (DirectoryStreamstream = Files.newDirectoryStream(path)) { for (Path entry: stream) { System.out.println(entry); } } System.out.println("======================================================="); //get the file that you need try (DirectoryStream 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); } } }
【部分摘自】
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_DELETEtest --> ENTRY_CREATEtest --> ENTRY_DELETE
【摘自】
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()); } }
【详情请看】
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; Futureoperation = 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](https://my.oschina.net/u/1162528) public void run() { readThread.readFileContent(MainThread.this); } }).start(); } [@Override](https://my.oschina.net/u/1162528) 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..."); } } } }
【部分摘自】
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> 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()); } }
【部分摘自】
新增Fork/Join框架
什么是Fork/Join框架
java 7 加入了并行计算的框架Fork/Join,Fork/Join采用的是分治法。所谓分治法就是将一个大任务切分成N个小任务并行执行,并最终聚合结果。 在实际情况中,很多时候我们都需要面对经典的“分治”问题。要解决这类问题,主要任务通常被分解为多个任务块(分解阶段),其后每一小块任务被独立并行计算。一旦计算任务完成,每一块的结果会被合并或者解决(解决阶段) 。
请看图:
Fork/Join框架的核心类
1. ForkJoinPool
这个类实现了ExecutorService接口和工作窃取算法(Work-Stealing Algorithm)。它管理工作者线程,并提供任务的状态信息,以及任务的执行信息。
2. ForkJoinTask
这个类是一个在ForkJoinPool中执行的任务的基类。ForkJoinTask 提供了在一个任务里执行 fork() 和 join() 操作的机制和控制任务状态的方法。通常,为了实现Fork/Join任务,需要实现它的子类:RecursiveAction、RecursiveTask。
- RecursiveAction:用于任务没有返回结果的场景。
- RecursiveTask:用于任务有返回结果的场景。
它们的继承(实现)关系图:
简单的例子
在这个例子中,会使用ExecutorService的方法和Fork/Join的方法来共同实现一个任务——1~1000的累加和。
1. 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{ 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](https://my.oschina.net/u/1162528) public Integer call() throws Exception { int total = 0; for (int i = from; i <= to; i++) { total += numbers[i]; } return total; } } /** * 计算入口 * [@param](https://my.oschina.net/u/2303379) numbers 用于计算的数组 * [@return](https://my.oschina.net/u/556800) 最终的计算结果 */ public int sumUp(Integer[] numbers) { List > 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 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
2. java 7的版本 ——Fork/Join
public class ForkJoinCalculator { private ForkJoinPool pool; public ForkJoinCalculator() { pool = new ForkJoinPool();//会以Runtime.avaliableProcessors()方法的返回值作为并行线程数量参数 } private class SumTask extends RecursiveTask{ 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](https://my.oschina.net/u/1162528) 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](https://my.oschina.net/u/2303379) 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
【摘自】