Java基础——IO编程

I/O编程

I/O

  • 简单介绍一下Java中的输入 / 输出系统
  • 输入输出是对于磁盘和内存来说的,程序的运行是在内存中,所以要将数据输入到内存。处理完毕的数据需要保存,便输出到磁盘。
  • Java 中将数据的输入输出抽象为流,流是一组有顺序的,单向的,有起点和终点的数据集合
  • 按照数据单元分为字节流和字符流
  1. 字节流:以 8 位(即 1 byte,8 bit)作为一个数据单元,数据流中最小的数据单元是字节;
    使用InputStream/OutputStream类实现
  2. 字符流:以 16 位(即 1 char,2 byte,16 bit)作为一个数据单元,数据流中最小的数据单元是字符, Java 中的字符是 Unicode 编码,一个字符占用两个字节
    使用Reader/Writer类实现
    在这里插入图片描述
  • Reader/Writer本质上是一个能自动编解码的InputStream/OutputStream
  • JDK提供的java.io是同步IO,java.nio是异步IO
    在这里插入图片描述
  • 我们较常使用的IO类
    在这里插入图片描述
  • 如果有兴趣可以读一下源码
  • 先从目录/文件说起

File

  • java.io.File表示文件系统的一个文件或者目录
	// 构造方法
	File f = new File("C:\\Windows\\notepad.exe")	// windows下使用 \\

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

import java.io.File;
import java.io.IOException;

public static void main(String[] args) throws IOException {
	File win = new File("C:\\Windows");
	System.out.println(win.isDirectory()); // true
	File notepad = new File("C:\\Windows\\notepad.exe");
	System.out.println(notepad.isFile()); // true
	File dir = new File("C:\\abc\\xyz");
	System.out.println(dir.mkdir()); // -> mkdirs
	File readme = new File("./src/readme.txt");
	System.out.println(readme.isFile()); // false
	System.out.println(readme.getAbsolutePath());
	System.out.println(readme.getCanonicalPath());
}

InputStream

  • java.io.InputStream是所有输入流的超类
public static void main(String[] args) throws IOException {
	// 推荐写法,try(resource)保证流被正确关闭
	try (InputStream input = new FileInputStream("readme.txt")) {// FileInputStream文件流
		int n;
		byte[] buffer = new byte[1000];	// 建立buffer缓冲区
		// 一次尽可能多的将字节读入缓冲区,但不会超过;需要使用while保证所有字节读出
		while ((n = input.read(buffer)) != -1) {	
			System.out.println(n);	// 返回字节数
			// System.out.println(buffer);
		}
	}
}

OutputStream

  • java.io.OutputStream是所有输出流的超类
public static void main(String[] args) throws IOException {
	try (OutputStream output = new FileOutputStream("output.txt")) {// FileOutputStream文件流
		byte[] b1 = "Hello".getBytes("UTF-8");
		output.write(b1);
		byte[] b2 = "你好".getBytes("UTF-8");
		output.write(b2);
	}
}
  • ByteArrayOutputStream/ByteArrayInputStream 在内存中模拟字节流的输出输入

Filter模式

  • InputStream可以被继承从而扩展出很多子类。出现子类爆炸的现象
  • 为了避免这种情况我们使用组合功能而非继承的设计模式,称为Filter模式(或Decorator)
  • 通过少量的类组合出复杂的功能
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • FileStream与FilterStream相互配合,包装所需的类
  • 可以参考如下包装形式理解:
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.GZIPInputStream;

public static void main(String[] args) throws IOException {
	try (InputStream input = new GZIPInputStream(new BufferedInputStream(new FileInputStream("test.txt.gz")))) {// 最后向上转型为InputStream
		ByteArrayOutputStream output = new ByteArrayOutputStream();
		byte[] buffer = new byte[1024];
		int n;
		while ((n = input.read(buffer)) != -1) {
			output.write(buffer, 0, n);
		}
		byte[] data = output.toByteArray();
		String text = new String(data, "UTF-8");
		System.out.println(text);
	}
}
  • ZipInputStream是一种FilterInputStream,配合FileInputStream可以直接读取zip内容
  • ZipOutputStream同理
    在这里插入图片描述
  • 下面是ZipStream的基本用法,也是FileStream与FilterStream组合的例子
