12 BUg优化
12.1 技术问题
正则表达式
Pattern和Matcher
Pattern是正则表达式引擎
Matcher是匹配器
Matches : 全词匹配
Find : 任意位置
lookingAt : 从前往后匹配
package com;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class TestRegex_01 {
public static void main(String[] args) {
String regex = "\\d{11}";
String tel = "131131131121";
// 创建引擎
Pattern pattern = Pattern.compile(regex);
// 创建匹配器
Matcher matcher = pattern.matcher(tel);
// System.out.println(matcher.matches());
// System.out.println(matcher.find());
System.out.println(matcher.lookingAt());
tel = "我的电话是13113113111";
regex = "我的电话是(\\d{11})";
pattern = Pattern.compile(regex);
matcher = pattern.matcher(tel);
matcher.find();
System.out.println(matcher.group(1));
}
}
12.2 封装工具类
package com.tledu.zrz.util;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 正则表达式工具类
*
* @author 天亮教育-帅气多汁你泽哥
* @Date 2021年11月12日 上午9:37:50
*/
public class RegexUtil {
/**
* 格式验证
*
* @param regex
* @param input
* @return
*/
public static boolean isValid(String regex, String input) {
Pattern pattern = Pattern.compile(regex);
// 创建匹配器
Matcher matcher = pattern.matcher(input);
return matcher.matches();
}
/**
* 数据提取
*
* @param regex
* @param input
* @param groupIndex
* @return
*/
public static String getMatchContent(String regex, String input,
int groupIndex) {
Pattern pattern = Pattern.compile(regex);
// 创建匹配器
Matcher matcher = pattern.matcher(input);
if (matcher.find()) {
return matcher.group(groupIndex);
}
return null;
}
public static String getMatchContent(String regex, String input) {
return getMatchContent(regex, input, 0);
}
}
12.3 测试工具类
package com;
import com.tledu.zrz.util.RegexUtil;
public class TestRegex_02 {
public static void main(String[] args) {
String regex = "\\d{11}";
String tel = "13113113111";
System.out.println(RegexUtil.isValid(regex, tel));
tel = "我的电话是13113113111";
regex = "我的电话是(\\d{11})";
System.out.println(RegexUtil.getMatchContent(regex, tel,1));
}
}
12.4 业务问题
package com.tledu.zrz.util;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 正则表达式工具类
*
*/
public class RegexUtil {
private static String regexIP = "((25[0-5]|2[0-4]\\d|[1]{1}\\d{1}\\d{1}|[1-9]{1}\\d{1}|\\d{1})($|(?!\\.$)\\.)){4}";
/**
* 校验IP
* @param ip
* @return
*/
public static boolean isValidIP(String ip) {
return isValid(regexIP, ip);
}
/**
* 格式验证
*
* @param regex
* @param input
* @return
*/
public static boolean isValid(String regex, String input) {
Pattern pattern = Pattern.compile(regex);
// 创建匹配器
Matcher matcher = pattern.matcher(input);
return matcher.matches();
}
/**
* 数据提取
*
* @param regex
* @param input
* @param groupIndex
* @return
*/
public static String getMatchContent(String regex, String input,
int groupIndex) {
Pattern pattern = Pattern.compile(regex);
// 创建匹配器
Matcher matcher = pattern.matcher(input);
if (matcher.find()) {
return matcher.group(groupIndex);
}
return null;
}
public static String getMatchContent(String regex, String input) {
return getMatchContent(regex, input, 0);
}
}
12.5测试
package com;
import com.tledu.zrz.util.RegexUtil;
public class TestRegex_03 {
public static void main(String[] args) {
String ip = "1.1.322.5";
System.out.println(RegexUtil.isValidIP(ip));
}
}
12.6应用
校验应该写在对外提供的接口处
getLocation
13 性能调优
13.1相关技术
13.1.1硬件
内存,CPU.磁盘,网络等 都可以实现性能提高
13.1.2软件
13.1.2.1直接调优
哪里慢,就调哪里,不需要花里胡哨的
主要指算法问题,内核层面,难度较大,大部分都是非直接调优
13.1.2.2迂回调优
通过设计,策略,可以通过不用面对底层优化的难题
1.3.1.2.3迂回调优方向
缓存策略
通过添加时间断点,测试得出,结构化耗时较多
一开始,我们一次运行中,先后校验两个IP,需要结构化两次
后来我们使用静态语句块解决了这个问题
做到一次生命周期中,只会结构化一次
现在面临的问题是,需要让多次生命周期,使用同一个结构化之后的对象,就可以解决当前的问题可以使用序列化和反序列化解决
13.1.3 序列化和反序列化
序列化 : 将内存中对象保存到硬盘中
反序列化 : 把硬盘中对象载入到内存
被序列化的对象必须实现serlizable接口
13.2首次调优
13.2.1技术问题
package com;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class TestSerinalizable_01 {
public static void main(String[] args) throws Exception{
User user =new User(11);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:/x"));
oos.writeObject(user);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:/x"));
Object o = ois.readObject();
System.out.println(o);
}
}
class User implements Serializable{
private int age;
public User(int age) {
super();
this.age = age;
}
@Override
public String toString() {
return "User [age=" + age + "]";
}
}
13.2.2封装工具类
package com.tledu.zrz.util;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class SerDeUtil {
/**
* 写入
*
* @param obj
* @param objFilePath
* @throws IOException
*/
public static void saveObject(Object obj, String objFilePath)
throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(
objFilePath));
oos.writeObject(obj);
oos.close();
}
/**
* 读取
*
* @param objFilePath
* @return
* @throws ClassNotFoundException
* @throws IOException
*/
public static Object getObj(String objFilePath)
throws ClassNotFoundException, IOException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
objFilePath));
Object o = ois.readObject();
return o;
}
}
13.2.3测试
package com;
import com.tledu.zrz.util.SerDeUtil;
public class TestSerinalizable_02 {
public static void main(String[] args) throws Exception{
User user =new User(11);
SerDeUtil.saveObject(user, "D:/a");
System.out.println(SerDeUtil.getObj("D:/a"));
}
}
13.2.4初始化优化
只有第一次才序列化,其余的都反序列化即可
判断该文件是否存在,如果存在,就反序列化获取,如果不存在,就序列化写出
注意
public class IPAndLocationPojo implements Serializable,
Comparable<IPAndLocationPojo> {
package com.tledu.zrz.manager;
import com.tledu.zrz.pojo.IPAndLocationPojo;
import com.tledu.zrz.util.FileOperatorUtil;
import com.tledu.zrz.util.IPUtil;
import com.tledu.zrz.util.RegexUtil;
import com.tledu.zrz.util.SerDeUtil;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* 该类为项目中管理类
*
* @author 天亮教育-帅气多汁你泽哥
* @Date 2021年11月11日 上午11:45:19
*/
public class DataProcessManager {
private static IPAndLocationPojo[] ipLocationPojoArr = null;
static {
// 地址库文件
String ipLibrartPath = "ip_location_relation.txt";
// 字符编码
String encoding = "utf-8";
// 文件地址
String serde_obj_filepath = "ipLibObj.data";
// 判断序列化文件是否存在
boolean isInit = new File(serde_obj_filepath).exists();
// 存在就反序列化获取
if (isInit) {
try {
Object object = SerDeUtil.getObj(serde_obj_filepath);
ipLocationPojoArr = (IPAndLocationPojo[]) object;
} catch (ClassNotFoundException | IOException e) {
e.printStackTrace();
}
}else{
// 不存在就序列化写出
// 获取数据
List<IPAndLocationPojo> ipAndLocationPojos = null;
try {
ipAndLocationPojos = DataProcessManager.getPojoList(ipLibrartPath,
encoding);
} catch (IOException e) {
e.printStackTrace();
}
// 转换为数组
ipLocationPojoArr = DataProcessManager
.convertListToArrayAndSort(ipAndLocationPojos);
try {
SerDeUtil.saveObject(ipLocationPojoArr, serde_obj_filepath);
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 对外提供的接口,入参IP出参地址
*
* @param ip
* @return
*/
public static String getLocation(String ip) {
if (RegexUtil.isValidIP(ip)) {
int index = DataProcessManager.binaraySearch(ipLocationPojoArr, ip);
return index == -1 ? "未找到" : ipLocationPojoArr[index].getLocation();
}else{
return "IP地址格式不正确,请重新输入";
}
}
/**
* 业务类对应的二分法
*
* @param ipLocationPojoArr
* 数组
* @param ip
* ip
* @return 索引
*/
public static int binaraySearch(IPAndLocationPojo[] ipLocationPojoArr,
String ip) {
// 转换为long类型
long ipLong = IPUtil.ipToLong(ip);
int startIndex = 0;
int endIndex = ipLocationPojoArr.length - 1;
int m = (endIndex + startIndex) / 2;
while (startIndex <= endIndex) {
// 大于等于起始 小于等于结束 说明找到了
// 小于起始 在前半截
// 大于结束 在后半截
if (ipLong > ipLocationPojoArr[m].getEndIPLong()) {
startIndex = m + 1;
} else if (ipLong < ipLocationPojoArr[m].getStartIPLong()) {
endIndex = m - 1;
} else {
return m;
}
m = (startIndex + endIndex) / 2;
}
return -1;
}
/**
* 将对象集合转换为对象数组并排序
*
* @param pojoList
* @return
*/
public static IPAndLocationPojo[] convertListToArrayAndSort(
List<IPAndLocationPojo> pojoList) {
// 转换为数组
IPAndLocationPojo[] ipLocationPojoArr = new IPAndLocationPojo[pojoList
.size()];
pojoList.toArray(ipLocationPojoArr);
// 排序
Arrays.sort(ipLocationPojoArr);
return ipLocationPojoArr;
}
/**
* 把读取到的List<String> 转换为 List<IPAndLocationPojo>
*
* @param ipLibrartPath
* @param encoding
* @return
* @throws IOException
*/
public static List<IPAndLocationPojo> getPojoList(String ipLibrartPath,
String encoding) throws IOException {
List<String> lineList = FileOperatorUtil.getLineList(ipLibrartPath,
encoding);
List<IPAndLocationPojo> ipAndLocationPojos = new ArrayList<IPAndLocationPojo>();
// 遍历 获取每一行
for (String string : lineList) {
if (string == null || string.trim().equals("")) {
continue;
}
// 以\t分割,得到三个列
String[] columnArray = string.split("\t");
// 创建结构化对象
IPAndLocationPojo ipAndLocationPojo = new IPAndLocationPojo(
columnArray[0], columnArray[1], columnArray[2]);
// 保存到集合中
ipAndLocationPojos.add(ipAndLocationPojo);
}
return ipAndLocationPojos;
}
}
13.3IO调优
加入序列化和反序列化之后,导致效率更低,并且第二个运行要比第一次还慢,说明反序列化有问题
缓冲流 : 缓冲流是IO流的缓冲区,用来提高IO的效率
首次 7000
非首次 20000
文件大小为 38.3M
13.3.1引入缓冲流
package com.tledu.zrz.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class SerDeUtil {
/**
* 对象写出,引入缓冲流
*
* @param obj
* @param objFilePath
* @param cacheByyeArrayLength
* @throws IOException
*/
public static void saveObject(Object obj, String objFilePath,
int cacheByyeArrayLength) throws IOException {
FileOutputStream fos = new FileOutputStream(objFilePath);
// 字节数组缓冲流
ByteArrayOutputStream baos = new ByteArrayOutputStream(
cacheByyeArrayLength);
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(obj);
byte[] bytes = baos.toByteArray();
fos.write(bytes);
oos.close();
fos.close();
}
/**
* 获取,引入缓冲流
*
* @param objFilePath
* @param cacheByyeArrayLength
* @return
* @throws ClassNotFoundException
* @throws IOException
*/
public static Object getObj(String objFilePath, int cacheByyeArrayLength)
throws ClassNotFoundException, IOException {
FileInputStream fis = new FileInputStream(objFilePath);
byte[] bytes = new byte[cacheByyeArrayLength];
fis.read(bytes);
fis.close();
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais);
Object o = ois.readObject();
ois.close();
return o;
}
/**
* 写入
*
* @param obj
* @param objFilePath
* @throws IOException
*/
public static void saveObject(Object obj, String objFilePath)
throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(
objFilePath));
oos.writeObject(obj);
oos.close();
}
/**
* 读取
*
* @param objFilePath
* @return
* @throws ClassNotFoundException
* @throws IOException
*/
public static Object getObj(String objFilePath)
throws ClassNotFoundException, IOException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
objFilePath));
Object o = ois.readObject();
ois.close();
return o;
}
}
13.3.2 调用处更改
13.4代码标准化
代码中,出现了好多这些变量,当我们需要更改某一个的时候,不好找
集中管理
13.4.1StaticValue
package com.tledu.zrz.util;
public class StaticValue {
// 地址库文件
public static String ipLibrartPath = "ip_location_relation.txt";
// 字符编码
public static String encoding = "utf-8";
// 文件地址
public static String serde_obj_filepath = "ipLibObj.data";
// 根据文件大小,计算长度
public static int cacheByteArrayLength = 40*1024*1024;
}
13.4.2应用
// 判断序列化文件是否存在
File file = new File(StaticValue.serde_obj_filepath);
boolean isInit = file.exists();
// 存在就反序列化获取
if (isInit) {
try {
Object object = SerDeUtil.getObj(
StaticValue.serde_obj_filepath,
StaticValue.cacheByteArrayLength);
ipLocationPojoArr = (IPAndLocationPojo[]) object;
} catch (ClassNotFoundException | IOException e) {
e.printStackTrace();
}
} else {
// 不存在就序列化写出
// 获取数据
List<IPAndLocationPojo> ipAndLocationPojos = null;
try {
ipAndLocationPojos = DataProcessManager.getPojoList(
StaticValue.ipLibrartPath, StaticValue.encoding);
} catch (IOException e) {
e.printStackTrace();
}
// 转换为数组
ipLocationPojoArr = DataProcessManager
.convertListToArrayAndSort(ipAndLocationPojos);
try {
SerDeUtil.saveObject(ipLocationPojoArr,
StaticValue.serde_obj_filepath,
StaticValue.cacheByteArrayLength);
} catch (IOException e) {
e.printStackTrace();
}
}
14优化进阶
14.1.1 IO优化
直接优化 : 提高IO效率
间接优化 : 数据大小也会应该效率问题
文件大小变动
首次2500 非首次 520-600