java 7 的新特性

二进制前缀0b或者0B

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

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);
}

字面常量数字的下划线

用下划线链接整数提高其可读性,自身无含义,不可用在数字的起始和末尾。java

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());
}

【摘自】 http://www.importnew.com/7015.htmlapi

try-with-resources

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

传统的资源关闭方式

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

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);
    }
}

【摘自】 http://www.javashuo.com/article/p-gxawejwn-hv.html异步

switch 支持String类型

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

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

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;
        }
    }
}

【摘自】 http://www.javashuo.com/article/p-amiizzgi-go.html

泛型实例化类型自动推断

Java 7 之前的版本

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

Java 7 的版本

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

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

【摘自】 https://blog.csdn.net/u011240877/article/details/47702745

Files工具类和Path接口

java 7 引入了 FIles 类和 Path 接口。他们两封装了用户对文件的全部可能的操做,相比于以前的File类来讲,使用起来方便不少。可是其实一些本质的操做仍是很相似的。主要须要知道的是,Path表示路径可使文件的路径也能够是目录的路径,Files中全部成员都是静态方法,经过路径实现了对文件的基本操做。

Files的简介

Files类是很是好用的io操做工具类,它提供了不少方法进行一些经常使用的io操做,例如文件复制,移动,删除,读取文件内容,写入文件内容等 。这里对Files再也不赘述,读者可查阅相关的文档:https://docs.oracle.com/javase/7/docs/api/java/nio/file/Files.html

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: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

【部分摘自】http://www.javashuo.com/article/p-byxcyvku-c.html

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);
            }
        }
    }

【部分摘自】https://docs.oracle.com/javase/7/docs/api/java/nio/file/DirectoryStream.html

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

【摘自】http://www.cnblogs.com/hwaggLee/p/6552561.html

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());
		}
	}

【详情请看】https://docs.oracle.com/javase/8/docs/api/java/nio/channels/FileChannel.html

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](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...");
    			}
    		}
    	}
    }

【部分摘自】

https://www.jianshu.com/p/b38f8c596193

https://blog.csdn.net/wanglha/article/details/51383245

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());
		}
	}

【部分摘自】https://www.cnblogs.com/pony1223/p/8186229.html?utm_source=debugrun&utm_medium=referral

新增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<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](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<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);	
	}
}
2. 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](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<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);	
	}
}

【摘自】

https://blog.csdn.net/caicongyang/article/details/51180330

http://www.importnew.com/2279.html

https://blog.csdn.net/al_assad/article/details/60878486

http://blog.dyngr.com/blog/2016/09/15/java-forkjoinpool-internals/

相关文章
相关标签/搜索