欢迎访问悦橙教程(wld5.com),关注java教程。悦橙教程  java问答|  每日更新
页面导航 : > > 文章正文

java 7 的新特性,java新特性

来源: javaer 分享于  点击 46557 次 点评:86

java 7 的新特性,java新特性


java 7 的新特性

java 7 的新特性

二进制前缀0b或者0B

字面常量数字的下划线捕获多个异常Java 7之前的版本Java 7 的版本try-with-resources传统的资源关闭方式Java 7 的资源关闭方式switch 支持String类型泛型实例化类型自动推断Java 7 以前的版本Java 7 的版本Files工具类和Path接口Files的简介Path和File的对比DirectoryStreamWatchServiceFileChannel通道获取AsynchronousFileChannelNetworkChannel接口新增Fork/Join框架什么是Fork/Join框架Fork/Join框架的核心类ForkJoinPoolForkJoinTask简单的例子Java 7 之前——ExecutorServicejava 7的版本 ——Fork/Join

 

 

 


 

二进制前缀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());
}

【摘自】 http://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);
    }
}

【摘自】 https://www.cnblogs.com/itZhy/p/7636615.html

 

 

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

【摘自】 https://www.cnblogs.com/lchzls/p/6711222.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的对比

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

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

【部分摘自】https://blog.csdn.net/qq_35326718/article/details/65447561

 

 

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

【部分摘自】

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框架的核心类

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

【摘自】

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/

相关文章

    暂无相关文章
相关栏目:

用户点评