public static void main(String[] args) throws IOException {
	try (ZipInputStream zip = new ZipInputStream(new BufferedInputStream(new FileInputStream("test.jar")))) {	// 包装
		ZipEntry entry = null;
		while ((entry = zip.getNextEntry()) != null) {// zip不能向上转型为InputStream
			if (entry.isDirectory()) {	// 如果是目录
				System.out.println("D " + entry.getName());
			} else {
				System.out.println("F " + entry.getName() + " " + entry.getSize());
				printFileContent(zip);
			}
		}
	}
}

static void printFileContent(ZipInputStream zip) throws IOException {	// 打印文件内容
	ByteArrayOutputStream output = new ByteArrayOutputStream();// 内存中模拟字节流
	byte[] buffer = new byte[1024];
	int n;
	while ((n = zip.read(buffer)) != -1) {
		output.write(buffer, 0, n);
	}
	byte[] data = output.toByteArray();
	System.out.println("  size: " + data.length);
}

classpath资源文件

  • Java存放.class的目录或者jar包可以包含任意类型的其他文件(jar包主要是压缩的class文件和辅助资源)
  • 从classpath读取文件可以避免不同环境下(Windows/Linux)文件路径不一致的问题
  • Class对象的getResourceAsStream()可以从classpath读取资源
public static void main(String[] args) throws IOException {
	// 从classpath读取配置文件:
	try (InputStream input = Main.class.getResourceAsStream("/conf.properties")) {// src根目录下
		if (input != null) {	// 需要检查返回的InputStream是否为null
			System.out.println("Read /conf.properties...");
			Properties props = new Properties();// 配置读取器
			props.load(input);
			System.out.println("name=" + props.getProperty("name"));
		}
	}
	// 从classpath读取txt文件:
	String data = "/com/hello/sample/data.txt";
	try (InputStream input = Main.class.getResourceAsStream(data)) {
		if (input != null) {	// 要检查是否为null
			System.out.println("Read " + data + "...");
			// Java流读取
			BufferedReader reader = new BufferedReader(new InputStreamReader(input, "UTF-8"));
			System.out.println(reader.readLine());
		} else {
			System.out.println("Resource not found: " + data);
		}
	}
}

序列化

  • 序列化是将一个对象变成二进制文件byte[]
  • 可序列化的java对象必须实现java.io.Serializable接口
  • 类似Serializable这样的空接口被称为“标记接口”(marker interface)
  • 反序列化时JVM不调用构造方法
// Main
public static void main(String[] args) throws IOException, ClassNotFoundException {
	String dataFile = "saved.data";
	try (ObjectOutputStream output = new ObjectOutputStream(
			new BufferedOutputStream(new FileOutputStream(dataFile)))) {
		// 依次写入 int, String, Person:
		output.writeInt(999);
		output.writeUTF("Hello, world!");
		output.writeObject(new Person("Xiao Ming"));
	}
	System.out.println("Read...");
	try (ObjectInputStream input = new ObjectInputStream(new BufferedInputStream(new FileInputStream(dataFile)))) {
		// 依次读入 int, String, Person:
		System.out.println(input.readInt());
		System.out.println(input.readUTF());
		Person p = (Person) input.readObject();
		System.out.println(p);
	}
}
public class Person implements Serializable {// 必须实现此接口
// 可以借助IDEA设置serialVersionUID作为版本号(可选),这样我们即使删除了写入数据的步骤,可以记住UID读取序列化文件!
	private final String name;

