1. 与用户互动
1.1 使用Scanner获取键盘输入
-
Scanner 类了解
- Scanner类是一个基于正则表达式的文本扫描器, 可以从文件,输入流, 字符串中解析出基本类型值和字符串值
- Scanner默认使用空白(包含空格, Tab空白, 回车)作为多个输入项之间的分隔符; 但是可为Scanner指定分割符, 通过使用:
useDelimiter(String prtten)
方法指定, patten 参数是一个正则表达式 - Scanner的读取操作可能被堵塞(当前执行顺序流暂停)来等待信息输入; 如果输入源没有结束, Scanner又读取不到更多的输入项时(尤其在键盘输入时比较常见), Scanner 的 hasNext() 和 next() 方法都有可能阻塞, (hasNext() 方法是否阻塞与其相关的 next() 方法是否阻塞无关)
-
Scanner 两个扫描输入方法:(例子1)
hasNextXxx()
: 是否还有下一个输入项, 其中Xxx可以是Int,Long等基本数据类型的字符串; 如果只是判断是
否包含下一项字符串, 则直接使用hasNext()nextXxx()
: 获取下一个输入项, Xxx的含义与前一个方法中Xxx相同
-
Scanner 逐行读取的方法:(例子2)
boolean hasNextLine()
: 返回输入源中是否还有下一行String nextLine()
: 返回输入源中下一行的字符串
示例代码
// 例子1:
// ScannerKeyBoardTest.java
// 获取到键盘标准输入, 然后将输入的内容输出到屏幕
import java.util.*;
public class ScannerKeyBoardTest {
public static void main(String[] args) {
// System.in 代表标准输入, 就是键盘输入
Scanner sc = new Scanner(System.in);
// 下面代码将只把回车作为换行符
sc.useDelimiter("\n");
// 判断是否还有下一个输入项
while (sc.hasNext()){
System.out.println("Input is: " + sc.next());
}
sc.close();
}
}
// 例子2:
import java.io.File;
import java.util.*;
public class ScannerFileTest{
public static void main(String[] args) throws Exception {
// 将一个File对象作为Scanner的构造器的参数, Scanner读取到文件内容
Scanner sc = new Scanner(new File(
"C:\\Users\\Administrator\\Desktop\\studyfile\\java\\src\\chapter06\\ScannerKeyBoardTest.java"));
System.out.println("扫描到的文件内容如下: ");
// 判断是否还有下一行
while (sc.hasNextLine()){
// 输出文件中的下一行
System.out.println(sc.nextLine());
}
sc.close();
}
}
2. 系统相关
2.1 System 类
-
System 类说明(例子1)
- System类代表当前Java程序的运行平台, 程序不能创建System的对象, System类提供了一些类变量和类方法, 允许直接通过System类来调用这些类变量和类方法
- System 类提供了代表标准输入, 标准输出和错误输出的类变量, 并提供了一些静态方法用于访问环境变量, 系统变量的方法, 还提供了加载文件和动态链接库的方法, 加载文件和动态连接库主要对 native 方法有用, 对于一些特殊的功能(如访问操作系统底层硬件设备等)Java无法实现, 必须借助C语言来完成 (例子1)
- System类的 in, out和err分别代表系统的标准输入(通常是键盘), 标准输出(通常是显示器)和错误输出流,还有 setIn(), setOut()和setErr()方法来改变系统的标准输入, 标准输出和标准错误流输出
- System类提供 gc() 方法进行垃圾回收, runFinalization() 方法进行资源清理
-
identityHashCode(object x) 方法 (例子2)
- 该方法返回对象的精确hashCode值, 也就是根据该对象的地址计算得到的 hashCode 值,
- 当某个类的hashCode()方法被重写后, 该类实例的 hashCode()方法就不能唯一标识该对象; 但通过identityHashCode()方法返回的hashCode 值, 依然是根据该对象的地址计算得到的 hashCode 值
- 如果两个对象的 identityHashCode 值相同, 则两个对象绝对是同一个对象
-
System 类获取当前时间的方法currentTimeMillis()和nanoTime()
- 这两个方法都返回一个long型整数, 实际上这两个方法返回的是当前时间与UTC1790年1月1日午夜的时间差; 这两个方法返回的时间精度取决于操作系统
- currentTimeMillis()是以毫秒作为单位, nanoTime()是以纳秒作为单位
示例代码
// 例子1:
import java.io.FileOutputStream;
import java.util.Map;
import java.util.Properties;
public class SystemTest {
public static void main(String[] args) throws Exception {
// 获取系统所有的环境变量
Map<String, String> env = System.getenv();
for (String name : env.keySet()){
System.out.println(name + "--->" + env.get(name));
}
// 获取指定环境变量的值
System.out.println(System.getenv("JAVA_HOME"));
// 获取所有系统属性
Properties props = System.getProperties();
// 将所有的系统属性保存到 prop.txt文件中
props.store(new FileOutputStream("props.txt"), "System Properties");
// 输出特定的系统属性
System.out.println(System.getProperty("os.name"));
}
}
// 例子:
public class identityHashCodeTest{
public static void main(String[] args){
// 下面程序中 s1 和 s2 是两个不同的对象
String s1 = new String("Hello");
String s2 = new String("Hello");
// String 重写了 hashCode()方法---改为根据字符串序列计算hashCode值
// 因为 s1 和 s2 的字符序列相同, 所以他们的hashCode()方法返回值相同
System.out.println(s1.hashCode() + "----" + s2.hashCode());
// s1 和 s2 是不同的字符串对象, 所以他们的 identityHashCode 值不同
System.out.println(System.identityHashCode(s1) + "---"
+ System.identityHashCode(s2));
String s3 = "java";
String s4 = "java";
// s3 和 s4 是相同的字符串对象, 所以他们的 identityHashCode值相同
System.out.println(System.identityHashCode(s3) + "---"
+ System.identityHashCode(s4));
}
}
2.2 Runtime 类
- runtime类说明
- Runtime类代表了Java程序的运行时环境, 每个Java程序都有一个与之对应的Runtime实例, 应用程序通过该对象与其运行时环境相连, 应用程序不能创建自己的Runtime实例,但可通过 getRuntime()方法获取与之关联的 Runtime 对象
- Runtime 类 也提供 gc() 方法进行垃圾回收, runFinalization() 方法进行资源清理; 并提供了load(String filename) 和 loadLibrary(String libname) 方法来加载文件和动态连接库
- Runtime 类代表了Java程序的运行时环境, 可以访问JVM的相关信息(例子1)
- Runtime 提供了一系列 exex()方法来运行操作系统命令(例子2)
示例代码
// 例子1:
// RuntimeTest.java
// 获取JVM运行时环境
public class RuntimeTest{
public static void main(String[] args) {
// 获取Java程序关联的运行时对象
Runtime rt = Runtime.getRuntime();
System.out.println("处理器数量: " + rt.availableProcessors());
System.out.println("空闲内存数: " + rt.freeMemory());
System.out.println("总内存数: " + rt.totalMemory());
System.out.println("可用最大内存数: " + rt.maxMemory());
}
}
// 例子2:
// ExecTest.java
// 通过Java程序调用Runtime类的 getRuntime方法获取关联的Runtime对象, 调用 exec()方法运行记事本
public class ExecTest{
public static void main(String[] args) throws Exception{
Runtime rt = Runtime.getRuntime();
// 运行记事本程序
rt.exec("notepad.exe");
}
}
3. 常用类
3.1 Object类
Object 类是所有类, 数组, 枚举类(继承Enum类, Enum类又继承Object类)的父类, 即Java允许把任何类型的对象赋给 Object类型的变量; 所以任何Java对象都可以调用 Object类的方法
Object类的常用方法
-
boolean equals(Object obj)
说明: 判断指定对象与该对象是否相等;(此处的相等标准是: 两个对象是同一个对象) -
protected void finalize()
说明: 当系统中没有引用变量引用到该对象时, 垃圾回收器调用此方法来清理对象的资源 -
Class<?> getClass()
说明: 返回该对象的运行时类 -
int hashCode()
说明: 返回该对象的hashCode值, 在默认情况下, Object类的hashCode()方法根据该对象的地址计算(即与System.identityHashCode(Object x)方法计算的结果相同),但很多类重写了hashCode方法 -
String toString()
说明: 这个方法前一章学过了, toString()方法返回该对象的字符串表示 -
wait() notify() notifyAll()
说明: 这几个方法可以控制线程的暂停和运行
3.2 Java7 新增的 Objects类
Objects类是一个工具类, 它提供了一些工具方法来操作对象, 这些工具方法大多数"空指针"安全的(例子1)
示例代码
// 例子1:
public class ObjectsTest{
// 定义一个ojb变量, 它的默认值是null
Static ObjectsTest obj;
public static void main(String[] args){
// 输出一个null对象的hashCode值, 输出0
System.out.println(Objects.hashCode(obj));
// 输出一个null对象的toString, 输出 null
System.out.println(Objects.toString(obj));
// 要求 obj 不能为 null, 如果obj为null则引发异常
System.out.println(Objects.requireNonNull(obj));
}
}
// 程序说明:Objects提供的requireNonNull()方法, 当传入的参数不为null时, 该方法返回参数本身; 否则将会引
// 发 NullPointerException 异常, 该方法主要用来对方法形参进行输入校验, 如例子2
//
//
// 例子2:
public Foo(Bar bar){
// 校验 bar 参数, 如果 bar 参数为null将会引发异常, 否则this.bar被赋值为bar参数
this.bar = Objects.requireNonNull(bar);
}
3.3 String, StringBuffer 和 StringBuilder 类
String 类
-
String 类是不可变类, 即一旦一个String对象被创建以后, 包含在这个对象中的字符序列是不可改变的, 直
至这个对象被销毁 -
String()
说明: 创建一个包含0个字符串序列的String对象(并不是返回null) -
String(byte[] bytes, Charset charset)
说明: 使用指定的字符集将指定的byte[]数组解码成一个新的String对象 -
String(byte[] bytes, int offset, int length)
说明: 使用平台的默认字符集将指定的 byte[] 数组从 offset开始, 长度为length的子数组解码成一个新的String对象 -
String(byte[] bytes, int offset, String charsetName)
说明: 使用指定的字符集将指定的byte[] 数组从 offset 开始, 长度为length 的子数组解码成一个新的的String对象 -
String(byte[] bytes, String charsetName)
说明: 使用指定的字符集将指定的byte[]数组解码成一个新的String对象 -
String(char[] value, int offset, int count)
说明: 将指定的字符数字从offset开始, 长度为count的字符元素连缀成字符串 -
String(String original)
说明: 根据字符串直接量来创建一个String对象, 也就是说, 新创建的String对象是该参数字符串的副本 -
String(StringBuffer buffer)
说明: 根据StringBuffer对象来创建对应的String对象 -
String(StringBuilder builder)
说明: 根据StringBuilder 对象里创建对应的String对象
String类操作字符串对象的方法
-
char charAt(int index)
说明: 获取字符串中指定位置的字符, 其中index指的是字符串的序数(序数从0开始到length()-1) -
int compareTo(String anotherString)
说明: 比较两个字符串的大小, 如果两个字符串的字符序列相等, 则返回0; 不相等时, 从两个字符串第0个字符开始比较, 返回第一个不相等的字符差; 另一种情况, 较长字符串的前面部分恰巧是较短的字符串,则返回他们的长度差 -
String concat(String str)
说明: 将该String对象与str连接一起, 与Java提供的字符串连接运算符"+"的功能相同 -
boolean contentEquals(StringNuffer sb)
说明: 将该String对象与Stringbuffer 对象sb进行比较, 当它们包含的字符序列相同时返回true -
等等等等 记住书上P250-P251页的内容
StringBuffer 类
- StringBuffer 对象则代表一个字符序列可变的字符串, 当一个StringBuffer被创建以后,通过StringBuffer提供的 append(), insert(), reverse(), setCharAt(), setLength()等方法可以改变这个字符串对象的字符序列,
- 一旦通过StringBuffer生成了最终想要的字符串, 就可以调用它的toString()方法将其转换为一个String类型的对象
StringBuilder 类
- StringBuilder类也代表字符串对象, 构造器及方法和StringBuffer类似, 区别是: StringBuffer是线程安全的, 而StringBuilder 则没有实现线程安全功能, 所以性能略高
- 通常情况下, 如果需要创建一个内容可变的字符串对象, 则应该优先考虑使用StringBuilder类
- String, StringBuffer, StringBuilder 都实现了 CharSequence接口, 因此CharSequence可认为是一个字符串的协议接口
- StringBuilder, StringBuffer 有两个属性: length和capacity, 其中length属性表示其包含的字符序列的长度, 与String对象的length不同的是, Stringbuffer, StringBuilder 的length是可以改变的, 可以通过 length(), setLength(int len)方法来访问和修改其字符串序列的长度; capacity属性表示StringBuilder 的容量, capacity 通过比length 大, 了解了解把
示例代码
// 例子:
// StringBuilderTest.java
public class StringBuilderTest {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
// 追加字符串
sb.append("java"); // sb = "java"
System.out.println(sb);
// 插入
sb.insert(0, "hello "); // sb = "hello java"
System.out.println(sb);
// 替换
sb.replace(5, 6, ","); // sb = "hello,java"
System.out.println(sb);
// 删除
sb.delete(5, 6); // sb = "hellojava"
System.out.println(sb);
// 反转
sb.reverse(); // sb = "avajolleh"
// 再反转回来
sb.reverse();
System.out.println(sb);
System.out.println(sb.length()); // 输出9
System.out.println(sb.capacity()); // 输出16
// 改变StringBuilder的长度, 将只保留前面部分
sb.setLength(5);
System.out.println(sb);
}
}
3.4 Math 类
- 通过例子来了解Math提供的各种方法
- Java提供了Math工具类来完成这些复杂的运算, Math类是一个工具类, 他的构造器是private访问权限, 因此无法创建Math类的对象,Math类的所有方法都是类方法, 可以直接通过类名(Math)来调用他们
- Math类还有两个类变量: PI和E 他们的值等于π和e
示例代码
// 例子:
// MathTest.java
public class MathTest{
public static void main(String[] args) {
/*--------下面是三角运算------*/
// 将弧度转换为角度
System.out.println("Math.toDegrees(1.57): " + Math.toDegrees(1.57));
// 将角度转换为弧度
System.out.println("Math.toRadians(90): " + Math.toRadians(90));
// 计算反余弦, 返回的角度范围在0.0 到 pi 之间
System.out.println("Math.acos(1.2): " + Math.acos(1.2));
// 计算反正弦, 返回的角度范围在 -pi/2 到 pi/2 之间
System.out.println("Math.asin(0.8): " + Math.asin(0.8));
// 计算反正切, 返回的角度范围在 -pi/2 到 pi/2 之间
System.out.println("Math.atan(2.3): " + Math.atan(2.3));
// 计算三角余弦
System.out.println("Math.cos(1.57): " + Math.cos(1.57));
// 计算双曲余弦
System.out.println("Math.cosh(1.2): " + Math.cosh(1.2));
// 计算正弦
System.out.println("Math.sin(1.2): " + Math.sin(1.2));
// 计算双曲正弦
System.out.println("Math.sinh(0.8): " + Math.sinh(0.8));
// 计算三角正切
System.out.println("Math.tan(0.8): " + Math.tan(0.8));
// 计算双曲正切
System.out.println("Math.tanh(2.1): " + Math.tanh(2.1));
// 将矩形坐标(x, y)转换成极坐标(r, thet)
System.out.println("Math.atan2(0.1, 0.2): " + Math.atan2(0.1, 0.2));
//
/*--------下面是取整运算------*/
// 取整, 返回小于目标数的最大整数
System.out.println("Math.floor(1.2): " + Math.floor(1.2));
// 取整, 返回大于目标数的最小整数
System.out.println("Math.ceil(1.2): " + Math.ceil(1.2));
// 四舍五入取整
System.out.println("Math.round(2.3): " + Math.round(2.3));
//
/*--------下面是乘方, 开方,指数运算------*/
// 计算平方根
System.out.println("Math.sqrt(2.3): " + Math.sqrt(2.3));
// 计算立方根
System.out.println("Math.cbrt(9): " + Math.cbrt(9));
// 返回欧拉数 e 的 n 次幂
System.out.println("Math.exp(2): " + Math.exp(2));
// 返回sqrt(x2 + y2), 没有中间溢出或下溢
System.out.println("Math.hypot(4, 4): " + Math.hypot(4, 4));
// 按照IEEE 754标准的规定, 对两个参数进行余数运算
System.out.println("Math.IEEEremainder(5, 2): " + Math.IEEEremainder(5, 2));
// 计算乘方
System.out.println("Math.pow(3, 2): " + Math.pow(3, 2));
// 计算自然对数
System.out.println("Math.log(12): " + Math.log(12));
// 计算底数为10的对数
System.out.println("Math.log10(12): " + Math.log10(12));
// 返回参数与1之和的自然对数
System.out.println("Math.log1p(12): " + Math.log1p(12));
//
/*--------下面是符号相关的运算------*/
// 计算绝对值
System.out.println("Math.abs(-4.5): " + Math.abs(-4.5));
// 符号赋值, 返回带有第二个浮点数符号的第一个浮点参数
System.out.println("Math.copySign(1.2, -1.0): " + Math.copySign(1.2, -1.0));
// 符号函数, 如果参数为0, 则返回0, 如果参数大于0
// 则返回1.0; 如果参数小数0, 则返回-1.0
System.out.println("Math.signum(2.3): " + Math.signum(2.3));
//
/*--------下面是大小相关的运算------*/
// 找出最大值
System.out.println("Math.max(2.3, 4.5): "+ Math.max(2.3, 4.5));
// 计算最小值
System.out.println("Math.min(2.3, 4.5): "+ Math.min(2.3, 4.5));
// 返回第一个参数和第二个参数之间与第一个参数相邻的浮点数
System.out.println("Math.nextAfter(1.2, 1.0): "+ Math.nextAfter(1.2, 1.0));
// 返回比目标数略大的浮点数
System.out.println("Math.nextUp(1.2): " + Math.nextUp(1.2));
// 返回一个伪随机数, 该值大于等于0.0 且小于 1.0
System.out.println("Math.random(): " + Math.random());
System.out.println("Math.PI : " + Math.PI);
System.out.println("Math.E : " + Math.E);
}
}
3.5 Java7 的 ThreadLocalRandom 和 Random
- Random类专门用于生成一个伪随机数, 他有两个构造器: 一个构造器使用默认的种子(以当前时间作为种子), 另一个构造器需要程序员显式传入一个long型整数的种子
- ThreadLocalRandom 是Java7新增的, 是Random的增强版; 在并发访问的环境下, 使用ThreadLocalRandom来代替Random可以减少多线程资源的竞争, 最终保证系统具有更好的线程安全性
- ThreadLocalRandom 类用法类似与Random, 提供一个静态的 current()方法来获取ThreadLocalRandom对象, 获取该对象之后即可调用各种nextXxx()方法来获取伪随机数
- Random产生的数字并不是真正随机的, 而是一种伪随机, 可能产生两个Random对象产生相同的数字序列, 通常通过使用当前时间作为Random对象的种子, 如:Random rand = new Random(System.currentTimeMillis());
- ThreadLocalRandom 与 Random 都比Math类提供的Random()方法提供更多的方式来生成各种伪随机数, 可以生成浮点数类型的伪随机数, 也可以生成整数类型的伪随机数, 还可以指定生成随机数的范围(例子2)
示例代码
// 例子1:
// 生成伪随机数的demo
// RandomTest.java
import java.util.Arrays;
import java.util.Random;
//
public class RandomTest {
public static void main(String[] args) {
Random rand = new Random();
System.out.println("rand.nextBoolean(): " + rand.nextBoolean());
byte[] buffer = new byte[16];
rand.nextBytes(buffer);
System.out.println(Arrays.toString(buffer));
// 生成 0.0~1.0之间的伪随机double数
System.out.println("rand.nextDouble(): " + rand.nextDouble());
// 生成 0.0~1.0之间的伪随机float数
System.out.println("rand.nextFloat(): " + rand.nextFloat());
// 生成平均值是0.0, 标准差是1.0的伪高斯数
System.out.println("rand.nextGaussian(): " + rand.nextGaussian());
// 生成一个处于int整形取值范围的伪随机数
System.out.println("rand.nextInt(): " + rand.nextInt());
// 生成一个0~26之间的伪随机整数
System.out.println("rand.nextInt(26): " + rand.nextInt(26));
// 生成一个处于long整数取值范围的伪随机整数
System.out.println("rand.nextLong(): " + rand.nextLong());
}
}
// 例子2:
// ThreadLocalRandom 生成伪随机的用法
ThreadLocalRandom rand = ThreadLocalRandom.current();
// 生成一个4-20之间的伪随机整数
int val1 = tlr.nextInt(5, 16);
System.out.println(val1);
// 生成一个2.0-10.0之间的伪随机浮点数
double val2 = tlr.nextDouble(5.0, 16.0);
System.out.println(val2);
3.6 BigDecimal 类
- float, double两种基本浮点数容易引起精度丢失, 尤其在进行算术运算时更容易发生(例子1)
- BigDecimal 类提供了大量构造器用于创建BigDecimal对象, 包括把所有的基本数值型变量转换成一个BigDecimal对象, 也包括利用数字字符串, 数字字符数组来创建BigDecimal对象
- BigDecimal 类不推荐使用BigDecimal(double val);因为使用该构造器时有一定的不可预知性
- 使用 BigDecimal(String val) 构造器的结果是可预知的, 写入一个 new BigDecimal("0.1")将创建一个BigDecimal, 它正好等于预期的 0.1; 所以优先使用基于String的构造器
- 如果必须使用double浮点数作为BigDecimal构造器的参数, 不要直接将该double浮点数作为构造器的参数来创建BigDecimal对象, 而是通过 BigDecimal.valueOf(double value)静态方法来创建BigDecimal对象
- BigDecimal类提供了add(), subtract(), multiply(), pow()等方法对精确浮点数进行常规算术运算(例2)
- 如果程序中要求对double浮点数进行加, 减, 乘, 除基本运算, 则需要先将double类型的数值包装成BigDecimal 对象, 调用 BigDecimal 对象的方法执行算数运算后再将结果转换成double型变量, (如例子3, 以 BigDecimal 为基础定义一个 Arith 工具类,)
示例代码
// 例子1:
// DoubleTest.java
// 普通的double类型的算术运算容易造成精度丢失
public class DoubleTest{
public static void main(String[] args){
System.out.println("0.05 + 0.01 = " + (0.05 + 0.01));
System.out.println("1.0 - 0.42 = " + (1.0 - 0.42));
System.out.println("4.015 * 100 = " + (4.015 * 100));
System.out.println("123.3 / 100 = " + (123.3 / 100));
}
}
// 例子2:
// BigDecimalTest.java
import java.math.BigDecimal;
public class BigDecimalTest {
public static void main(String[] args) {
BigDecimal f1 = new BigDecimal("0.05");
BigDecimal f2 = BigDecimal.valueOf(0.01);
BigDecimal f3 = new BigDecimal(0.05);
// 计算结果可预期
System.out.println("使用String作为BigDecimal构造器参数:");
System.out.println("0.05 + 0.01 = " + f1.add(f2));
System.out.println("0.05 - 0.01 = " + f1.subtract(f2));
System.out.println("0.05 * 0.01 = " + f1.multiply(f2));
System.out.println("0.05 / 0.01 = " + f1.divide(f2));
// 计算结果不可预期
System.out.println("使用double作为BigDecimal构造器参数:");
System.out.println("0.05 + 0.01 = " + f3.add(f2));
System.out.println("0.05 - 0.01 = " + f3.subtract(f2));
System.out.println("0.05 * 0.01 = " + f3.multiply(f2));
System.out.println("0.05 / 0.01 = " + f3.divide(f2));
}
}
// 输出:
// 使用String作为BigDecimal构造器参数:
// 0.05 + 0.01 = 0.06
// 0.05 - 0.01 = 0.04
// 0.05 * 0.01 = 0.0005
// 0.05 / 0.01 = 5
// 使用double作为BigDecimal构造器参数:
// 0.05 + 0.01 = 0.06000000000000000277555756156289135105907917022705078125
// 0.05 - 0.01 = 0.04000000000000000277555756156289135105907917022705078125
// 0.05 * 0.01 = 0.0005000000000000000277555756156289135105907917022705078125
// 0.05 / 0.01 = 5.000000000000000277555756156289135105907917022705078125
// 说明: 从运行结果看出BigDecimal进行算数运算时, 一定要使用String对象作为构造器的参数, 而不是直接使用
// double类型的数字
// 例子3:
// Arith.java
// 以 BigDecimal 为基础定义一个 Arith 工具类
import java.math.BigDecimal;
public class Arith{
// 默认的除法运算精度
private static final int DEF_DIV_SCALE = 10;
// 构造器私有化, 让这个类不能实例化
private Arith(){}
// 提供精确的加法运算
public static double add(double v1, double v2){
BigDecimal b1 = BigDecimal.valueOf(v1);
BigDecimal b2 = BigDecimal.valueOf(v2);
return b1.add(b2).doubleValue();
}
// 提供精确的减法运算
public static double sub(double v1, double v2){
BigDecimal b1 = BigDecimal.valueOf(v1);
BigDecimal b2 = BigDecimal.valueOf(v2);
return b1.subtract(b2).doubleValue();
}
// 提供精确的乘法运算
public static double mul(double v1, double v2){
BigDecimal b1 = BigDecimal.valueOf(v1);
BigDecimal b2 = BigDecimal.valueOf(v2);
return b1.multiply(b2).doubleValue();
}
// 提供相对精确的除法运算, 当发生除不尽的情况时, 精确到小数点以后10位的数字四舍五入
public static double div(double v1, double v2){
BigDecimal b1 = BigDecimal.valueOf(v1);
BigDecimal b2 = BigDecimal.valueOf(v2);
return b1.divide(b2, DEF_DIV_SCALE, BigDecimal.ROUND_HALF_UP).doubleValue();
}
public static void main(String[] args) {
System.out.println("0.05 + 0.01 = " + Arith.add(0.05, 0.01));
System.out.println("1.0 - 0.42 = " + Arith.sub(1.0, 0.42));
System.out.println("4.015 * 100 = " + Arith.mul(4.015, 100));
System.out.println("123.3 / 100 = " + Arith.div(123.3, 100));
System.out.println("123.3 / 99 = " + Arith.div(123.3, 99));
}
}
4. Java 8 的日期, 时间类
4.1 Date 类(了解, Java官网都不推荐使用)
Date类的大部分构造器, 方法都已经过时, 了解剩下的能用的两个
-
剩下的两个可以用的构造器
- Date()
说明: 生成一个代表当前日期时间的Date对象, 该构造器在底层调用System.cunnentTimeMillis()获得 long 整数作为日期参数 - Date(long date)
说明: 根据指定的long型整数来生成一个Date对象; 该构造器的参数表示创建的Date对象和 GMT 1970年1月1日00:00:00之间的时间差, 以毫秒作为计时单位
- Date()
-
Date对象的方法
- Boolean after(Date when)
说明: 测试该日期是否在指定日期when之后 - boolean before(Date when)
说明: 测试该日期是否在指定日期when之前 - long getTime()
说明: 返回long型整数, 即从 GMT 1970年1月1日00:00:00之间的时间差, 以毫秒作为计时单位 - void setTime(long time)
说明: 设置该Date对象的时间
- Boolean after(Date when)
4.2 Calendar 类
- Calendar 类是一个抽象类, 更好地处理日期和时间
- 因为是一个抽象类, 所以不能使用构造器来创建 Calendar 对象, 但是可通过 getInstance()方法来获取 Calendar 对象,
- Calendar 与 Date 都是表示日期的工具类, 他们之间可以自由转换
Calendar 类常用方法
- void add(int field, int amount)
说明: 根据日历的规则, 为给定的日历字段添加或减去指定的时间量 - int get(int field)
说明: 返回指定日历字段的值 - int getActualMaximum(int field)
说明: 返回指定日历字段可能拥有的最大值, 月最大值为11 - int getActualMinimum(int field)
说明: 返回指定日历字段可能拥有的最小值, 月最小值为0 - void roll(int field, int amount)
说明: 与 add()方法类似, 区别在于加上amount后超过了该字段所能表示的最大范围时, 也不会向上一个字段进位 - void set(int field, int value)
说明: 将给定的日历字段设置为给定值 - void set(int year, int month, int date)
说明: 设置 Calendar 对象的年, 月, 日三个字段值 - void set(int year, int month, int date, int hourOfDay, int minute, int second)
说明: 设置 Calendar 对象的年, 月, 日, 时, 分, 秒6个字段值
- 注意:
- 上面的很多方法都需要一个int类型的field参数, field是Calendar类的类变量,如Calendar.YEAR Calendar.MONTH 等分别代表了年月日小时分钟秒等时间字段
- Calendar.MONTH 的字段是从0开始的
示例代码
// 例子1:
public calss CalendarTest{
public static void main(String[] args){
Calendar c = Calendar.getInstance();
// 取出年
System.out.println(c.get(YEAR));
// 取出月份
System.out.println(c.get(MONTH));
// 取出日
System.out.println(c.get(DATE));
// 分别设置年, 月, 日, 时, 分, 秒
c.set(2020, 09, 07, 20, 00, 00);
System.out.println(c.getTime());
// 将Calendar 的年前推一年
c.add(YEAR, -1);
System.out.println(c.getTime());
// 将Calendar的月份前推8个月
c.roll(MONTH, -8);
System.out.println(c.getTime());
}
}
add() 和 roll() 方法的区别
- add(int field, int amount)的功能非常强大, add 主要的用于改变 Calendar的特定字段的值, 如果需要增加某字段值, 则让amount为正数, 如果需要减少某字段的值, 则让amount为附负数即可
- 当被修改的字段超出允许的范围时, 会发生进位, 即上一级字段也会增大(例子1)
- 如果下一级字段也需要改变, 那么该字段会修正到变化最小的值(例子2)
- roll()的规则与add()的处理规则不同: 当被修改的字段超出它允许的范围时, 上一级字段不会增大(例子3)
- 下一级字段的处理规则与add()相似(例子4)
示例代码
//例子1:
Calendar cal1 = Calendar.getInstance();
cal1.set(2003, 7, 23, 0, 0, 0); // 2003-8-23
cal1.add(MONTH, 6); // 2003-2-23
// 例子2:
Calendar cal2 = Calendar.getInstance();
cal2.set(2003, 7, 31, 0, 0, 0); // 2003-8-31
// 因为进位后月份改为2月, 2月没有31日, 自动变成29日
cal2.add(MONTH, 6); // 2003-8-21 => 2004-2-29
// 例子3:
Calendar cal3 = Calendar.getInstance();
cal3.set(2003, 7, 23, 0, 0, 0); // 2003-8-23
// MONTH 字段 "进位", 但YEAR字段并没有增加
cal3.roll(MONTH, 6); // 2003-8-23 => 2003-2-23
// 例子4:
Calendar cal4 = Calendar.getInstance();
cal4.set(2003, 7, 31, 0, 0, 0); // 2003-8-31
// MONTH 字段 "进位"后变成2, 2月没有31日
// YEAR 字段不会改变, 2003年的2月份只有28天
cal4.roll(MONTH, 6); // 2003-8-31 => 2003-2-28
设置 Calendar 的容错性
- 因为 Calendar 对象的 set() 方法来改变指定时间字段的值时, 有可能传入一个不合法的参数, 所以需要通过容错性来指定是否检查输入的值符合规定
- Calendar 通过setLenient()方法来设置它的容错性, Calendar 默认支持较好的容错性, 可通过setLenient(false) 关闭 Calendar 的容错性, 让它进行更严格的参数检查
- Calendar 由两种解释日历字段的模式: lenient 模式和 non_lenient 模式:lenient 模式时每个时间字段可接受超出它允许范围的值;non_lenient 模式时如果为某个时间字段设置的值超出程序允许范围时, 程序将抛出异常
示例代码
// 例子:
public class LenientTest{
public static void main(String[] args){
Calendar cal = Calendar.getInstance();
// 结果是 YEAR 字段加1, MONTH字段为1(2月)
cal.set(MONTH, 13);
System.out.println(cal.getTime());
// 关闭容错性
cal.setLenient(false);
// 导致运行时异常, 因为关闭容错性, 执行更严格的时间参数检查
cal.set(MONTH, 13);
System.out.println(cal.getTime());
}
}
set()方法的延迟修改:
- 含义: set(f, value)方法将日历字段f更改为value, 此外他还设置了一个内部成员变量, 以指示日历字段f已经被更改; 尽管日历字段f是立即更改的, 但该Calendar所代表的时间却不会立即修改直到下次调用get(), getTime(), getTimeMillis(), add()或roll()时才会重新计算日历时间,这被称之为 set()方法的延迟修改 即: 调用 set(f, value) 方法后不会立即修改, 直到调用获取时间的方法时才修改
- 优势: 延迟修改的优势是多次调用set()不会触发多次不必要的计算(需要计算出一个代表实际时间的long型整数)
示例代码
// 例子:
ublic class LazyTest{
public static void main(String[] args){
Calendar cal = Calendar.getInstance();
cal.set(2003, 7, 31); // 2003-8-31
// 将月份设置为9, 但9月31不存在
// 如果立即修改, 系统将会把cal自动调整为10月1日
cal.set(MONTH, 8);
// 下面的代码输出10月1日
System.out.prntln(cal.getTime()); // ①
// 设置 DATE 字段为 5
cal.set(DATE, 5); // ②
System.out.prntln(cal.getTime()); // ③
}
}
// 程序说明:
// 1. 上面程序中创建了代表2003-8-31的Calendar对象, 当把这个对象的MONTH字段加1后得到
// 2003-10-1(因为9月没有31日), 如果程序在①处代码输出当前Calendar里的日期, 也会看到
// 输出的是2003-10-1, ③处的代码将输出2003-10-5
// 2. 如果将①处的代码注释起来, 因为Calendar的set()方法具有延迟修改的特性, 即调用set()方
// 法后Calendar实际上并未计算真实的日期, 他只是使用内部成员变量表记录MONTH字段被修改
// 为8, 接着程序设置DATE字段的值为5, 程序内部再次记录DATE字段为5---也就是9月5日, 因
// 次这是的③处将输出 2003-9-5
Java8新增的日期, 时间java.time包类及方法
-
Clock
说明: 该类用于获取指定时区的当前日期, 时间; 可代替 System类的 currentTimeMillis()方法, 而且提供了更多的方法来获取当前日期, 时间, 该类提供了大量的静态方法来获取Clock对象 -
Duration
说明: 该类代表持续时间, 可以很方便的获取一段时间 -
Instant
说明: 代表一个具体的时刻, 可以精确到纳秒. 该类提供 now() 方法用来获取当前时刻; 也提供了静态的 now(Clock clock) 方法来获取 clock 对应的时刻; 还提供了 minusXxx()方法在当前时刻的基础上减去一段时间; 也提供了 plusXxx()方法在当前时刻的基础上加上一段时间 -
LocalDate
说明: 该类代表不带时区的日期:如2019-10-01; 提供静态 now() 方法获取当前日期; 提供静态的now(Clock clock) 方法来获取clock对应的日期; 提供 minusXxx()方法在当前年份基础上减去几年几月几周或几日; 提供 plusXxx() 方法在当前年份的基础是加上几年几月几周或几日 -
LocalTime
说明: 该类代表了不带时区的时间:如 10:15:30; 提供静态 now() 方法获取当前时间; 提供静态的now(Clock clock) 方法来获取clock对应的时间; 提供 minusXxx() 方法在当前年份基础上减去几小时,几分,几秒; 提供 plusXxx() 方法在当前年份基础上加上及小时, 几分, 几秒 -
LocalDateTime
说明: 该类代表不带时区的日期, 时间, 如 2017-12-03T10:15:33; 也提供了 now(), now(Clock clock), minusXxx(), plusXxx() 等方法 -
MonthDay
说明: 该类代表月日, 如04-12; 提供now()方法获取当前月日, 也提供静态的now(Clock clock)方法来获取 clock 对应的月日 -
Year
说明: 该类仅代表年. 如2014; 提供 now(), now(Clock clock), minusXxx(), plusXxx() 等方法 -
YearMonth
说明: 该类仅代表年月, 如2014-08; 提供 now(), now(Clock clock), minusXxx(), plusXxx() 等方法 -
ZonedDateTime
说明: 该类代表一个时区化的日期, 时间 -
Zoneld
说明: 该类代表一个时区 -
DayOfWeek
说明: 这是一个枚举类, 顶一颗周日到周六的枚举值 -
Month
说明: 这也是一个枚举类, 定义了一月到十二月的枚举值
示例代码
// 例子:
// NewDatePackageTest.java
import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Month;
import java.time.MonthDay;
import java.time.Year;
import java.time.YearMonth;
public class NewDatePackageTest {
public static void main(String[] args) {
System.out.println("----下面是关于Clock的用法----");
// ----下面是关于Clock的用法----
// 获取当前Clock
Clock clock = Clock.systemUTC();
// 通过 Clock 获取当前时刻
System.out.println("当前时刻为: " + clock.instant());
// 获取 clock 对应的毫秒数, 与 System.currentTimeMillis()输出相同
System.out.println(clock.millis());
System.out.println(System.currentTimeMillis());
//
System.out.println("----下面是关于Duration的用法----");
// ----下面是关于Duration的用法----
Duration d = Duration.ofSeconds(6000);
System.out.println("6000秒相当于 " + d.toMinutes() + " 分钟");
System.out.println("6000秒相当于 " + d.toHours() + " 小时");
System.out.println("6000秒相当于 " + d.toDays() + " 天");
// 在 clock 基础上增加 6000 秒, 返回新的 Clock
Clock clock2 = Clock.offset(clock, d);
// 可以看到clock2和clock相差1小时40分
System.out.println("当前时刻加6000秒为: " + clock2.instant());
//
System.out.println("----下面是关于Instant的用法----");
// ----下面是关于Instant的用法----
// 获取当前时间
Instant instant = Instant.now();
System.out.println(instant);
// instant 添加6000秒(100分钟), 返回新的Instant
Instant instant2 = instant.plusSeconds(6000);
System.out.println(instant2);
// 根据字符串解析Instant对象
Instant instant3 = Instant.parse("2014-02-23T10:12:35.342Z");
System.out.println(instant3);
// 在instant3的基础上添加5小时4分钟
Instant instant4 = instant3.plus(Duration.ofHours(5).plusMinutes(4));
System.out.println(instant4);
// 获取 instant4 的5天以前的时刻
Instant instant5 = instant4.minus(Duration.ofDays(5));
System.out.println(instant5);
//
System.out.println("---下面是关于LocalDate的用法----");
// ----下面是关于LocalDate的用法----
LocalDate localDate = LocalDate.now();
System.out.println(localDate);
// 获取2014年的第146天
localDate = LocalDate.ofYearDay(2014, 146);
System.out.println(localDate); // 2014-05-26
// 设置为 2014年5月21日, 月份调用MONTH的枚举实例
localDate = LocalDate.of(2014, Month.MAY, 21);
System.out.println(localDate); // 2014-05-21
//
System.out.println("----下面是关于LocalTime的用法----");
// ----下面是关于LocalTime的用法----
// 获取当前时间
LocalTime localTime = LocalTime.now();
// 设置时间为 22点33分
localTime = LocalTime.of(22, 33);
System.out.println(localTime); // 22:33
// 返回一天中的9070秒
localTime = LocalTime.ofSecondOfDay(9070);
System.out.println("一天中的9070秒是: " + localTime);
//
System.out.println("-----下面是LocalDateTime的用法----");
// ----下面是LocalDateTime的用法----
// 获取当前的日期时间
LocalDateTime localDateTime = LocalDateTime.now();
// 当前的日期, 时间加上25小时3分钟
LocalDateTime future = localDateTime.plusHours(25).plusMinutes(3);
System.out.println("当前的日期,时间的25小时3分钟之后是: " + future);
//
System.out.println("----下面是关于Year, YearMonth, MonthDay的用法----");
// ----下面是关于Year, YearMonth, MonthDay的用法----
// 获取当前的年份
Year year = Year.now();
System.out.println("当前年份是: " + year);
// 当前的年份再加5年
year = year.plusYears(5);
System.out.println("当前年份再过5年是: " + year);
// 根据指定月份获取YearMonth
YearMonth ym = year.atMonth(10);
System.out.println("year年的10月: " + ym);
// 当前的年份再加5年, 减去3个月
ym = ym.plusYears(5).minusMonths(3);
System.out.println("year年10月再加5年,减去3个月是: " + ym);
MonthDay md = MonthDay.now();
System.out.println("当前月日: " + md);
// 设置为5月23日
MonthDay md2 = md.with(Month.MAY).withDayOfMonth(23);
System.out.println("5月23日为: " + md2);
}
}
5. 正则表达式
String 类中正则的几个方法
-
boolean matches(String regex)
说明: 判断该字符串是否匹配指定的正则表达式 -
String replaceAll(String regex, String replacement)
说明: 将该字符串中所有匹配 regex 的字串替换成 replacement -
String replaceFirst(String regex, String replacement)
说明: 将该字符串中第一个匹配 regex 的字串替换成 replacement -
String[] split(String regex)
说明: 以regex作为分隔符, 把该字符串分割成多个字串
创建正则表达式
正则表达式支持的合法字符
字符 | 解释 |
---|---|
x | 字符x(x可以是任何合法的字符) |
\0mnn | 八进制数0mnn所表示的字符 |
\xhh | 十六进制 0xhh 所表示的字符 |
\uhhh | 十六进制 0xhhh 所表示的 Unicode 字符 |
\t | 制表符("\u0009") |
\n | 换行(新行)符 ("\u000A") |
\r | 回车符 ("\u000D") |
\f | 换页符 ("\u000C") |
\a | 报警(bell)符 ("\u0007") |
\e | Escape符 ("\u001B") |
正则表达式中的特殊字符
字符 | 解释 |
---|---|
$ | 匹配一行的行尾, 要匹配 $ 字符本身, 使用 $ |
^ | 匹配一行的开头. 要匹配 ^ 字符本身, 使用 ^ |
() | 标记自表达式的开始和结束位置, 要匹配这些字符, 使用 \( 和 \) |
[] | 用于确定中括号表达式的开始和结束位置, 要匹配字符本身, 使用 \[ 和 \] |
{} | 用于标记前面子表达式出现的频度, 要匹配字符本身, 使用 \{和 \} |
\* | 指定前面的子表达式可以出现0次或多次, 要匹配字符本身, 使用 \\ |
+ | 指定前面的自表达式可以出现1次或多次, 要匹配+字符本身, 使用 \+ |
? | 指定前面的自表达式可以出现0次或1次, 要匹配?字符本身, 使用 ? |
. | 匹配除换行符("\n")之外的任何单个字符, 要匹配 . 本身, 使用 \\. |
\ | 用于转义下一个字符, 或指定八进制, 十六进制字符, 要匹配 \ 本身. 使用 \\ |
| | 指定两项之间任选一项, 如果要匹配 | 本身, 使用 \| |
预定义字符
字符 | 解释 |
---|---|
. | 可以匹配任何单个字符 |
\d | 匹配 0~9 的所有数字 |
\D | 匹配非数字 |
\s | 匹配所有的空白符, 包括空格, 制表符, 回车符, 换页符, 换行符等 |
\S | 匹配所有的非空白字符 |
\w | 匹配所有的单词字符, 包括 0~9 所有数字, 26个英文字母和下划线(_) |
\W | 匹配所有的非单词字符 |
方括号表达式
方括号 | 解释 |
---|---|
枚举 | 例如[abc],表示a,b,c其中任意一个字符; [gz], 表示g, z其中任意一个字符 |
范围 ~ | [a~cx~z],表示a~c, x~z范围内的任意字符 |
求否 ^ | 例如[^abc], 表示非 a,b,c的任意字符; [^a~f],表示不是a~f范围内的任意字符 |
"与"运算 && | 例如 [a-z&&[def]], 求 a~z 和[def]的交集, 表示d, e 或 f [a-z&&[^bc]], a~z 范围内除了b和c之外的字符, 即 [ad-z] [a-z&&[^m-p]], a~z范围内除去m~p范围的所有字符 即[a-lq-z] |
"并"运算 | 并运算与前面的枚举类似, 例如[a-d[m-p]] 等价于 [a-dm-p] |
边界匹配符
边界匹配符 | 解释 |
---|---|
^ | 行的开头 |
$ | 行的结尾 |
\b | 单词的边界 |
\B | 非单词的边界 |
\A | 输入的开头 |
\G | 前一个匹配的结尾 |
\Z | 输入的行尾, 仅用于最后的结束符 |
\z | 输入的行尾 |
正则表达式数量标识符的几种模式
-
Greedy(贪婪模式):
- 数量标识符默认采用贪婪模式, 除非另有表示
- 贪婪模式的表达式会一直匹配下去, 直到无法匹配为止
-
Reluctant(勉强模式):
- 用问号后缀(?)表示, 他只会匹配最少的字符, 也称为最小匹配模式
-
possessive(占有模式):
- 占有模式目前只有Java支持
- 用加号后缀(+)表示, 通常比较少用
三种模式的数量表示符
贪婪模式 | 勉强模式 | 占有模式 | 说明 |
---|---|---|---|
X? | X?? | X?? | X表达式出现0次或1次 |
X* | X*? | X*? | X表达式出现0次或多次 |
X+ | X+? | X+? | X表达式出现1次或多次 |
X | X? | X? | X表达式出现n次 |
X{n,} | X{n,}? | X{n,}? | X表达式最少出现n次 |
X{n,m} | X{n,m}? | X{n,m}? | X表达式最少出现n次, 最多出现m次 |
使用正则表达式:
- 熟悉 Pattern 和 Matcher 类
- Pattern 对象是正则表达式编译后再内存中的表示形式, 因此正则表达式字符串必须先被编译为 Pattern对象, 然后再利用该Pattern对象创建对应的Matcher对象. 执行匹配所涉及的状态保留再Mather对象中, 多个Matcher对象可以共享他同一个Pattern对象
- pattern 类是不可变类, 可供多个并发的线程安全使用
Matcher类的几个常用方法
- find()
说明: 返回目标字符串中是否包含与Pattern匹配的字串 - group()
说明: 返回上一次与Pattern匹配的字串 - start()
说明: 返回上一次与Pattern匹配的字串在目标字符串中的开始位置 - end()
说明: 返回上一次与Pattern匹配的字串在目标字符串中的结束位置加1 - lookingAt()
说明: 返回目标字符串前面部分与Pattern是否匹配 - matches()
说明: 返回整个目标字符串与Pattern是否匹配 - reset()
说明: 将现有的 Matcher 对象应用于一个新的字符序列
示例代码
// 例子1:
// 最经典的正则表达式调用顺序
// 将一个字符串编译成 Patern 对象, 这个 Pattern 对象可以重复使用
Pattern p = Pattern.compile("a*b");
// 使用 Pattern 对象创建 Matcher 对象
Matcher m = p.matcher("aaaaaab");
boolean b = m.matches(); // out: true
// 如果不需要重复使用, 即这个正则表达式只使用一次, 可使用Pattern类的静态方法matches()
// 此方法自动把指定字符串编译v黑人女孩匿名的Pattern对象, 并执行匹配
boolean b = Pattern.matches("a*b", "aaaaab"); // out: true
// 例子2:
// FindGroup.java
// 从大段的字符串中找出电话号码
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class FindGroup{
public static void main(String[] args) {
// 使用字符串模拟从网路上得到的网页源码
String str = "我想求购一本<疯狂 Java 讲义>, 尽快联系我 12345678912"
+ "交朋友, 电话号码: 12934568715"
+ "出售二手电脑, 电话号码: 12456783324";
// 创建一个 Pattern 对象, 并用它建立一个Matcher对象
// 该正则表达式中抓取12开头的手机号码
// 可根据需求改变匹配规则
Matcher m = Pattern.compile("12\\d{9}").matcher(str);
while (m.find()){
System.out.println(m.group());
}
}
}
// 例子3:
// StartaEnd.java
// start() 和 end() 方法确定字串在目标字符串中出现的位置
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class StartEnd{
public static void main(String[] args) {
// 创建一个 Pattern 对象, 并用它建立一个 Matcher 对象
String regStr = "Java is very easy! I think Not";
System.out.println("目标字符串是: " + regStr);
Matcher m = Pattern.compile("\\w+").matcher(regStr);
while(m.find()){
System.out.println(m.group() + " 字串的起始位置: "
+ m.start() + "; 字串的结束位置: " + m.end()
+ "; 字符长度为:" + (m.end() - m.start()));
}
}
}
// 例子4:
// MatchesTest.java
// matches() 和 lookingAt() 方法有点类似, 只是 matches() 方法要求整个字符串和Pattern完全匹配
// 时才返回true, 而 lookingAt() 只要字符串以 pattern 开头就会返回 true
// reset()方法可将现有的Matcher对象应用于新的字符序列
public class MatchesTest{
public static void main(String[] args) {
String[] mails = {
"kongeni@163.com",
"jefxff@outlook.com",
"jerry@gmail.com",
"waaw@abc.xx",
"aaa@wwwwwwww.gov"
};
String mailRegEx = "\\w{2,8}@\\w{2,5}\\.(com|xx|gov)";
Pattern mailPattern = Pattern.compile(mailRegEx);
Matcher matcher = null;
for(String mail : mails){
if(matcher == null){
matcher = mailPattern.matcher(mail);
}
else{
matcher.reset(mail);
}
String result = mail + (matcher.matches() ? " 是" : " 不是")
+ "一个有效的地址!";
System.out.println(result);
}
}
}
// 例子5:
// ReplaceTest.java
// 利用正则表达式对目标字符串进行分割, 查找, 替换等操作
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ReplaceTest {
public static void main(String[] args) {
String[] msgs = {
"java has regular expressions in 1.4",
"regular expressions noe expressing in java",
"java represses oracular expressions"
};
Pattern p = Pattern.compile("re\\w*");
Matcher matcher = null;
for (int i = 0; i < msgs.length; i++){
if (matcher == null){
matcher = p.matcher(msgs[i]);
}
else{
matcher.reset(msgs[i]);
}
System.out.println(matcher.replaceAll("哈哈"));
}
}
}
// 例子6:
// StringReg.java
// String 类中提供的 replaceAll(), replaceFirst(), split() 等方法应用
import java.util.Arrays;
public class StringReg {
public static void main(String[] args) {
String[] msgs = {
"java has regular expressions in 1.4",
"regular expressions noe expressing in java",
"java represses oracular expressions"
};
for (String msg : msgs){
System.out.println(msg.replaceFirst("re\\w*", "哈哈:)"));
System.out.println(Arrays.toString(msg.split(" ")));
}
}
}
6 DateFormat 抽象类
- java.text.DateFormat 是一个抽象类,不能直接使用, 需要通过java.text.SimpleDateFormat子类来进行Date类型和String类型的互相转换
- 格式化: 通过 String format(Date date) 方法, 将 Date 对象转化为 String 对象
- 解析: 通过 Date parse(String source) 方法, 将 String 对象转换为 Date 对象
示例代码
import java.text.SimpleDateFormat;
import java.util.Date;
//
public class DateFormatTest {
public static void main(String[] args) throws Exception {
System.out.println("将Date格式转换为String格式");
// 先创建一个Date对象, 在创建一个SimpleDateFormat对象并传入日期格式, 通过 SimpleDateFormat
// 对象调用format(Date d) 方法, 进行格式化, 并返回 String 类型的对象
Date d = new Date();
// SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String s = sdf.format(d);
System.out.println(s + "\n");
//
System.out.println("将String格式转换为Date格式");
// 先有String类型的日期时间字符串, 在创建一个SimpleDateFormat对象并传入日期格式, 通过 SimpleDateFormat
// 对象调用 parse(String ss) 方法, 进行解析, 并返回 Date 类型的对象
String ss = "1991-09-07 08:08:08";
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d2 = sdf2.parse(ss);
System.out.println(d2);
}
}
7. Java8新增的日期, 时间格式
- 在java.time.format包下提供了一个DateTimeFormatter格式器类, 该类相当于前面学习的 DateFormat 和 SimpleDateFormat 的合体
- DateTimeFormatter能将日期, 时间对象格式化成字符串, 也可以将特定格式的字符串解析成日期, 时间对象
- 使用 DateTimeFormatter 进行格式化或解析之前, 必须先获取 DateTimeFormatter 对象
获取 DateTimeFormatter 对象的三种方式
- 直接使用静态常量创建 DateTimeFormatter 格式器 (DateTimeFormatter 类中包含了大量形如ISO_LOCAL_DATE, ISO_LOCAL_TIME, ISLO_LOCAL_DATE_TIME等静态常量, 这些常量本身就是 DateTimeFormatter 实例)
- 使用代表不同风格的枚举值来创建 DateTimeFormatter 格式器; 在 FormatStyle 枚举类中定义了 FULL, LONG, MEDIUM, SHORT四个枚举值, 他们代表日期, 时间的不同格式
- 根据模式字符串来创建 DateTimeFormatter 对象, 类似于 SimpleDateFormat, 可以采用模式字符串来创建DateTimeFormatter
♥使用 DateTimeFormatter 将日期, 时间格式化成字符串(两种方式)
- 调用 DateTimeFormatter 的 format(TemporaAccessor temporal)方法执行格式化, 其中LocalDate, LocalDateTime, LocalTime 等类都是 TemporaAccessor 接口的实现
- 调用 中LocalDate, LocalDateTime, LocalTime 等日期, 时间对象的 format(DateTimeFormatter)方法执行格式化
示例代码
// 例子:
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
public class NewFormatterTest {
public static void main(String[] args){
DateTimeFormatter[] formatters = new DateTimeFormatter[]{
// 直接使用常量创建 DateTimeFormatter格式器
DateTimeFormatter.ISO_LOCAL_DATE,
DateTimeFormatter.ISO_LOCAL_TIME,
DateTimeFormatter.ISO_LOCAL_DATE_TIME,
// 使用本地化的不同风格来创建 DateTimeFormatter 格式器
DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL, FormatStyle.MEDIUM),
// DateTimeFormatter.ofLocalizedTime(FormatStyle.LONG),
// 根据模式字符串来创建 DateTimeFormatter格式器
DateTimeFormatter.ofPattern("Gyyyy%%MMM%%dd HH:mm:ss"),
DateTimeFormatter.ofPattern("Gyyyy-MMM-d HH:mm:ss")
};
LocalDateTime date = LocalDateTime.now();
// 一次使用不同的格式器对 LocalDateTime 进行格式化
for (int i = 0; i < formatters.length; i++){
// 这两行代码的作用相同
System.out.println(date.format(formatters[i]));
System.out.println(formatters[i].format(date));
}
}
}
♥使用 DateTimeFormatter 字符串解析成日期,时间对象
DateTimeFormatter将指定格式的字符串解析成日期, 时间对象(LocalDate, LocalDateTime, LocalTime等实例), 可通过日期, 时间对象提供的 parse(CharSequence text, DateTimeFormatter formatter)方法进行.
示例代码
// 例子:
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class NewFormatterParse {
public static void main(String[] args){
// 定义一个任格式的日期, 时间字符串
String str1 = "2014==09==12 01时06分09秒";
// 根据需要解析的日期, 时间字符串定义解析所用的格式器
DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern(
"yyyy==MM==dd HH时mm分ss秒");
// 执行解析
LocalDateTime dt1 = LocalDateTime.parse(str1, formatter1);
System.out.println(dt1); // out: 2014-09-12T01:06:09
// 再次解析另外一个字符串
String str2 = "2014$$$04$$$13 20 小时";
DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyy$$$MM$$$dd HH 小时");
LocalDateTime dt2 = LocalDateTime.parse(str2, formatter2);
System.out.println(dt2); // out: 2014-04-13T20:00
}
}
8. Calendar 类
- calendar 类是一个表示日历类的抽象类, 可以进行日期运算, 不能创建对象
- 可以通过两种方式来获取GregorianCalendar对象:
- 直接创建GregorianCalendar对象;
- 通过 Calendar 类的静态方法 getInstance()方法获取GregorianCalendar对象
常用方法
-
public static Calendar getInstance()
- 获取一个它的子类 GregorianCalendar 对象
-
public int get(int field)
- 获取某个字段的值, field 参数表示获取那个字段的值
- 可以使用Calendar中定义的常量来表示:
- Calendar.YEAR : 年
- Calendar.MONTH :月
- Calendar.DAY_OF_MONTH:月中的日期
- Calendar.HOUR:小时
- Calendar.MINUTE:分钟
- Calendar.SECOND:秒
- Calendar.DAY_OF_WEEK:星期
-
public void set(int field, int value)
- 设置某个字段的值
-
public void add(int field, int amount)
- 为某个字段增加/减少指定的值
常用方法代码示例
import java.util.Calendar;
//
public class CalendarTest {
// 根据int类型1~7的值, 返回String类型的对应的字符串
public static String getWeek(int w) {
String[] week = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
return week[w-1];
}
//
public static void main(String[] args) throws Exception {
// 通过Calendar获取执行代码的此刻的日期及时间
// 通过 Calendar 的getInstance() 方法来获取Calendar对象
Calendar d = Calendar.getInstance();
int year = d.get(Calendar.YEAR);
int month = d.get(Calendar.MONTH) + 1;
int day = d.get(Calendar.DAY_OF_MONTH);
int hour = d.get(Calendar.HOUR_OF_DAY);
int minute = d.get(Calendar.MINUTE);
int second = d.get(Calendar.SECOND);
//返回值范围:1--7,分别表示:"星期日","星期一","星期二",...,"星期六"
int week = d.get(Calendar.DAY_OF_WEEK);
System.out.println(year + "年 " + month + "月 " + day + "日 " +
hour + " : " + minute + " : " + second);
System.out.println(week);
System.out.println(getWeek(week));
//
// 通过set方法指定Calendar的日期
Calendar c = Calendar.getInstance();
c.set(Calendar.YEAR, 1991);
c.set(Calendar.MONTH, 9-1);
c.set(Calendar.DAY_OF_MONTH, 07);
//
int w = c.get(Calendar.DAY_OF_WEEK);
System.out.println(getWeek(w));
//
// 通过add()方法增加或减少指定天数
Calendar c2 = Calendar.getInstance();
c2.add(Calendar.DAY_OF_MONTH, 200);
int y = c2.get(Calendar.YEAR);
int m = c2.get(Calendar.MONTH) + 1;//转换为实际的月份
int d = c2.get(Calendar.DAY_OF_MONTH);
int wk = c2.get(Calendar.DAY_OF_WEEK);
System.out.println("200天后是:" + y + "年" + m + "月" + d + "日" + getWeek(wk));
}
}