20145306 《java程序设计》第八周学习总结
学习内容总结
第十四章
一、认识NIO
1.NIO叙述
第十章介绍了基于InputStream。OutputStream,reader,Writer,的输入输出。对于高级输入/输出处理,Java从JDK1.4开始提供了NIO(New IO),而Java SE7中又提供了NIO2,认识与善用这些高级输入/输出处理API,对于输入/输出的处理效率会有很大的帮助。InputStream、OutputStream的输入/输出,基本上是以字节为单位进行低层次处理,虽然你得直接面对字节数组,但实际上多半是对字节数组中整个区块进行处理。例如在10.1.1节中看到过的dump()方法,实际上是整块数据读入之后,又整快数据写出,然而你必须处理byte[],必须记录读取的字节数,必须指定写出byte[]的起点与字节数。
虽然java.io套件中也有一些装饰类,不过,若只要对字节或字符串中感兴趣的区块进行处理,这些类就不见得合适,必须自行撰写API或寻找相关的链接库来处理索引、标记等细节。相对于串流输入/输出使用InputStream、OutputStream来衔接数据源与目的地,NIO使用频道来衔接数据节点,在处理数据时,NIO可以让你设定缓冲区容量,在缓冲区中对感兴趣的数据区块进行标记,对于这些区块标记,提供了clear(),rewind(),flip(),compact()等高级操作。
2.Channel架构与操作
NIO中Channel相关接口与类,是位于java.nio.channels套件之中,Channel接口是AutoClosable的子接口,因此都可以使用JDK7之后的尝试关闭资源语法,Channel接口上新增了isOpen()方法,用来确认Channel是否开启。对于初学者来说,主要可以先认识如图所示的Channel继承架构。
ByteChannel没有定义任何方法,单纯继承了ReadableByteChannel与WritableByteChannel的行为,ByteChannel的子接口SeekableByteChannel可以读取与改变下一个要存取数据的位置。
1.3Buffer架构与操作
在NIO设计中,数据都是在java.nio.Buffer中处理,Buffer是个抽象类,定义了clear(),rewind(),flip(),compact()等对数据区块的高级操作,这类操作返回类型都是Buffer,实际上返回this。
Buffer类继承架构
二、NIO2文件系统
1.NIO2架构
NIO2文件系统API提供一组标准接口与类,应用程序开发者只要基于这些标准接口与类进行文件系统操作就好。应用程序开发者主要使用java.nio.file与java.nio.file.attribute,包中必须操作的抽象类或接口,由文件系统提供者操作。NIO2文件系统的中心是java.nio.file.spi.FileSystemProvider,本身为抽象类。是文件系统提供者操作的类。作用是产生java.nio.file与java.nio.file.attribute中各种抽象类或接口的操作对象。
2.操作路径
想要取得Path实例,可以使用Paths.get()方法,最基本的使用方式,就是使用字符串路径,可以使用相对路径与绝对路径。Path实例仅代表路径信息,该路径实际对应的文档或文件夹不一定存在。
操作文档与目录
如果想要删除Path代表的文档或目录,可以使用Files.delete()方法,如果不存在,会抛出NoSuchFileException,如果因目录不为空而无法删除文档,会抛出DirectoryNotEmptyException。使用Files.deleteIfExists()方法也可以删除文档,这个方法在文档不存在时调用,并不会抛出异常。Files.copy()还有两个重载版本,一个是接受InputStream作为来源,可直接读取数据,并将结果复制至指定的Path中;另一个Files.copy()版本是将来源Path复制至指定的OutputStream。若要进行文档或目录移动,可以使用Files.move()方法,使用方式与Files.copy()方法类似,可指定来源Path、目的地Path与CopyOption。
.过滤、搜索文档
如果想在列出目录内容时过滤想显示的文档,例如只想显示.class与.jar文档,可以在使用Files.newDirectoryStream()时,将第二个参数指定过滤条件为*.{class,jar}。Files.newDirectoryStream()的另一版本接受DirectoryStream.Filter接口操作对象,如果Glob语法无法满足条件过滤需求,可以自行操作DirectoryStream.Filter的accept()方法自定义过滤条件。
第十五章
一、日志
1.日志API简介
java.util.logging包提供了日志功能相关类与接口。不必额外配置日志组件,就可在标准Java平台使用是其好处,使用日志的起点是Logger类,Logger类的构造函数标示为protected,不是java.util.logging同包的类不能直接以new创建,要取得Logger实例,必须使用Logger的静态方法getLogger()。调用getLogger()时,必须指定Logger实例所属名称空间。名称空间以“.”作为层级区分。名称空间层级相同的Logger,其父Logger组态相同。通常在哪个类中取得的Logger,名称空间就会命名为哪个类全名。简单来说,Logger是记录信息的起点,要输出的信息,必须先通过Logger的Level与Filter过滤,再通过Handler的Level与Filter过滤,格式化信息的动作交给Formatter,输出信息的动作实际上是Handler负责。
指定日志层级
Logger与Handler默认都会先依据Level过滤信息,如果没有做任何修改,取得的Logger实例之父Logger组态,就是Logger.GLOBALLOGGERNAME名称空间Logger实例的组态,这个实例的组态设定为INFO,可以通过Logger实例的getParent()取得父Logger实例,可通过getLevel()取得设定的Level实例。Logger的信息处理会往父Logger传播,也就是说,在没有做任何组态设定的情况下,默认取得的Logger实例,层级必须大于或等于Logger.GLOBALLOGGERNAME名称空间Logger实例设定的Level.INFO,才有可能输出信息。
使用Handler与Formatter
MemoryHandler不会格式化日志信息,信息会暂存于内存缓冲区,直到超过缓冲区大小,才将信息输出至指定的目标Handler。StreamHandler可自行指定信息输出时使用的OutputStream实例,它与子类都会使用指定的Formatter格式化信息,ConsoleHandler创建时,会自动指定OutputStream为System.err,所以日志信息会显示在控制台上。FileHandler创建时会建立日志输出时使用的FileOutputStream,文档位置与名称可以使用模式(Pattern)字符串指定。
4.自定义Handler、Formatter、Filter
如果java.util.logging包中提供的Handler成果都不符合需求,可以继承Handler类,操作抽象方法publish(),flush(),close()来自定义Handler,建议操作时考虑信息过滤与格式化。
JDK8 API增强功能
1.StringJoiner、Arrays新增API
如果你有一组字符串,想要指定每个字符串间以逗号分隔进行连结,String新增了join()静态方法可以直接使用,不仅List,这个版本的join()实际上可以接受Iterable操作对象。在Arrays上新增了parallePrefix()、paralleSetAll()与paralleSort()方法。
2.Stream相关API
如果想对数组进行管道化操作,方法之一是使用Arrays的asList()方法返回List,而后调用stream()方法取得Stream实例。另一个方式是使用Arrays的stream()方法,它可以指定数组后返回Stream实例。