	public Person(String name) {
		System.out.println(name);// 反序列化时不调用构造方法
		this.name = name;
	}
	public String getName() {
		return name;
	}
	@Override
	public String toString() {
		return "(Person: " + name + ")";
	}
}
  • Java的序列化机制适用于Java,如果要与其他语言交互,必须 使用通用的序列化方法例如 json

Reader

  • Reader是所有字符输入流的超类,它与InputStream的区别:
    在这里插入图片描述
    在这里插入图片描述
  • Reader实际上是基于InputStream构造的,FileReader内部持有一个FileInputStream
  • 可以通过InputStreamReader()将任意的InputStream转化为Reader
public static void main(String[] args) throws IOException {
	// try (Reader reader = new InputStreamReader(new FileInputStream("readme.txt"), "UTF-8"));// 指定编码
	try (Reader reader = new FileReader("readme.txt")) {// 无法指定编码
		int n;
		while ((n = reader.read()) != -1) {
			System.out.println((char) n);
		}
	}
}
  • CharArrayReader/CharArrayWriter在内存中模拟字符流输入输出
  • 和InputStream一样也是阻塞(blocking)的

Writer

  • Writer是所有字符输入流的超类,它与OutputStream的区别:
    在这里插入图片描述
  • 好了不想多说类比一下吧!
  • 都要使用try(resource)格式保证正常关闭哦!

时间和日期

  • 需要了解时间戳,时区,计时规则和表示形式。比较简单百度一下
  • Java中有新旧两套操作时间日期的类,因为目前有的程序还在混合使用
// 旧接口
import java.util.Date;
// Main
public class Main {
	public static void main(String[] args) throws Exception {
		// 获取系统当前时间戳:
		System.out.println(System.currentTimeMillis());// 获取当前时间戳
		// 获取当前时间:
		Date now = new Date();
		System.out.println(now);
		// 把Date转化为long:
		long t = now.getTime();
		System.out.println(t);
		// 把long转化为Date:
		System.out.println(new Date(t));
	}
}

// Date2String
import java.util.Date;

public class Date2String {
	public static void main(String[] args) throws Exception {
		// 获取当前时间:
		Date now = new Date();
		// 以当前时区打印日期时间:
		System.out.println(now.toString());
		// 以GMT+00:00时区打印日期时间:
		System.out.println(now.toGMTString());
		// 以当前时区+当前Locale打印日期时间:
		System.out.println(now.toLocaleString());	// 国际化
	}
}

// Format
import java.text.SimpleDateFormat;
import java.util.Date;

public class Format {	// 格式化输出
	public static void main(String[] args) throws Exception {
		// 获取当前时间:
		Date now = new Date();
		// 指定格式打印:
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");// "MM-dd-yyyy HH:mm:ss"
		System.out.println(sdf.format(now));
	}
}

// Parse
import java.text.SimpleDateFormat;
import java.util.Date;

public class Parse {	// 字符串解析为时间
	public static void main(String[] args) throws Exception {
		// 按系统Locale解析日期时间:
		String s1 = "2016-11-20 12:15:59";
		Date date1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(s1);
		System.out.println(date1);
		// 解析MMM时默认按照系统Locale:
		String s2 = "Nov/20/2016 12:15:59";
		Date date2 = new SimpleDateFormat("MMM/dd/yyyy HH:mm:ss").parse(s2);
		System.out.println(date2);
		// 按ISO 8601标准格式解析:
		String iso = "2016-11-20T12:15:59";
		Date date3 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").parse(iso);
		System.out.println(date3);
	}
}
// Calendar接口 
import java.util.Calendar;

