目录
I/O编程
I/O
- 简单介绍一下Java中的输入 / 输出系统
- 输入输出是对于磁盘和内存来说的,程序的运行是在内存中,所以要将数据输入到内存。处理完毕的数据需要保存,便输出到磁盘。
- Java 中将数据的输入输出抽象为流,流是一组有顺序的,单向的,有起点和终点的数据集合
- 按照数据单元分为字节流和字符流
- 字节流:以 8 位(即 1 byte,8 bit)作为一个数据单元,数据流中最小的数据单元是字节;
使用InputStream/OutputStream
类实现 - 字符流:以 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
- 需要使用如下方法
使用步骤:
- 在需要测试的类中使用
ctrl+shift+T
创建测试类,可能会自动下载一些jar包添加到lib库 - 在IDEA为我们创建好的测试方法中填写逻辑
- 测试方法一般都为
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中操作时间日期的方法,如何进行代码测试以及正则表达式的基本使用方法。
部分图片来源于网络
部分代码来自廖雪峰老师的教程
如有不当,烦请指出