教材学习内容总结
学习目标
了解NIO
会使用Channel、Buffer与NIO2
会使用日志API、国际化
会使用正则表达式
了解JDK8增强功能
第14章 NIO与NIO2
14.1 认识NIO
(1)NIO概述
NIO使用频道(Channel)来衔接数据节点,在处理数据时,NIO可以设定缓冲区(Buffer)容量,在缓冲区中对感兴趣的数据区块进行标记,像是标记读取位置、数据有效位置,对于这些区块标记,提供了clear()、rewind()、flip()、compact()等高级操作。下面用NIO的方法来实现10.1.1中的dump()方法,代码如下:
public static void dump(ReadableByteChannel src,WritableByteChannel dest)throws IOException{ByteBuffer buffer = ByteBuffer.allocate(1024);try(ReadableByteChannel srcCH = src;WritableByteChannel destCH = dest){ while(srcCH.read(buffer)!=-1){ buffer.flip(); destCH.write(buffer); buffer.clear(); }}}
(2)Channel架构与操作
Channel接口是AutoClosable的子接口,主要是增加了isOpen()方法来确认Channel是否开启,下图为Channel的继承架构:ReadableByteChannel定义了read()方法负责将ReadableByteChannel中的数据读取至ByteBuffer;
WritableByteChannel定义了write()方法,负责将ByteBuffer的数据写到WritableByteChannel中; ScatteringByteChannel定义了read()方法,负责将ScatteringByteChannel分配到ByteBuffer数组中; GatheringByteChannel定义了write()方法,负责将ByteBuffer的数据写到GatheringByteChannel中。
要想取得Channel的操作对象,可以使用Channels类。
(3)Buffer架构与操作
Buffer是个抽象类,定义clear()、flip()、reset()、rewind()等对数据区域块的高级操作,操作的返回类型均为Buffer,所以在连续高级操作时,可形成管线操作风格。Buffer的类继承架构如下图所示:可根据不同的数据类型处理需求来选择不同的的Buffer子类,他们都是抽象类,不能直接实例化。Buffer的所有直接子类们都有个allocate()静态方法,可以让你指定Buffer容量(Capacity)。Buffer是个容器,填装的数据不会超过它的容量。
14.2 NIO2文件系统
NIO2文件系统API提供一组标准接口与类,应用程序开发者只要基于这些标准接口与类进行文件系统操作,底层实际如何进行文件系统操作,是由文件系统提供者负责(由厂商操作)。
应用程式开发者可以通过java.nio.file套件中FileSystems、Paths、Files等类提供的静态方法,取得相关操作对象或进行各种文件系统操作,这些静态方法内部会运用FileSystemProvider来取得所需的操作对象,完成应有的操作。
第15章 通用API
15.1 日志
(1)日志API简介
java.util.logging包提供了日志功能相关类与接口,Logger类的构造函数标示为protected,不是java.util.logging同包的类不能直接以new创建,要取得Logger实例,必修使用Logger的静态方法getLogger()。取得Logger实例后,可用log()方法输出信息,输出时可用Level的静态成员制定信息层级(Level)。具体的代码实例如下:
public class LoggerDemo { public static void main(String[] args) { Logger logger = Logger.getLogger(LoggerDemo.class.getName()); logger.log(Level.WARNING, "WARNING信息"); logger.log(Level.INFO, "INFO信息"); logger.log(Level.CONFIG, "CONFIG信息"); logger.log(Level.FINE, "FINE信息"); }}
运行结果如下:
(2)指定日志层级
Logger与Handler预设都会先依Level过滤信息,如果没有做任何修改,取得的Logger实例之父Logger组态,就是Logger.GLOBAL_LOGGER_NAME名称空间Logger实例的组态,这个实例的Level设定为INFO,可通过Logger实例的getParent()取得父Logger实例,可通过getLevel()取得设定的Level实例。
Logger可通过setLevel()来设定Level实例,若log()时指定的Lever实例内含的int值小于Logger设定的Lever实例内含的int值,Lever就不会记录信息。
在经过Logger过滤之后,还得再经过Handler的过滤,一个Logger可以拥有多个Handler,可通过Logger的addHandler()新增Handler实例。实际上进行信息输出时,目前Logger的Handler处理完,还会传播给父Logger的所有Handler处理,可通过getHandlers()方法取得目前已有的Handler实例数组。例如:
public class LoggerDemo2 { public static void main(String[] args) { Logger logger = Logger.getLogger(LoggerDemo2.class.getName()); logger.setLevel(Level.FINE); for(Handler handler : logger.getParent().getHandlers()){ handler.setLevel(Level.FINE); } logger.log(Level.WARNING, "WARNING信息"); logger.log(Level.INFO, "INFO信息"); logger.log(Level.CONFIG, "CONFIG信息"); logger.log(Level.FINE, "FINE信息"); }}
运行结果如下:
这样FINE级及以上的log均能打印出来。
(3)使用Handler与Formatter
Handler负责日志输出。Logger可以使用addHandler()新增Handler实例,使用removeHandler()移除Handler。
Logger与Handler默认只会根据层级过滤信息。Logger与Handler都有setFilter()方法,可以指定Filter操作对象,当然也可以添加额外的过滤条件来操作Filter接口。
15.2 国际化基础
在不修改应用程序情况下,根据不同用户直接采用不同语言、日期格式等,这样的设计考虑称为国际化,简称i18n。
(1)使用ResourceBundle
对于以后可能变动的文字信息,可考虑将信息移至程序外,方法是使用ResourceBundle来完成信息绑定。
ResourceBundle的静态getBundle()方法会取得一个ResourceBundle的实例,所给定的自变量名称是信息文档的主文件名,getBundle()会自动找到对应的.properties文档,取得ResourceBundle实例后,可以使用getString()指定键来取得。
(2)使用Locale
国际化的三个标准是地区(Locale)信息、资源包(Resource bundle)与基础名称(Base name)。
地区信息的对应类是Locale,在建立Locale实例时,可指定语言编码与地区编码,例如,建立代表台湾繁体中文的Locale,例如:
Locale locale = new Locale("zh","TW");
资源包中包括了特定地区的相关信息。
15.3 规则表达式
(1)规则表示式简介
规则表达式基本上包括两种字符:字面意义字符和元字符。字面意义字符是指按照字面意义比较的字符;元字符时不按照字面比较,在不同情境有不同意义的字符。
例如使用String的split()方法返回切割后各字符串组成的String数组。
- 字面意义字符
字母和数字在规则表示式中都是按照字面意义比较的,有些字符之前加上\之后会被当做元字符。
元字符在规则表示式中有特殊意义,比较标点时可以在每个符号前加上。- 字符类
规则表示式中,多个字符可以分归在一起,成为一个字符类,会比较文字中是否有任一个字符符合字符类中某个字符。
归类字符的方式之一是将字符放于[]中。- 贪婪、逐步、独吐量词
{n}是贪婪量词表示法的一种,表示前面的量词出现n次,会尽可能找出长度最长的符合文字。
在贪婪量词表示法后加上?,将会成为逐步量词,会尽可能找出长度最短的符合文字。 在贪婪量词表示法后加上+,将会成为独吐量词,没有任何文字符合。- 边界比较
边界比较用来表示文字必须符合指定的边界条件,也就是定位点,因此这类表示式也常称为锚点。
- 分组与参考
可以使用()来将规则表示式分组,除了作为子规则表示式之外,还可以搭配量词使用。
分组回头参考时,是在\后加上分组计数,表示参考第几个分组的比对结果 。(2)Pattern与Matcher
在程序中使用表示式,必须先针对规则表示式做剖析、验证等动作,确定规则表示式语法无误,对字符串进行比较。
java.util.regex.Pattern实例是规则表示式在JVM中的代表对象,Pattern的构造函数被标示为private,必须通过Pattern的静态方法compile()来取得。
15.4 JDK8 API增强功能
(1)StringJoiner、Arrays新增API
String新增join()静态方法可以指定每个字符串间以逗号分隔进行连接。
Arrays上新增parallelPrefix()、parallelSetAll()与parallelSort()方法.
(2)Stream相关API
若想对数组进行管线化操作,方法一是使用Arrays的asList()方法返回List,而后调用stream()方法取得Stream实例;另一个方法是使用Arrays的stream()方法,可以指定数组后返回Stream实例。
CharSequence上新增了chars()和codePoints()方法,都是返回intStream。
Math在JDK8中也新增了不少数学运行相关API。
教材学习中的问题和解决过程
代码调试中的问题和解决过程
在本次代码运行中没有发现什么问题。
本周代码托管截图
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第二周 | 200/400 | 1/3 | 12/52 | |
预备作业 | 0/400 | 1/4 | 15/67 | |
第三周 | 500/900 | 1/5 | 10/77 | |
第四周 | 500/1500 | 1/6 | 15/92 | |
第五周 | 500/2000 | 1/7 | 20/112 | |
第六周 | 500/2500 | 2/9 | 20/132 | |
第七周 | 500/3000 | 2/11 | 30/162 | |
第八周 | 500/2000 | 2/13 | 20/182 |