// Main
public class Main {
	public static void main(String[] args) throws Exception {
		// 获取当前时间表示的Calendar:
		Calendar c = Calendar.getInstance();
		// 转换为Date打印:
		System.out.println(c.getTime());
		// 转换为long打印:
		System.out.println(c.getTimeInMillis());
		// 获取年月日时分秒:
		System.out.println("    Year = " + c.get(Calendar.YEAR));
		// 注意月份从0开始:1月=0,2月=1,...,12月=11:
		System.out.println("   Month = " + c.get(Calendar.MONTH));// 月份从0开始,反人类吧!
		System.out.println("     Day = " + c.get(Calendar.DAY_OF_MONTH));
		// 注意星期从1开始:星期日=1,星期一=2,...,星期六=7:
		System.out.println(" Weekday = " + c.get(Calendar.DAY_OF_WEEK));
		System.out.println("    Hour = " + c.get(Calendar.HOUR_OF_DAY));
		System.out.println("  Minute = " + c.get(Calendar.MINUTE));
		System.out.println("  Second = " + c.get(Calendar.SECOND));
		System.out.println("  Millis = " + c.get(Calendar.MILLISECOND));
		// 默认时区:
		System.out.println("TimeZone = " + c.getTimeZone());// Asia/shanghai
	}
}

// setTime
public class SetTime { // 可以设置时间
	public static void main(String[] args) throws Exception {
		// 获取当前时间表示的Calendar:
		Calendar c = Calendar.getInstance();
		// 转换为Date打印:
		System.out.println(c.getTime());
		// 设置为指定时间:
		c.clear();
		c.set(Calendar.YEAR, 1999);
		c.set(Calendar.MONTH, 10); // 11月
		c.set(Calendar.DAY_OF_MONTH, 30);
		c.set(Calendar.HOUR_OF_DAY, 21);
		System.out.println(c.getTime());
	}
}

// Calculate
public class Calculate {	// 可以运算日期时间
	public static void main(String[] args) throws Exception {
		// 获取当前时间表示的Calendar:
		Calendar c = Calendar.getInstance();
		// 转换为Date打印:
		System.out.println(c.getTime());
		// + 5 days:
		c.add(Calendar.DAY_OF_MONTH, 5);
		// - 2 hours:
		c.add(Calendar.HOUR_OF_DAY, -2);
		// 转换为Date打印:
		System.out.println(c.getTime());
	}
}

// 
import java.util.TimeZone;

public class Zone {	// 获取指定时区的时间
	public static void main(String[] args) throws Exception {
		// 获取当前时间:
		Calendar c = Calendar.getInstance();
		System.out.println(c.getTime());
		// 获取纽约时间:
		c.setTimeZone(TimeZone.getTimeZone("America/New_York"));
		int y = c.get(Calendar.YEAR);
		int m = c.get(Calendar.MONTH) + 1;
		int d = c.get(Calendar.DAY_OF_MONTH);
		int hh = c.get(Calendar.HOUR_OF_DAY);
		int mm = c.get(Calendar.MINUTE);
		int ss = c.get(Calendar.SECOND);
		System.out.println(y + "-" + m + "-" + d + " " + hh + ":" + mm + ":" + ss);
	}
}

java.time

在这里插入图片描述

// 新接口
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;

public class Main {
	public static void main(String[] args) throws Exception {
		// 获取当前本地日期:
		LocalDate d1 = LocalDate.now();
		System.out.println(d1);
		System.out.println("Week = " + d1.getDayOfWeek().getValue());
		// 注意11月=11:
		LocalDate d2 = LocalDate.of(2016, 11, 30);
		System.out.println(d2);

		// 获取当前本地时间:
		LocalTime t1 = LocalTime.now();
		System.out.println(t1);
		LocalTime t2 = LocalTime.of(15, 16, 17);
		System.out.println(t2);

		// 获取当前本地日期和时间:
		LocalDateTime dt1 = LocalDateTime.now();
		System.out.println(dt1);
		// 用LocalDate和LocalTime组合:
		LocalDateTime dt2 = LocalDateTime.of(d2, t2);
		System.out.println(dt2);
	}
}

// Format
import java.time.format.DateTimeFormatter;

