Java基础类库
本章思维导图
用户互动
使用Scanner获取键盘输入
- Scanner主要提供了两个方法来扫描输入
-
hasNextXxx();
- 是否还有下一个输入项,其中
可以是Xxx
、int
等代表基本数据类型的字符串。long
- 是否还有下一个输入项,其中
-
nextXxx();
- 获取下一个输入项。
的含义与前一个方法中的Xxx
相同。Xxx
- 获取下一个输入项。
-
默认情况下,Scanner使用空白(
空格
、
Tab
、
回车
)作为多个输入项之间的分隔符。
如果希望改变Scanner的分隔符,使用方法
useDelimiter(String pattern);
Scanner的读取操作可能被阻塞,Scanner的
hasNext();
和
next();
方法都有可能阻塞,
hasNext();
方法是否阻塞与和其相关的
next();
方法是否阻塞无关
为Scanenr设置分隔符使用
useDelimiter(String pattern);
方法即可,该方法的参数应该是一个正则表达式
- Scanner提供了两个简单的方法来逐行读取
-
boolean hasNextLine();
- 返回输入源中是否还有下一行
-
String nextLine();
- 返回输入源中下一行的字符串
-
- Scanner不仅能读取用户的键盘输入,还可以读取文件输入。
- 只要在创建Scanner对象时传入一个
对象作为参数,就可以让Scanner读取该文件的内容。File
- 只要在创建Scanner对象时传入一个
系统相关
System类
System类代表当前Java程序的运行平台,程序不能创建System类的对象,System类提供了一些类变量和类方法,允许直接通过System类来调用这些类变量和类方法。
- System类提供了代表标准输入、标准输出和错误输出的类变量,并提供了一些静态方法用于访问环境变量、系统属性的方法,还提供了加载文件和动态链接库的方法。
- 加载文件和动态链接库主要对
方法有用,对于一些特殊的功能(如访问操作系统底层硬件设备等)Java程序无法实现,必须借助C语言来完成,此时需要C语言为Java方法提供实现。native
-
- Java程序中声明native修饰的方法,类似于
方法,只有方法签名,没有实现。编译该Java程序,生产一个abstract
文件。class
- Java程序中声明native修饰的方法,类似于
-
- 用
编译第1步生产的javah
文件,将生产一个class
文件。.h
- 用
-
- 写一个
文件实现native方法,这一步需要包含第2步产生的cpp
文件(这个.h
文件中包含了JDK带的.h
文件)。jni.h
- 写一个
-
- 将第3步的
文件编译成动态链接库文件。.cpp
- 将第3步的
-
- 在Java中用System类活动
方法或Runtime类的loadLibrary..()
方法加载第4步产生的动态链接库文件,Java程序中就可以调用这个native方法了。loadLibrary()
- 在Java中用System类活动
-
- 加载文件和动态链接库主要对
调用System类的
getenv()
、
getProperties()
、
getProperty()
等方法来访问程序所在平台的环境变量和系统属性。
System类提供了通知系统进行垃圾回收的
gc()
方法,以及通知系统进行资源清理的
runFinalization()
方法。
- System类还有两个获取系统当前时间的方法
-
currentTimeMillis();
-
nanoTime();
- 它们都返回一个
型整数;实际上它们都返回当前时间与UTC1970年1月1日午夜的时间差,前者以毫秒作为单位,后者以纳秒作为单位。long
- 这两个方法返回的时间粒度取决于底层的操作系统,可能所在的操作系统根本不支持以毫秒、纳秒作为计时单位。
- 许多操作系统以几十毫秒为单位测量时间,
方法不可能返回精确的毫秒数;而currentTimeMillis()
方法很少用,因为大部分操作系统都不支持使用纳秒作为计时单位。nanoTime()
-
System类的
in
、
out
、
err
分别代表系统的标准输入(通常是键盘输入)、标准输出(通常是显示器)和错误输出流,并提供了
setIn()
、
setOut()
和
setErr()
方法来改变系统的标准输入、标准输出和标准错误输出流。
System类还提供了一个
identityHashCode(Object x);
方法,该方法返回指定对象的精确
hashCode
值,根据该对象的地址计算得到的
hashCode
值。
Runtime类与java9的ProcessHandle
Runtime类代表Java程序运行时的环境,每个Java程序都有一个与之对应的Runtime实例,应用程序通过该对象与其运行时环境相连。
应用程序不能创建自己的Runtime实例,但可以通过
getRuntime()
方法获取与之关联的Runtime对象。
Runtime类也提供了
gc()
方法或
runFinalization()
方法来通知系统进行垃圾回收、清理系统资源,并提供了
load(String filename)
和
loadLibrary(String libname)
方法来加载文件和动态链接库。
- Runtime类部分方法
-
availableProcessors();
-
freeMemory();
-
totalMemory();
-
maxMemory();
-
exec();
-
通过exec启动平台上的命令之后,它就变成了一个进程,Java使用Process来代表进程。
Java9新增了一个
ProcessorHandle
接口,通过该接口可获取进程的ID、父进程和后代进程;通过该接口的
onExit()
方法可在进程结束时完成某些行为。
ProcessorHandle
还提供了一个
ProcessorHandle.Info
类,用于获取进程的命令、参数、启动时间、累计运行时间、用户等信息。
常用类
Object类
- 常用方法
-
boolean equals(Object obj);
- 判断指定对象与该对象是否相等。
-
protected void finalize();
- 当系统中没有引用变量引用到该对象时,垃圾回收器调用此方法来清理该对象的资源。
-
Class<?> getClass();
- 返回该对象的运行时类。
-
int hashCode();
- 返回该对象的hashCode值。
-
String toString();
- 返回该对象的字符串表示。
-
Java还提供了一个
protected
修饰的
clone()
方法,该方法用于帮助其他对象实现自我克隆,就是得到一个当前对象的副本,而且二者之间完全隔离。
- 自定义类实现克隆的步骤
-
- 自定义类实现
接口。这是一个标记行性的接口,实现接口的对象可以实现自我克隆,接口里没有定义任何方法。Cloneable
- 自定义类实现
-
- 自定义类实现自己的
方法。clone()
- 自定义类实现自己的
-
- 实现
方法时通过clone()
调用super.clone();
实现的Object
方法来得到该对象的副本,并返回副本。clone()
- 实现
-
Object类提供的Clone机制只对对象里各实例变量进行简单复制,如果实例变量的类型是引用类型,Object的Clone机制也只是简单地复制这个引用变量,这样原有对象的引用类型的实例变量与克隆对象的引用类型的实例变量依然指向内存中的同一个实例。
Object类的
clone()
方法只是一种浅克隆,只克隆该对象的所有成员变量值,不会对引用类型的成员变量值所引用的对象进行克隆。
如果需要对对象进行深克隆,则需要进行递归克隆,保证所有引用类型的成员变量值所引用的对象都被复制了。
Objects类
Java7新增的一个类,提供了一些工具方法来操作对象,这些工具方法大多是空指针安全的。
Java为工具类的命名习惯是添加一个字母
s
,比如操作数组的工具类是
Arrays
,操作集合的工具类是
Collections
。
Java9改进的String、StringBuffer和StringBuilder类
Java提供了
String
、
StringBuffer
和
StringBuilder
三个类来封装字符串,并提供了一系列方法来操作字符串对象。
String类是不可变类,即一旦一个String对象被创建以后,包含在这个对象的字符序列是不可改变的,直至这个对象被销毁。
StringBuffer
对象则代表一个字符序列可变的字符串,当一个StringBuffer被创建以后,通过StringBuffer提供的
append()
、
insert()
、
reverse()
、
setCharAt()
、
setLength()
等方法改变这个字符串对象的字符序列。一旦通过StringBuffer生产了最终想要的字符串,就可以调用它的
toString()
方法将其转换为一个String对象。
StringBuilder
类是JDK1.5新增的类,它也代表可变字符串对象。StringBuffer和StringBuilder基本相似,两个类的构造器和方法也基本相同。不同的是,StringBuffer是线程安全的,而StringBuilder则没有实现线程安全功能,所以性能略高。
String、StringBuffer、StringBuilder都实现了
CharSequence
接口,因此
CharSequence
可认为是一个字符串的协议接口。
- String类提供了大量构造器来创建String对象
-
:创建了一个包含0个的字符串序列的String对象。String()
-
:使用指定的字符集将指定的String(byte[] bytes, Charset charset)
数组解码成一个新的String对象。byte[]
-
:使用平台默认的字符集将指定的String(byte[] bytes, int offset, int length)
数组从byte[]
开始、长度为offset
的子数组解码成一个新的String对象。length
-
:使用指定的字符集将指定的String(byte[] bytes, int offset, int length, String charsetName)
数组从byte[]
开始、长度为offset
的子数组解码成一个新的String对象。length
-
:使用指定的字符集将指定的String(byte[] bytes, String charsetName)
数组解码成一个新的String对象。byte[]
-
:将指定的字符数组从String(char[] value, int offset, int count)
开始、长度为offset
的字符元素连缀成字符串。count
-
:根据字符串直接量来创建一个String对象。String(String original)
-
:根据String(StringBuffer buffer)
对象来创建对应的String对象。StringBuffer
-
:根据String(StringBuilder builder)
对象来创建对应的String对象。StringBuilder
-
- String类也提供了大量方法来操作字符串对象
-
:获取字符串中指定位置的字符。char charAt(int index)
-
:比较两个字符串的大小。如果两个字符串的字符序列相等,则返回0;不相等时,从两个字符串第0个字符开始比较,返回第一个不相等的字符差。另一种情况,较长字符串的前面部分恰巧是较短的字符串,则返回它们的长度差。int compareTo(String anotherString)
-
:将该String对象和str连接在一起。String concat(String str)
-
:将该对象与StringBuffer对象sb进行比较,当它们包含的字符序列相同时返回true。boolean contentEquals(StringBuffer sb)
-
:将字数组连缀成字符串。static String copy ValueOf(char[] data)
-
:将char数组的子数组中的元素连缀成字符串。static String copyValueOf(char[] data, int offset, int count)
-
:返回该String对象是否以boolean endsWith(String suffix)
结尾。suffix
-
:将字符串与指定对象比较,如果二者包含的字符序列相等,则返回true,否则返回false。boolean equals(Object anObject)
-
:将字符串与boolean equalsIgnoreCase(String str)
忽略大小写比较。str
-
:将该String对象转换成byte[] getBytes()
数组。byte
-
:该方法将字符串中从void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
开始,到srcBegin
结束的字符复制到srcEnd
字符数组中,其中dst
为目标字符数组的起始复制位置。dstBegin
-
:找出int indexOf(int ch, int fromIndex)
字符在该字符串中从ch
开始第一次出现的位置。fromIndex
-
:找出int indexOf(String str)
子字符串在该字符串中第一次出现的位置。str
-
:找出int indexOf(String str, int fromIndex)
子字符串在该字符串中从str
开始第一次出现的位置。fromIndex
-
:找出int lastIndexOf(int ch)
字符在该字符串中最后一次出现的位置。ch
-
:找出int lastIndexOf(int ch, int fromIndex)
字符中从ch
在该字符串中最后一次出现的位置。fronIndex
-
:找出int lastIndexOf(String str)
子字符串在该字符串中最后一次出现的位置。str
-
:找出int lastIndexOf(String str, int fromIndex)
子字符串在该字符串中从str
开始后最后一次出现的位置。fromIndex
-
:返回当前字符串长度。int length()
-
:将字符串中第一个String replace(char oldChar, char newChar)
替换成oldChar
。newChar
-
:该String对象是否以boolean startsWith(String prefix)
开始。prefix
-
:该String对象从boolean startsWith(String prefix, int toffset)
位置算起,是否以toffset
开始。prefix
-
:获取从String substring(int beginIndex)
位置开始到结束的字符串。beginIndex
-
:获取从String substring(int beginIndex, int endIndex)
位置开始到beginIndex
位置的子字符串。endIndex
-
:将该String对象转换成char数组。char[] toCharArray()
-
:将字符串转换成小写。String toLowerCase()
-
:将字符串转换成大写。String toUpeprCase()
-
:一系列用于将基本类型值转换为String对象的方法。static String valueOf(X x)
-
- StringBuffer、StringBuilder有两个属性:
和length
。capacity
- 其中
属性表示其包含的字符串序列的长度。与String对象不同的是,StringBuffer、StringBuilder的length是可以改变的,可以通过length
、length()
方法来访问和修改其字符序列的长度。setLength(int len)
-
属性表示StringBuilder的容量,capacity
通常比capacity
大,程序通常无需关心length
属性。capacity
- 其中
Math类
Math类是一个工具类,它的构造器被定义成
private
的,因此无法创建Math类的对象;Math类中的所有方法都是类方法;还提供了的两个类变量
PI
和
E
。
ThreadLocalRandom与Random
Random
类专门用于生成一个伪随机数,它有两个构造器:一个构造器使用默认的种子(以当前时间作为种子),另一个构造器需要显式传入一个
long
型整数的种子。
ThreadLocalRandom
类是Java7新增的一个类,它是
Random
的增强版。在并发访问的环境下,使用
ThreadLocalRandom
来代替
Random
可以减少多线程资源竞争,最终保证系统具有更好的线程安全性。
ThreadLocalRandom
类的用法和
Random
类的用法基本相似,它提供了一个静态的
current()
方法来获取
ThreadLocalRandom
对象,获取该对象之后即可调用各种
nextXxx()
方法来获取伪随机数。
Random使用一个48位的种子,如果这个类的两个实例都是用同一个种子创建的,对它们以同样的顺序调用方法,则它们会产生相同的数字序列。
为避免两个Random对象产生相同的数字序列,通常推荐使用当前时间作为Random对象的种子:
System.currentTimeMillis();
BigDecimal类
float
、
double
两种基本浮点类型的浮点数容易引起精度丢失。
为了精确表示、计算浮点数,Java提供了
BigDecimal
类,该类提供了大量的构造器用于创建BigDecimal对象,包括把所有的基本数值类型变量转换成一个BigDecimal对象,包括利用数字字符串、数字字符数组来创建BigDecimal对象。
不推荐使用
BigDecimal(double val);
构造器来创建对象,而是
BigDecimal(String val);
或
BigDecimal.valueOf(double value);
静态方法来创建BigDecimal对象。
BigDecimal类提供了
add()
、
subtract()
、
multiply()
、
divide()
、
pow()
等方法对精确浮点数进行常规算术运算。
日期、时间类
Date类
Java提供了
Date
类来处理日期、时间,Date对象既包含日期,也包含时间。
Date类从JDK1.0起就开始存在了,但正因为它历史悠久,所以它的大部分构造器、方法都已经过时,不在推荐使用了。
Date类提供了6个构造器,其中4个已经
Deprecated
(Java不在推荐使用,使用不再推荐的构造器时编译会提出警告信息,并导致程序性能、安全性能等方面的问题),剩下的两个构造器:
-
:生成一个代表当前日期时间的Date对象。该构造器在底层调用Date()
获得System.currentMillis()
整数作为日期参数。long
-
:根据指定的Date(long date)
型整数来生成一个Date对象。该构造器的参数表示创建的Date对象和GMT1970年1月1日00:00:00之间的时间差,以毫秒作为计时单位。long
Date对象的大部分方法也
Deprecated
了,剩下为数不多的几个方法:
-
:测试该日期是否在指定日期when之后。boolean after(Date when)
-
:测试该日期是否在指定日期when之前。boolean before(Date when)
-
:返回该时间对应的long型整数,即从GMT1970-01-01 00:00:00到该Date对象之间的时间差,以毫秒作为计时单位。long getTime()
-
:设置Date对象的时间。void setTime(long time)
总体来说,Date是一个设计相当糟糕的类,Java官方推荐尽量少用Date的构造器和方法。
Calendar类
由于
Date
类在设计上存在一些缺陷,所以Java提供了
Calendar
类来更好地处理日期和时间。
Calendar
类本身是一个抽象类,它是所有日历类的模板,并提供了一些所有日历通用的方法;但它本身不能直接实例化,程序只能创建
Calendar
子类的实例,Java本身提供了一个
GregorianCalendar
类,一个代表格里高利日历的子类,它代表了通常所说的公历。
Calendar
类是一个抽象类,所以不能使用构造器来创建Calendar对象。但它提供了几个静态
getInstance()
方法来获取
Calendar
对象,这些方法根据
TimeZone
、
Locale
类来获取特定的
Calendar
,如果不指定
TimeZone
、
Locale
,则使用默认的
TimeZone
、
Locale
来创建
Calendar
。
Calendar
和
Date
都是表示日期的工具类,他们直接可以自由转换。
Calendar类提供了大量访问、修改日期时间的方法:
-
:根据日历的规则,为给定的日历字段添加或减去指定的时间量。void add(int field, int amount)
-
:返回指定日历字段的值。int get(int field)
-
:返回指定日历字段可能拥有的最大值。int getActualMaximum(int field)
-
:返回指定日历字段可能拥有的最小值。int getActualMinimum(int field)
-
:为给定的日历字段设置为给定值。void set(int field, int value)
-
:设置Calendar对象的年、月、日三个字段的值。void set(int year, int month, int date)
-
:设置Calendar对象的年、月、日、时、分、秒6个字段的值。void set(int year, int month, int date, int hourOfDay, int minute, int second)
上面的很多方法都需要一个
int
类型的
field
参数,
field
是
Cakendar
类的类变量,如
Calendar.YEAR
、
Calendar.MONTH
等分别代表了年、月、日、小时、分钟、秒等时间字段。
Calendar.MONTH
字段代表月份,月份的起始值不是1,而是0。
Calendar类的注意点:
-
与add
的区别roll
-
的功能非常强大,add(int field, int amount)
主要用于改变add
的特定字段的值。有两条规则:Calendar
- 当被修改的字段超出它允许的范围时,会发生进位,即上一级字段也会增大。
- 如果下一级字段也需要改变,那么该字段会修正到变化最小的值。
-
的规则与roll()
的处理规则不同:当被修改的字段超出它允许的范围时,上一级字段不会增大;下一级字段的处理规则与add()
相似。add()
-
- 设置
的容错性Calendar
- Calendar有两种解释日历字段的模式:
模式和lenient
模式。当处于non-lenient
模式时,每个时间字段可接受超过它允许范围的值;当处于lenient
模式时,如果为某个时间字段设置的值超出了它允许的取值范围,程序将会抛出异常。non-lenient
- Calendar有两种解释日历字段的模式:
-
方法延迟修改set()
-
方法将日历字段set(f, value)
更改为f
,此处它还设置了一个内部成员变量,以指示日历字段value
已经被更改。尽管日历字段f
是立即更改的,但该f
所代表的时间不会立即修改,直到下次调用Calendar
、get()
、getTime()
、getTimeInMillis()
或add()
时才会重新计算日历的时间。roll()
-
Java8新增的日期、时间包
Java8新增了一个java.time包,该包包含如下常用类:
-
:该类用于获取指定时区的当前日期、时间。该类可取代System类的currentTimeMillis()方法,而且提供了更多方法来获取当前日期、时间。该类提供了大量静态方法来获取Clock
对象。Clock
-
:该类代表持续时间。该类可以非常方便地获取一段时间。Duration
-
:代表一个具体的时刻,可以精确到纳秒。该类提供了静态的Instant
方法来获取当前时刻,也提供了静态的now()
方法来获取now(Clock clock)
对应的时刻。除此之外,它还提供了一系列clock
方法在当前时刻基础上减去一段时间,也提供了minusXxx()
方法在当前时刻基础上加上一段时间。plusXxx()
-
:该类代表不带时区的日期,例如1999-10-30。该类提供了静态的LocalDate
方法来获取当前日期,也提供了静态的now()
方法来获取当前now(Clock clock)
对应的日期。除此之外,它还提供了一系列clock
方法在当前年份基础上减去几年、几月、几周或几日,也提供了minusXxx()
方法在当前年份基础上加上几年、几月、几周或几日。plusXxx()
-
:该类代表不带时区的时间,例如10:30:13。该类提供了静态的LocalTime
方法来获取当前时间,也提供了静态的now()
方法来获取now(Clock clock)
对应的时间。除此之外,它还提供了一系列clock
方法在当前年份基础上减去几小时、几分、几秒等,也提供了minusXxx()
方法在当前年份基础上加上加几小时、几分、几秒等。plusXxx()
-
:该类代表不带时区的日期、时间,例如1999-10-30T10:30:13。该类提供了静态的LocalDateTime
方法来获取当前日期、时间,也提供了静态的now()
方法来获取now(Clock clock)
对应的日期、时间。除此之外,它还提供了一系列clock
方法在当前年份基础上减去几年、几月、几日几小时、几分、几秒等,也提供了minusXxx()
方法在当前年份基础上加上几年、几月、几日几小时、几分、几秒等。plusXxx()
-
:该类仅代表月日,例如–10-30。该类提供了静态的MonthDay
方法来获取当前月日,也提供了静态的now()
方法来获取now(Clock clock)
对应的月日。clock
-
:该类仅代表年,例如1999。该类提供了静态的Year
方法来获取当前年份,也提供了静态的now()
方法来获取now(Clock clock)
对应的年份。除此之外,它还提供了clock
方法在当前年份基础上减去几年,也提供了minusYears()
方法在当前年份基础上加上几年。plusYear()
-
:该类仅代表年月,例如1999-10。该类提供了静态的YearMonth
方法来获取当前年月,也提供了静态的now()
方法来获取now(Clock clock)
对应的年月。除此之外,它还提供了clock
方法在当前年月基础上减去几年、几月,也提供了minusXxx()
方法在当前年月基础上加上几年、几月。plusXxx()
-
:该类代表一个时区化的日期、时间。ZonedDateTime
-
:该类代表一个时区。ZoneId
-
:这是一个枚举类,定义了周日到周六的枚举值。DayOfWeek
-
:这是一个枚举类,定义了一月到十二月的枚举值。Month
-
正则表达式
正则表达式是一个强大的字符串处理工具,可以对字符串进行查找、提取、分割、替换等操作。
String
类里也提供了如下几个特殊方法:
-
:判断该字符串是否匹配指定的正则表达式。boolean matches(String regex)
-
:将该字符串中所有匹配String replaceAll(String regex, String replacement)
的字串替换成regex
。replacement
-
:将该字符串中第一个匹配String repalceFirst(String regex, String replacement)
的字串替换成regex
。replacement
-
:以String[] split(String regex)
作为分隔符,把该字符串分割成多个字串。regex
上面这些特殊的方法都依赖于Java提供的正则表达式支持,除此之外,Java还提供了
Pattern
和
Matches
两个类专门用于提供正则表达式支持。
创建正则表达式
正则表达式所支持的合法字符:
-
:字符x(x可代表任何合法的字符)x
-
:八进制数0mnn所代表的字符\0mnn
-
:十六进制值0xhh所代表的字符\xhh
-
:十六进制值0xhhhh所代表的\uhhhh
字符Unicode
-
:制表符(’\u000A’)\t
-
:新行(换行)符(’\u000A’)\n
-
:回车符(’\u000D’)\r
-
:换页符(’\u000C’)\f
-
:报警(bell)符(’\u0007’)\a
-
:Escape符(’\u001B’)\e
-
:\cx
对应的控制符。x值必须为x
或A~Z
之一。a~z
正则表达式中有一些特殊字符,这些特殊字符在正则表达式中有其特殊的用途,如果需要匹配这些特殊字符,就必须首先将这些字符转义,也就是在前面加一个反斜线(
\
)。
-
:匹配一行的结尾。$
-
:匹配一行的开头。^
-
:标记子表达式的开始和结束位置。()
-
:用于确定中括号表达式的开始和结束位置。[]
-
:用于标记前面子表达式的出现频度。{}
-
:指定前面子表达式可以出现零次或多次,*
-
:指定前面表达式可以出现一次或多次。+
-
:指定前面子表达式可以出现零次或一次。?
-
:用于转义下一个字符,或指定八进制、十六进制字符。\
-
:指定两项之间任选一项。|
预定义字符
-
:可以匹配任何字符。.
-
:匹配\d
的所有数字。0~9
-
:匹配非数字。\D
-
:匹配所有的空白字符,包括空格、制表符、回车符、换页符、换行符等。\s
-
:匹配所有的非空白字符。\S
-
:匹配所有的单词字符,包括0~9所有数字、26个英文字母和下划线(_)。\w
-
:匹配所有的非单词字符。\W
方括号表达式
- 表示枚举:例如
,表示f、x其中任意一个字符;[fx]
表示j、x其中任意一个字符。[jk]
- 表示范围-:例如
,表示[a-f]
范围内的任意字符;如a~f
,表示[a-cx-z]
、a~c
范围内的任意字符。x~z
- 表示求否
:例如^
,表示非a、b、c的任意字符;[^abc]
,表示不是[^a-f]
范围内的任意字符。a~f
- 表示与运算
:例如&&
,求[a-z&&[def]]
和a~z
的交集,表示d、e或f;[def]
,[a-z&&[^bc]]
范围内的所有字符,除b和c之外,即a~z
。[ad-z]
- 表示并运算:并运算与前面的枚举类似。例如
,表示[a-d[m-p]]
。[a-dm-p]
边界匹配符
-
:行的开头^
-
:行的结尾$
-
:单词的边界\b
-
:非单词的边界\B
-
:输入的开头\A
-
:前一个匹配的结尾\G
-
:输入的结尾,仅用于最后的结束符。\Z
-
:输入的结尾\z
数量标识符
-
(贪婪模式):数量标识符默认采用贪婪模式,除非另有表示。贪婪模式的表达式会一直匹配下去,直到无法匹配为止。Greedy
-
:X表达式出现零次或一次X?
-
:X表达式出现零次或多次X*
-
:X表达式出现一次或多次X+
-
:X表达式出现n次X{n}
-
:X表达式最少出现n次X{n,}
-
:X表达式最少出现n次,最多出现m次X{n,m}
-
-
(勉强模式):用问号后缀(Reluctant
)表示,它只会匹配最少的字符。也称为最小匹配模式。?
-
:X表达式出现零次或一次X??
-
:X表达式出现零次或多次X*?
-
:X表达式出现一次或多次X+?
-
:X表达式出现n次X{n}?
-
:X表达式最少出现n次X{n,}?
-
:X表达式最少出现n次,最多出现m次X{n,m}?
-
-
(占有模式):用加号后缀(Possessive
)表示,目前只有Java支持占有模式,通常比较少用。+
-
:X表达式出现零次或一次X?+
-
:X表达式出现零次或多次X*+
-
:X表达式出现一次或多次X++
-
:X表达式出现n次X{n}+
-
:X表达式最少出现n次X{n,}+
-
:X表达式最少出现n次,最多出现m次X{n,m}+
-
使用正则表达式
一旦在程序中定义了正则表达式,就可以使用
Pattern
和
Matcher
来使用正则表达式。
Pattern
对象是正则表达式编译后在内存中的表示形式,因此,正则表达式字符串必须先被编译为Pattern对象,然后再利用Pattern对象创建对应的
Matcher
对象。执行匹配所涉及的状态保留在
Matcher
对象中,多个
Matcher
对象可共享同一个
Pattern
对象。
如果某个正则表达式仅需一次使用,则可直接使用Pattern类的静态
matches()
方法,此方法自动把指定字符串编译成匿名
Pattern
对象,并执行匹配。
Pattern是不可变类,可供多个并发线程安全使用。
Matcher
类提供了如下几个常用方法:
-
:返回目标字符串中是否包含与find()
匹配的子串。Pattern
-
:返回上一次与group()
匹配的子串。Pattern
-
:返回上一次与start()
匹配的子串在目标字符串中的开始位置。Pattern
-
:返回上一次与end()
匹配的子串在目标字符串中的结束位置加1。Pattern
-
:返回目标字符串前面部分与lookingAt()
是否匹配。Pattern
-
:返回整个目标字符串与matches()
是否匹配。Pattern
-
:将现有的reset()
对象应用于一个新的字符序列。Matcher
通过
Matcher
类的
find()
和
group()
方法可以从目标字符串中依次取出特定子串(匹配正则表达式的子串)。
find()
方法依次查找字符串中与
Pattern
匹配的子串,一旦找到对应的子串,下次调用
find()
方法时将接着向下查找。
find()
方法还可以传入一个
int
类型的参数,带
int
参数的
find()
方法将从该
int
索引处向下搜索。
start()
和
end()
方法主要用于确定子串在目标字符串中的位置。
使用
find()
、
group()
方法逐项取出目标字符串中与指定正则表达式匹配的子串,并使用
start()
、
end()
方法返回子串在目标字符串中的位置。
matches()
和
lookingAt()
方法有点相似,只是
matches()
方法要求整个字符串和
Pattern
完全匹配时才返回
true
,而
lookingAt()
只要字符串以
Pattern
开头就会返回
true
。
reset()
方法可将现有的
Matcher
对象应用于新的字符序列。
从某个角度看,
Matcher
的
matches()
、
lookingAt()
和
String
类的
equals()
、
startWith()
有点相似。区别是
String
类的
equals()
和、
startWith()
都是与字符串进行比较,而
Matcher
的
matches()
和
lookingAt()
则是与正则表达式进行匹配。
String
类里也提供了
matches()
方法,该方法返回该字符串是否匹配指定的正则表达式。
还可以利用正则表达式对目标字符串进行分割、查找、替换等操作。
Matcher
类提供了
replaceAll(String replacement)
把字符串中所有与正则表达式匹配的子串替换成
replacement
,还提供了一个
replaceFirst(String replacement)
方法,该方法仅替换第一个匹配的子串。
String
类也提供了
replaceAll()
、
replaceFirst()
、
split()
等方法。
变量处理和方法处理
Java9引入了一个新的
VarHandle
类,并增强了原有的
MethodHandle
类。通过这两个类,允许Java像动态语言一样引用变量、饮用方法,并调用它们。
Java9增强的
MethodHandle
-
为Java增强了方法引用的功能,方法引用的概念有点类似于C的函数指针。这种方法引用是一种轻量级的引用方式,它不会检查方法的访问权限,也不管方法所属的类、实例方法或静态方法,MethodHandle
就是简单代表特定的方法,并可通过MethodHandle
来调用方法。MethodHandle
- 为了使用
类,还涉及如以下几个类:MethodHandle
-
:MethodHandles
的工厂类,它提供了一系列静态方法用于获取MethodHandle
。MethodHandle
-
:MethodHandles.Lookup
静态内部类也是Lookup
、MethodHandle
的工厂类,专门用于获取VarHandle
和MethodHandle
。VarHandle
-
:代表一个方法类型。MethodType
根据方法的形参、返回值类型来确定方法类型。MethodType
- 程序使用
对象根据类、方法名、方法类型来获取MethodHandles.Lookup
对象。获取的方法名是一个字符串类型,这意味着通过MethodHandle
可以让Java动态调用某个方法。MethodHandle
-
Java9增强的
VarHandle
-
主要用于动态操作数组的元素或对象的成员变量。VarHandle
和VarHandle
非常相似,它也需要通过MethodHandle
来获取实例,接下来调用MethodHandles
的方法即可动态操作指定数组的元素或指定对象的成员变量。VarHandle
Java9改进的国际化与格式化
国际化是指应用程序运行时,可根据客户端请求来自的国家/地区、语言的不同而显示不同的界面。
Java国际化的思路:
- Java程序的国际化思路是将程序中的标签、提示等信息放在资源文件中,程序需要支持哪些国家、语言环境,就对应提供的资源文件。
- 资源文件是
对,每个资源文件中的key-value
是不变的,但key
则随不同的国家、语言而改变。value
- Java程序的国际化主要是通过如下三个类完成:
-
:用于加载国家、语言资源包。java.util.ResourceBundle
-
:用于封装特定的国家/区域、语言环境。java.util.Locale
-
:用于格式化带占位符的字符串。java.text.MessageFormat
-
- 资源文件的命名可以有如下三种形式:
-
baseName_language_country.properties
-
baseName_language.properties
-
baseName.properties
-
- 其中
是资源文件的基本名,用户可随意指定;而baseName
和language
都不可随意变化,必须是Java所支持的语言和国家。country
Java支持的国家和语言:
- 可调用
类的Locale
方法,该方法返回一个getAvailableLocales()
数组,该数组包含了Java所支持的国家和语言。Locale
完成程序国际化:
- 为了让字符串常量可以改变,可以将需要输出的各种字符串(不同的国家/语言环境对应不同的字符串)定义在资源包中。
- Java9支持使用
字符集来保存属性文件,这样在属性文件中就可以直接包含非西欧字符。UTF-8
- Java9程序国际化的关键类是
,它有一个静态方法:ResourceBundle
,该方法将根据getBUndle(String baseName, Locale locale)
加载资源文件,而Locale
封装了一个国家、语言。Locale
使用
MessageFormat
处理包含占位符的字符串:
- 如果需要输出的消息中必须包含动态的内容,可以使用带占位符的消息。
- 例如:
。当程序使用msg=你好!{0}!今天是{1}
的ResourceBundle
方法来取出getString()
对应的字符串时,程序还需要为msg
和{0}
两个占位符赋值。{1}
- 此时需要使用
类,该类包含一个有用的静态方法:MessageFormat
-
:返回后面的多个参数值填充前面的format(String pattern, Object... values)
字符串,其中pattern
不是正则表达式,而是一个带占位符的字符串。patter
-
使用类文件代替资源文件:
除使用属性文件作为资源文件外,
Java
也允许使用类文件代替资源文件,即将所有的
key-value
对存入
class
文件。
使用类文件来代替资源文件必须满足以下条件:
- 该类的类名必须是
,这与属性文件的命名相似。baseName_language_country
- 该类必须继承
,并重写ListResourceBundle
方法,该方法返回getContents()
数组,该数组的每一项都是Object
对。key-value
如果系统同时存在资源文件、类文件,系统将以类文件为主,而不会调用资源文件。
对于简体中文的
Locale
,
ResourceBundle
搜索资源文件的顺序是:
-
baseName_zh_CN.class
-
baseName_zh_CN.properties
-
baseName_zh.class
-
baseName_zh.properties
-
baseName.class
-
baseName.properties
Java9新增的日志API
Java9强化了原有的日志API,这套日志API只是定义了记录消息的最小API,开发者可将这些日志消息路由到各种主流的日志框架(如
SLF4J
、
Log4J
等),否则默认使用Java传统的
java.util.logging
日志
API
。
这套日志API的用法非常简单,只要两步即可:
- 调用
类的System
方法获取getLogger(String name)
对象System.Logger
- 调用
对象的System.Logger
方法输出日志。该方法的第一个参数用于指定日志级别。log()
- 日志级别:
- Java9日志级别
-
:最低级别,系统将会输出所有日志信息。ALL
-
:输出系统的各种跟踪信息。TRACE
-
:输出系统的各种调试信息。DEBUG
-
:输出系统内需要提示用户的提示信息。INFO
-
:只输出系统内警告用户的警告信息。WARNING
-
:只输出系统发生错误的错误信息。ERROR
-
:关闭日志输出。OFF
-
- 传统日志级别
-
:最低级别,系统将会输出所有日志信息。ALL
-
:输出系统的各种跟踪信息。FINER
-
:输出系统的各种调试信息。FINE
-
:输出系统内需要提示用户的提示信息。INFO
-
:只输出系统内警告用户的警告信息。WARNING
-
:只输出系统发生错误的错误信息。SERVRE
-
:关闭日志输出。OFF
-
- Java9日志级别
- 日志级别:
Java9的日志API也支持国际化,
System
类除使用简单的
getLogger(String name)
方法获取
System.Logger
对象之外,还可使用
getLogger(String name, ResourceBundle bundle)
方法来获取该对象,该方法需要传入一个国际化语言资源包,这样该
Logger
对象即可根据
key
来输出国际化的日志信息。
使用 NumberFormat
格式化数字
NumberFormat
MessageFormat
是抽象类
Format
的子类,
Format
抽象类还有两个子类:
NumberFormat
和
DateFormat
,它们分别用以实现数值、日期的格式化。
NumberFormat
、
DateFormat
可以将数值、日期转换成字符串,也可以将字符串转换成数值、日期。
NumberFormat
和
DateFormat
都包含了
format()
和
parse()
方法,其中
format()
用于将数值、日期格式化成字符串,
parse()
用于将字符串解析成数值、日期。
NumberFormat
也是一个抽象基类,所以无法通过它的构造器来创建
NumberFormat
对象,它提供了如下几个类方法来得到
NumberFormat
对象:
-
:返回默认getCurrencyInstance()
的货币格式器。也可以在调用该方法时传入指定的Locale
,则获取指定Locale
的货币格式器。Locale
-
:返回默认getIntegerInstance()
的整数格式器。也可以在调用该方法时传入指定的Locale
,则获取指定Locale
的整数格式器。Locale
-
:返回默认getNumberInstance()
的通用数值格式器。也可以在调用该方法时传入指定的Locale
,则获取指定的Locale
的通用数值格式器。Locale
-
:返回默认的getPercentInstance()
的百分数格式器。也可以在调用该方法时传入指定的Locale
,则获取指定的Locale
的百分数格式器。Locale
一旦获得了
NumberFormat
对象后,就可以调用它的
format()
方法来格式化数值,包括整数和浮点数。
使用 DateFormat
格式化日期、时间
DateFormat
- 与
相似的是,NumberFormat
也是一个抽象类,它也提供了如下几个类方法用于获取DateFormat
对象:DateFormat
-
:返回一个日期格式器,它格式化后的字符串只有日期,没有时间。该方法可以传入多个参数,用于指定日期样式和getDateInstance()
等参数;如果不指定这些参数,则使用默认参数。Locale
-
:返回一个时间格式器,它格式化后的字符串只有时间,没有日期。该方法可以传入多个参数,用于指定时间样式和getTimeInstance()
等参数;如果不指定这些参数,则使用默认参数。Locale
-
:返回一个日期、时间格式器,它格式化后的字符串既有日期,也有时间。该方法可以传入多个参数,用于指定日期样式、时间样式和getDateTimeInstance()
等参数;如果不指定这些参数,则使用默认参数。Locale
-
上面三个方法可以指定日期样式、时间样式参数,它们是
DateFormat
的4个静态常量:
FULL
、
LONG
、
MEDIUM
和
SHORT
,通过这4个样式参数可以控制生成的格式化字符串。
DateFormat
的
parse()
方法可以把一个字符串解析成
Date
对象,但它要求被解析的字符串必须符合日期字符串的要求,否则可能抛出
ParseException
异常。
使用 SimpleDateFormat
格式化日期
SimpleDateFormat
DateFormat
的
parse()
方法可以把字符串解析成
Date
对象,但
parse()
方法不够灵活,它要求被解析的字符串必须满足特定的格式;为了更好地格式化日期、解析日期字符串,Java提供了
SimpleDateFormat
类。
-
是SimpleDateFormat
的子类。DateFormat
-
可以非常灵活地格式化SimpleDateFormat
,也可以用于解析各种格式的日期字符串。创建Date
对象时需要传入一个SimpleDateFormat
字符串,这个pattern
不是正则表达式,而是一个日期模板字符串。pattern
Java8新增的日期、时间格式器
java.time.format
包下提供了一个
DateTimeFormatter
格式器类,该类相当于
DateFormat
和
SimpleDateFormat
的合体。
DateTimeFormatter
不仅可以将日期、时间对象格式化成字符串,也可以将特定格式的字符串解析成日期、时间对象。
为了使用
DateTimeFormatter
进行格式化或解析,必须先获取
DateTimeFormatter
对象,获取对象有如下三种常见的方式:
- 直接使用静态常量创建
格式器。DateTimeFormatter
类中包含了大量形如DateTimeFormatter
、ISO_LOCAL_DATE
、ISO_LOCAL_TIME
等静态常量,这些静态常量本身就是ISO_LOCAL_DATE_TIME
实例。DateTimeFormatter
- 使用代表不同风格的枚举值来创建
格式器。在DateTimeFormatter
枚举类中定义了FormatStyle
、FULL
、LONG
、MEDIUM
四个枚举值,它们代表日期、时间不同的风格。SHORT
- 根据模式字符串来创建
格式器。类似于DateTimeFormatter
,可以采用模式字符串来创建SimpleDateFormat
。DateTimeFormatter
使用DateTimeFormatter完成格式化
使用
DateTimeFormatter
将日期、时间(
LocalDate
、
LocalDateTime
、
LocalTime
等实例)格式化为字符串,可通过如下两种方式:
- 调用
的DateTimeFormatter
方法执行格式化,其中format(TemporalAccessor temporal)
、LocalDate
、LocalDateTime
类都是LocalTime
接口的实现类。TemporalAccessor
- 调用
、LocalDate
、LocalDateTime
等日期、时间对象的LocalTime
方法执行格式化。format(DateTimeFormatter formatter)
DateTimeFormatter
则提供了一个
toFormat()
方法,该方法可获取
DateTimeFormatter
对应的
Format
对象。
使用DateTimeFormatter解析字符串
使
DateTimeFormatter
将指定格式的字符串解析成日期、时间对象(
LocalDate
、
LocalDateTime
、
LocalTime
等实例),可通过日期、时间对象提供的
parse(CharSequence text, DateTimeFormatter formatter)
方法进行解析。