BitSet
BitSet 类是用于存放二进制位值的布尔数组,数组大小按需增加。构造器为
BitSet();
// 指定初始化数组大小
BitSet(int size);
public class BitSetDemo {
// bit1 的值
// {0, 2, 4, 6, 8, 10, 12, 14}
// bit2 的值
// {1, 2, 3, 4, 6, 7, 8, 9, 11, 12, 13, 14}
// and
// {2, 4, 6, 8, 12, 14}
// or
// {1, 2, 3, 4, 6, 7, 8, 9, 11, 12, 13, 14}
public static void main(String[] args) {
BitSet bit1 = new BitSet(16);
BitSet bit2 = new BitSet(16);
for (int i = 0; i < 16; i++) {
if (i % 2 == 0) {
bit1.set(i);
}
if (i % 5 != 0) {
bit2.set(i);
}
}
System.out.println("bit1 的值");
System.out.println(bit1);
System.out.println("bit2 的值");
System.out.println(bit2);
System.out.println("and");
bit1.and(bit2);
System.out.println(bit1);
System.out.println("or");
bit1.or(bit2);
System.out.println(bit1);
}
}
Optional
Optional 类用于值可能有也可能没有的情况。这个类没有定义任何构造器,of()
方法用于创建具有指定值的 Optional 对象,empty()
方法创建没有值的 Optional 对象。isPresent()
方法判断 Optional 对象是否有值。orElse()
方法接收一个默认值,如果 Optional 对象有值,则返回这个值;否则,返回默认值。get()
方法返回 Optional 对象的值,如果对象没有值,使用 get()
方法将抛出异常。
// empty 没有值
// 默认值
// abc 有值
// 值为:abc
public class OptionalDemo {
public static void main(String[] args) {
Optional<String> empty = Optional.empty();
if (empty.isPresent()) {
System.out.println("empty 有值");
} else {
System.out.println("empty 没有值");
System.out.println(empty.orElse("默认值"));
}
Optional<String> abc = Optional.of("abc");
if (abc.isPresent()) {
System.out.println("abc 有值");
System.out.println("值为:" + abc.get());
}
}
}
OptionalInt、OptionalLong 和 OptionalDouble 类和 Optional 类相似,区别在于前 3 个类用于存储 int、long 和 double 类型值,Optional 类可以存储任意类型值。
Date
Date 类封装了日期和时间,构造器如下
// 以当前日期和时间创建对象
Date();
// 以从 1970.01.01 0 点开始经过了指定毫秒数到达的日期和时间创建对象
Date(long milliseconds);
Date 对象只能使用少数的日期和时间表示。
// Thu Aug 10 14:46:16 CST 2023
// 从 1970 年开始经过的毫秒数:1691649976647
public class DateDemo {
public static void main(String[] args) {
Date date = new Date();
long time = date.getTime();
System.out.println(date);
System.out.println("从 1970 年开始经过的毫秒数:" + time);
}
}
Calendar
Calendar 抽象类提供了获取日期和时间中特定部分的方法,每个部分的具体功能由子类实现。它没有提供 public 构造器。
public class CalendarDemo {
public static void main(String[] args) {
// 根据默认区域和时区创建 GregorianCalendar 对象
Calendar instance = Calendar.getInstance();
// 2023年 8月 10日
System.out.println(instance.get(Calendar.YEAR) + "年 "
+ (instance.get(Calendar.MONDAY) + 1)+ "月 "
+ instance.get(Calendar.DATE) + "日");
// 3:22:51
System.out.println(instance.get(Calendar.HOUR) + ":" +
instance.get(Calendar.MINUTE) + ":" +
instance.get(Calendar.SECOND));
// 11:22:30 (以 12 小时表示,24 小时无效)
instance.set(Calendar.HOUR, 11);
instance.set(Calendar.MINUTE, 22);
instance.set(Calendar.SECOND, 30);
System.out.println(instance.get(Calendar.HOUR) + ":" +
instance.get(Calendar.MINUTE) + ":" +
instance.get(Calendar.SECOND));
}
}
GregorianCalendar
GregorianCalendar 类是 Calendar 类的子类,它表示公历。构造器如下
// 使用默认区域和时间创建对象,month 中,0 表示 1 月,类推
GregorianCalendar(int year, int month, int dayOfMonth);
GregorianCalendar(int year, int month, int dayOfMonth, int hours, int minutes);
GregorianCalendar(int year, int month, int dayOfMonth, int h, int m, int s);
isLeapYear(int year)
方法判断是否为闰年。
GregorianCalendar 类的使用方式和 Calendar 类相似。
Random
Random 类用于产生伪随机数,因为产生的数服从均匀分布序列。构造器为
Random();
// 使用指定的 seed 创建随机数产生器,seed 决定了随机数产生的开始位置,
// 使用相同 seed 创建的产生器产生的随机数相同
Random(long seed)
nextXX()
方法返回对应类型的随机数,其中 XX 可以为 Boolean、Bytes、Int、Float 和 Double。nextGaussian()
返回的随机数服从均值为 0,标准差为 1 的 double 类型数。
// 平均值:0.07333551712931925
// *
// ******
// ******
// *******
// **************************
// **********************
// **************
// ***********
// ******
// *
public class RandDemo {
public static void main(String[] args) {
Random random = new Random();
double value;
double sum = 0;
int[] bell = new int[10];
for (int i = 0; i < 100; i++) {
value = random.nextGaussian();
sum += value;
double t = -2;
for (int j = 0; j < 10; j++, t += 0.5) {
if (value < t) {
bell[j]++;
break;
}
}
}
System.out.println("平均值:" + (sum / 100));
for (int i = 0; i < 10; i++) {
for (int j = bell[i]; j > 0; j--) {
System.out.print("*");
}
System.out.println();
}
}
}
doubles()
、ints()
和 longs()
方法返回伪随机数流,元素值范围是 [0,1)。元素类型分别为 double、int 和 long。最简的形式为
DoubleStream doubles();
IntStream ints();
LongStream longs();
Timer 和 TimerTask
Timer 和 TimerTask 类用于调度某个任务,使得这个任务在某个特定时间点开始执行。Timer 类用于调度任务,TimerTask 类则表示被调度的任务,它实现了 Runnable 接口。Timer 构造器的形式如下
// 作为普通线程运行
Timer();
// t 为 true 则作为 daemon 线程运行
Timer(boolean t);
// 为 Timer 线程指定名字,t 为 true 则作为 daemon 线程运行
Timer(String name, boolean t);
public class TTest {
static class TimerTaskA extends TimerTask {
@Override
public void run() {
System.out.println("任务执行完毕");
}
}
// 任务执行完毕
// 任务执行完毕
// 任务执行完毕
// 任务执行完毕
public static void main(String[] args) {
TimerTaskA a = new TimerTaskA();
Timer timer = new Timer();
// 1s 后 a 执行,然后每隔 0.5s 执行
timer.schedule(a, 1000, 500);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
// 取消 timer 线程
timer.cancel();
}
}
Formatter
Formatter 类用于格式化输出。它一般将程序使用的二进制数据转换成格式化文本,然后将格式化文本存入缓冲区。部分构造器如下
// 默认情况下,缓冲区是对象自动创建的一个 StringBuilder 对象
Formatter();
// buf 表示缓冲区,为 null 则使用自动创建的 StringBuilder 对象作为缓冲区
Formatter(Appendable buf);
// loc 表示区域
Formatter(Appendable buf, Locale loc);
// 将格式化文本写入文件 filename
Formatter(String filename);
// charset 指定了字符集
Formatter(String filename, String charset);
// file 表示写入格式化文本的文件
Formatter(File file);
// out 表示接收格式化文本的输出流
Formatter(OutputStream out);
Formatter 对象的 format()
方法用于格式化字符串。它的 toString()
方法返回格式化的字符串。
Formatter format(String fmt, Object... args);
// abc 字符串 10 3.960000
public class FormatDemo {
public static void main(String[] args) {
Formatter formatter = new Formatter();
formatter.format("abc %s %d %f", "字符串", 10, 3.96);
System.out.println(formatter);
}
}
它的 out()
方法返回存放格式化字符串的缓冲区的引用,也就是 Appendable 对象的引用。
在格式化字符串中,%n
表示换行,%%
表示百分号。位于百分号和格式标识符中间的数字表示最小位宽,也就是待格式化的数应该占的位数,当指定的位数小于待格式化数的位数时,忽略最小位宽,输出全部位数。
public class FormatDemo4 {
/*
输出
|10.314156|
| 10.314156|
|00010.314156|
*/
public static void main(String[] args) {
Formatter formatter = new Formatter();
// 最小域宽默认右对齐,0 表示补 0,默认补空格
formatter.format("|%f|%n|%12f|%n|%012f|", 10.314156, 10.314156, 10.314156);
System.out.println(formatter);
formatter.close();
}
}
位于百分号和格式标识符中间的小数点后面的数字表示格式化显示的精度。例如 %.3f
显示小数点后 3 位,%.10s
显示字符串前 10 个字符。
位于百分号和格式标识符中间的减号表示左对齐,例如 %-5.1f
格式化的浮点数占 5 个字符,保留小数点 1 位,左对齐。
位于百分号和格式标识符中间的 n$
表示格式化字符串中这个位置应该匹配第几个参数,参数从 1 开始算。例如
// 输出结果为:255 ff
fmt.format("%d %1$x", 255);
位于百分号和格式标识符中间的小于号表示当前位置使用前一个使用的参数。例如
// 输出结果为:255 ff
fmt.format("%d %<x", 255);
通常,Fomatter 对象使用完毕后需关闭,释放占用的资源。有两种方式:其一是调用 close()
方法,其二是在 try-with-resources 语句中使用。
printf()
方法内部使用 Fomatter 对象格式化字符串。
Scanner
Scanner 类和 Fomatter 类相反,它用于读取格式化输入并将其转换成二进制表示。
public class AvgNums {
/**
* 输入:1 2 3 4 5 6 7 8 9 10 done
* 输出:平均数为:5.5
*/
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int count = 0;
double sum = 0;
// 判断是否有可读取的内容
while (scanner.hasNext()) {
// 下一个可读去的内容是否和 double 类型兼容
if (scanner.hasNextDouble()) {
// 按照 double 类型读取
sum += scanner.nextDouble();
count++;
} else {
String str = scanner.next();
if (str.equals("done")) {
break;
} else {
System.out.println("格式错误");
return;
}
}
}
scanner.close();
System.out.println("平均数为:" + sum / count);
}
}
关闭 Scanner 对象时,与它关联的 Readable 对象会自动关闭。Scanner 对象实现了 AutoCloseable 接口,可以使用 try-with-resources 语句。
public class ScanMixed {
/**
* 输出:
* test
* scanning
* 10
* 10.3
* true
* two
* false
* 21
* 4.13
*/
public static void main(String[] args) throws IOException {
FileWriter fileWriter = new FileWriter("t1.txt");
fileWriter.write("test scanning 10 10.3 true two false 21 4.13");
fileWriter.close();
FileReader fileReader = new FileReader("t1.txt");
int i;
double d;
boolean b;
String s;
try(Scanner scanner = new Scanner(fileReader)) {
while (scanner.hasNext()) {
// int 必须位于 double 前面,不然 int 分支不可达
// double 兼容 int,隐式转换
if (scanner.hasNextInt()) {
System.out.println(scanner.nextInt());
} else if (scanner.hasNextDouble()) {
System.out.println(scanner.nextDouble());
} else if (scanner.hasNextBoolean()) {
System.out.println(scanner.nextBoolean());
} else {
// 读取字符串
System.out.println(scanner.next());
}
}
}
}
}
默认情况下,Scanner 对象使用空格作为一次读取的分隔符。useDelimiter()
方法可以自定义分隔符。形式为
Scanner useDelimiter(String pattern);
Scanner useDelimiter(Pattern pattern);
public class SetDelimiters {
/**
* 2.0
* 3.14
* 5.0
* 6.0
* 7.4
* 9.1
* 1.2
*/
public static void main(String[] args) throws IOException {
FileWriter fileWriter = new FileWriter("t2.txt");
fileWriter.write("2, 3.14, 5,6, 7.4, 9.1, 1.2, done");
fileWriter.close();
FileReader fileReader = new FileReader("t2.txt");
try (Scanner scanner = new Scanner(fileReader)) {
// 自定义读取分隔符
// 匹配一个 , 或者 0 或多个空格
scanner.useDelimiter(", *");
while (scanner.hasNext()) {
if (scanner.hasNextDouble()) {
System.out.println(scanner.nextDouble());
} else {
String next = scanner.next();
if (next.equals("done")) {
System.out.println("读取完毕");
} else {
System.out.println("发生错误");
return;
}
}
}
}
}
}
delimiter()
方法返回当前使用的分隔符。
findInLine()
方法从 Scanner 对象关联的输入数据中搜索匹配项,找到匹配项则读取匹配项并返回,下一次从匹配项的下一内容开始读取。如果没有匹配项,返回 null。
public class FindInLineDemo {
public static void main(String[] args) {
String s = "Name: abc age: 19 id: 223";
try (Scanner scanner = new Scanner(s)) {
String age = scanner.findInLine("age:");
if (scanner.hasNext()) {
// 从匹配项后面开始读取
System.out.println(scanner.next());
}
}
}
}
参考
[1] Herbert Schildt, Java The Complete Reference 11th, 2019.