public class Format {
	public static void main(String[] args) {
		// 格式化:
		DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
		System.out.println(dtf.format(LocalDateTime.now()));
		// 按ISO格式解析:
		LocalDateTime dt1 = LocalDateTime.parse("2016-11-30T15:16:17");
		System.out.println(dt1);
		// 按指定格式解析:
		LocalDateTime dt2 = LocalDateTime.parse("2016-11-30 15:16:17", dtf);
		System.out.println(dt2);
	}
}

// Calculate
mport java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.temporal.TemporalAdjusters;

public class Calculate {
	public static void main(String[] args) throws Exception {
		// 获取当前日期和时间:
		LocalDateTime ldt = LocalDateTime.now();
		System.out.println(ldt);
		// + 5 days:
		LocalDateTime ldt2 = ldt.plusDays(5);
		System.out.println(ldt2);
		// - 2 hours:
		LocalDateTime ldt3 = ldt2.minusHours(2);
		System.out.println(ldt3);
		// 获得当月第一天:
		LocalDate firstDay = LocalDate.now().withDayOfMonth(1);
		LocalDate firstDay2 = LocalDate.now().with(TemporalAdjusters.firstDayOfMonth());
		System.out.println(firstDay.equals(firstDay2));
		System.out.println(firstDay);
		// 获得当月最后一天:
		LocalDate lastDay = LocalDate.now().with(TemporalAdjusters.lastDayOfMonth());
		System.out.println(lastDay);
		// 获得当月第一个星期日:
		LocalDate firstSunday = LocalDate.now().with(TemporalAdjusters.firstInMonth(DayOfWeek.SUNDAY));
		System.out.println(firstSunday);
		// 判断两个日期哪个在前:
		System.out.println(firstSunday.isBefore(LocalDate.now()));
		// 两个日期相差?年?月?天:
		Period p = LocalDate.now().until(LocalDate.of(2050, 1, 1));
		System.out.println(p);
		// 两个日期一共相差多少天:
		System.out.println(LocalDate.of(2050, 1, 1).toEpochDay() - LocalDate.now().toEpochDay());
	}
}
  • 这里的LocalDateTime不能装换为long

ZonedDateTime

在这里插入图片描述
在这里插入图片描述

  • Instant表示时刻
  • long表示时间戳(秒值)
    在这里插入图片描述
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class Main {
	public static void main(String[] args) throws Exception {
		// 获取当前默认时区的日期和时间:
		ZonedDateTime now = ZonedDateTime.now();
		System.out.println(now);
		// 打印时区:
		System.out.println(now.getZone());
		// 获取Instant:
		Instant ins = now.toInstant();
		System.out.println(ins.getEpochSecond());
		// 按指定时区获取当前日期和时间:
		ZonedDateTime london = ZonedDateTime.now(ZoneId.of("Europe/London")); // 伦敦时间
		System.out.println(london);
		// 把伦敦时间转换到纽约时间:
		ZonedDateTime newyork = london.withZoneSameInstant(ZoneId.of("America/New_York")); // 纽约时间
		System.out.println(newyork);
	}
}

// Local2Zoned
public class Local2Zoned {	// 转换时区
	public static void main(String[] args) throws Exception {
		// 把LocalDateTime转换为ZonedDateTime:
		LocalDateTime ldt = LocalDateTime.of(2016, 11, 30, 8, 15, 59);
		// 关联到当前默认时区:
		ZonedDateTime bj = ldt.atZone(ZoneId.systemDefault());
		System.out.println(bj);
		// 关联到纽约时区:
		ZonedDateTime ny = ldt.atZone(ZoneId.of("America/New_York"));
		System.out.println(ny);
	}
}

public class ChangeZone { // 更改时区
	public static void main(String[] args) {
		// 把LocalDateTime转换为ZonedDateTime:
		LocalDateTime ldt = LocalDateTime.of(2016, 11, 30, 8, 15, 59);
		// 关联到当前默认时区:
		ZonedDateTime bj = ldt.atZone(ZoneId.systemDefault());
		System.out.println(bj);
		// 转换到纽约时区:
		ZonedDateTime ny = bj.withZoneSameInstant(ZoneId.of("America/New_York"));
		System.out.println(ny);
	}
}
  • 新旧接口的转换
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 设置符合不同用户习惯的时间格式
    在这里插入图片描述
  • Locale对象会根据国家常量构建不同的语言环境(主要是格式上)
  • 时间的确定主要是DateTime/long/Instant

单元测试

  • 什么是单元测试?
    在这里插入图片描述
    一个项目往往包含了大量的方法,可能有成千上万个。如何去保证这些方法产生的结果是我们想要的呢?最容易想到的一个方式,就是我们通过System.out来输出我们的结果,看看是不是满足我们的需求,但是项目中总不能在每一个方法中都去输出一遍非常繁琐,所以需要单元测试框架
  • 测试驱动开发(TDD)
    在这里插入图片描述
  • 测试框架JUnit
    在这里插入图片描述

JUnit模块

  • 特点:
    在这里插入图片描述
  • 使用断言Assert
    在这里插入图片描述
  • 使用JUnit需要注意:
    在这里插入图片描述

  • 测试之前我们一般要初始化一些资源,称为Fixture
  • 需要使用如下方法
    在这里插入图片描述
    使用步骤:
  1. 在需要测试的类中使用ctrl+shift+T创建测试类,可能会自动下载一些jar包添加到lib库
  2. 在IDEA为我们创建好的测试方法中填写逻辑
  3. 测试方法一般都为void类型,必须使用@Test注解
package Hello;

import org.junit.Test;
import static org.junit.Assert.*;
public class RecursionTest {
    @Test
    public void isNumberic() {
        Recursion re = new Recursion();
        boolean x = re.isNumberic("666");
        assertEquals(x,true);
    }
}
  • 我们要了解测试的生命周期
  • 一般情况下,只需将公有的实例化步骤放在@Before注解的方法中即可,一般命名为setUp()
  • 但如果需要创建数据库等耗时操作,需要在@BeforeClass注解的方法中执行
  • 顺序是:@BeforeClass–>@Before–>@After–>…[@Before–>@After]…–>@AfterClass

测试异常

  • 使用expected测试异常
// 在测试类中
@Test(expected=NumberFormatException.class)
public void testCalcWithNull() {
	calc.calculate(null);	// 如果测试未通过,说明我们传入null时没有报此异常,需要修改代码
}

参数化测试

  • 当我们使用一组参数对相同的方法测试时,可以将参数用方法返回,进行一次性测试,而不用不断重复
  • 参数必须由静态方法data()返回,被标记(注解)为@Parameters,返回类型为Collection<>
  • 此测试类必须被标记为@RunWith(parameterized.class)
  • 构造方法参数必须和测试参数(data中定义的参数)一一对应
    在这里插入图片描述
  • 相当于测试类会使用构造方法进行实例化,将数据赋值给成员变量
  • 可以通过@Parameter(index)标记public字段,就不用写构造方法,JUnit会自动创建实例,并把数据注入!
    在这里插入图片描述
  • 还可以为测试设置超时
@Test(timeout=1000)	// 单位是毫秒

超时测试不能取代性能测试和压力测试

正则表达式

  • 一个正则表达式就是一个描述规则的字符串,编写正确的规则,就可以通过正则引擎判断目标字符串是否符合规则
  • 可以应用于任何语言,JDK中使用java.util.regex
  • 规则可以参考博文

注:Java 的正则表达式字符串转义有两层次的意义,那就是 Java 字符串转义出符合正则表达式语法的字符串,所以匹配“ . ”要使用“ \\. ”,Java转义后交给正则表达式的就是 “\.”。如果要匹配到“\”,就需要使用“\\\\”,因为要保证Java 程序里输出的是 “\\”才行,交给正则表达时候,规则我们就比较熟悉了!

  • 我们常用分组匹配的方式
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Time {
    /**
     * TODO: 提取合法时间字符串的时,分,秒
     *
     * @param str
     *            Time字符串
     * @return Time对象,包含时,分,秒,或者当字符串不合法时返回null
     */
    // 只编译一次规则,提高效率
    static Pattern p = Pattern.compile("^([0-9]|[0-1][0-9]|2[0-3])\\:([0-9]|[0-5][0-9])\\:([0-9]|[0-5][0-9])$");
    public static Time parseTime(String str) {
        int h = 0;
        int m = 0;
        int s = 0;
        // FIXME:
        Matcher mt = p.matcher(str);// 正则匹配
        // 可以使用mt.find()实现搜索
        if (mt.matches()) {// 匹配成功
        	// group(0)表示匹配到的所有值
            h = Integer.parseInt(mt.group(1));// 第一个分组匹配到的值
            m = Integer.parseInt(mt.group(2));
            s = Integer.parseInt(mt.group(3));
            return new Time(h, m, s);
        }
        return null;
    }

    private final int hour;
    private final int minute;
    private final int second;

    public Time(int hour, int minute, int second) {// 构造方法
        this.hour = hour;
        this.minute = minute;
        this.second = second;
    }
    public int getHour() {
        return hour;
    }
    public int getMinute() {
        return minute;
    }
    public int getSecond() {
        return second;
    }
    @Override
    public boolean equals(Object o) {
        if (o == this) {
            return true;
        }
        if (o instanceof Time) {
            Time t = (Time) o;
            return t.hour == this.hour && t.minute == this.minute && t.second == this.second;
        }
        return false;
    }
    @Override
    public int hashCode() {
        return Objects.hash(hour, minute, second);
    }
    @Override
    public String toString() {
        return String.format("%02d:%02d:%02d", hour, minute, second);
    }
}

  • 用测试康康
import org.junit.Test;

import static org.junit.Assert.*;

public class TimeTest {

    @Test
    public void parseTime() {
        assertEquals(new Time(0, 0, 0), Time.parseTime("0:0:0"));
        assertEquals(new Time(0, 0, 59), Time.parseTime("0:0:59"));
        assertEquals(new Time(0, 59, 0), Time.parseTime("0:59:0"));
        assertEquals(new Time(5, 0, 9), Time.parseTime("05:00:9"));
        assertEquals(new Time(10, 2, 9), Time.parseTime("10:02:9"));
        assertEquals(new Time(10, 2, 9), Time.parseTime("10:2:09"));
        assertEquals(new Time(23, 0, 1), Time.parseTime("23:0:01"));
        assertEquals(new Time(23, 59, 59), Time.parseTime("23:59:59"));

        assertNull(Time.parseTime("000:00:00"));
        assertNull(Time.parseTime("23:59:60"));
        assertNull(Time.parseTime("23:60:59"));
        assertNull(Time.parseTime("24:00:00"));
        assertNull(Time.parseTime("0:0:A"));
        assertNull(Time.parseTime("11-12-12"));
    }
}
  • 我们可以使用正则表达式实现搜索、替换等等
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public static void main(String[] s) {
	String s = "Roy is   a handsome  boy";
	String r = s.replaceAll("\\s+", " ");
	String w = r.replaceAll("\\w+", "<h1>$1<h1>");	// $1表示匹配到的字符
}

小结

这里总结了Java的IO编程,主要包括字符字节流,Filter模式,通过classpath获取资源,序列化对象等。然后介绍了Java中操作时间日期的方法,如何进行代码测试以及正则表达式的基本使用方法。

部分图片来源于网络
部分代码来自廖雪峰老师的教程
如有不当,烦请指出

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章