最后
我还为大家准备了一套体系化的架构师学习资料包以及BAT面试资料,供大家参考及学习
已经将知识体系整理好(源码,笔记,PPT,学习视频)
List userDOList = …;
List userVOList = new ArrayList<>(userDOList.size());
for (UserDO userDO : userDOList) {
UserVO userVO = new UserVO();
userVO.setId(userDO.getId());
…
userVOList.add(userVO);
}
### 14. 不可变的静态常量,尽量使用非线程安全类
反例:
public static final Map<String, Class> CLASS_MAP;
static {
Map<String, Class> classMap = new ConcurrentHashMap<>(16);
classMap.put(“VARCHAR”, java.lang.String.class);
…
CLASS_MAP = Collections.unmodifiableMap(classMap);
}
正例:
public static final Map<String, Class> CLASS_MAP;
static {
Map<String, Class> classMap = new HashMap<>(16);
classMap.put(“VARCHAR”, java.lang.String.class);
…
CLASS_MAP = Collections.unmodifiableMap(classMap);
}
### 15. 尽量避免定义不必要的子类
**多一个类就需要多一份类加载,所以尽量避免定义不必要的子类**
反例:
public static final Map<String, Class> CLASS_MAP =
Collections.unmodifiableMap(new HashMap<String, Class>(16) {
private static final long serialVersionUID = 1L;
{
put(“VARCHAR”, java.lang.String.class);
}
});
正例:
public static final Map<String, Class> CLASS_MAP;
static {
Map<String, Class> classMap = new HashMap<>(16);
classMap.put(“VARCHAR”, java.lang.String.class);
…
CLASS_MAP = Collections.unmodifiableMap(classMap);
}
### 16. 尽量指定类的final修饰符
**为类指定final修饰符,可以让该类不可以被继承。如果指定了一个类为final,则该类所有的方法都是final的,Java编译器会寻找机会内联所有的final方法**
反例:
public class DateHelper {
…
}
正例:
public final class DateHelper {
…
}
### 17. 把跟类成员变量无关的方法声明成静态方法
**静态方法的好处就是不用生成类的实例就可以直接调用。静态方法不再属于某个对象,而是属于它所在的类**
反例:
public int getMonth(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
return calendar.get(Calendar.MONTH) + 1;
}
正例:
public static int getMonth(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
return calendar.get(Calendar.MONTH) + 1;
}
### 18. 尽量使用基本数据类型作为方法参数类型,避免不必要的装箱、拆箱和空指针判断
反例:
public static double sum(Double value1, Double value2) {
double double1 = Objects.isNull(value1) ? 0.0D : value1;
double double2 = Objects.isNull(value2) ? 0.0D : value2;
return double1 + double2;
}
double result = sum(1.0D, 2.0D);
正例:
public static double sum(double value1, double value2) {
return value1 + value2;
}
double result = sum(1.0D, 2.0D);
### 19. 协议方法参数值非空,避免不必要的空指针判断
**协议编程,可以@NonNull和@Nullable标注参数**
反例:
public static boolean isValid(UserDO user) {
if (Objects.isNull(user)) {
return false;
}
return Boolean.TRUE.equals(user.getIsValid());
}
正例:
public static boolean isValid(@NonNull UserDO user) {
return Boolean.TRUE.equals(user.getIsValid());
}
### 20. 尽量避免不必要的函数封装
**方法调用会引起入栈和出栈,导致消耗更多的CPU和内存,应当尽量避免不必要的函数封装。当然,为了使代码更简洁、更清晰、更易维护,增加一定的方法调用所带来的性能损耗是值得的**
反例:
// 函数封装
public static boolean isVip(Boolean isVip) {
return Boolean.TRUE.equals(isVip);
}
// 使用代码
boolean isVip = isVip(user.getVip());
正例:
boolean isVip = Boolean.TRUE.equals(user.getVip());
### 21. 尽量减少方法的重复调用
反例:
List userList = …;
for (int i = 0; i < userList.size(); i++) {
…
}
正例:
List userList = …;
int userLength = userList.size();
for (int i = 0; i < userLength; i++) {
…
}
### 22. 尽量使用移位来代替正整数乘除
**用移位操作可以极大地提高性能。对于乘除2^n(n为正整数)的正整数计算,可以用移位操作来代替**
反例:
int num1 = a * 4;
int num2 = a / 4;
正例:
int num1 = a << 2;
int num2 = a >> 2;
### 23. 尽量不在条件表达式中使用!取反
**使用!取反会多一次计算,如果没有必要则优化掉**
反例:
if (!(a >= 10)) {
… // 条件处理1
} else {
… // 条件处理2
}
正例:
if (a < 10) {
… // 条件处理1
} else {
… // 条件处理2
}
### 24. 对于多常量选择分支,尽量使用switch语句而不是if-else语句
**if-else语句,每个if条件语句都要加装计算,直到if条件语句为true为止。switch语句进行了跳转优化,Java中采用tableswitch或lookupswitch指令实现,对于多常量选择分支处理效率更高。经过试验证明:在每个分支出现概率相同的情况下,低于5个分支时if-else语句效率更高,高于5个分支时switch语句效率更高**
反例:
if (i == 1) {
…; // 分支1
} else if (i == 2) {
…; // 分支2
} else if (i == …) {
…; // 分支n
} else {
…; // 分支n+1
}
正例:
switch (i) {
case 1 :
… // 分支1
break;
case 2 :
… // 分支2
break;
case … :
… // 分支n
break;
default :
… // 分支n+1
break;
}
### 25. 尽量不要使用正则表达式匹配
**正则表达式匹配效率较低,尽量使用字符串匹配操作**
反例:
String source = “a::1,b::2,c::3,d::4”;
String target = source.replaceAll(“::”, “=”);
Stringp[] targets = source.spit(“::”);
正例:
String source = “a::1,b::2,c::3,d::4”;
String target = source.replace(“::”, “=”);
Stringp[] targets = StringUtils.split(source, “::”);
### 26. 不要使用循环拷贝数组,尽量使用System.arraycopy拷贝数组
**推荐使用System.arraycopy拷贝数组,也可以使用Arrays.copyOf拷贝数组**
反例:
int[] sources = new int[] {1, 2, 3, 4, 5};
int[] targets = new int[sources.length];
for (int i = 0; i < targets.length; i++) {
targets[i] = sources[i];
}
正例:
int[] sources = new int[] {1, 2, 3, 4, 5};
int[] targets = new int[sources.length];
System.arraycopy(sources, 0, targets, 0, targets.length);
### 27. 集合转化为类型T数组时,尽量传入空数组T[0]
**将集合转换为数组有2种形式:toArray(new T[n])和toArray(new T[0])。在旧的Java版本中,建议使用toArray(new T[n]),因为创建数组时所需的反射调用非常慢。在OpenJDK6后,反射调用是内在的,使得性能得以提高,toArray(new T[0])比toArray(new T[n])效率更高。此外,toArray(new T[n])比toArray(new T[0])多获取一次列表大小,如果计算列表大小耗时过长,也会导致toArray(new T[n])效率降低**
反例:
List integerList = Arrays.asList(1, 2, 3, 4, 5, …);
Integer[] integers = integerList.toArray(new Integer[integerList.size()]);
正例:
List integerList = Arrays.asList(1, 2, 3, 4, 5, …);
Integer[] integers = integerList.toArray(new Integer[0]); // 勿用new Integer[]{}
### 28. 不要使用循环拷贝集合,尽量使用JDK提供的方法拷贝集合
**JDK提供的方法可以一步指定集合的容量,避免多次扩容浪费时间和空间。同时,这些方法的底层也是调用System.arraycopy方法实现,进行数据的批量拷贝效率更高**
反例:
List user1List = …;
List user2List = …;
List userList = new ArrayList<>(user1List.size() + user2List.size());
for (UserDO user1 : user1List) {
userList.add(user1);
}
for (UserDO user2 : user2List) {
userList.add(user2);
}
正例:
List user1List = …;
List user2List = …;
List userList = new ArrayList<>(user1List.size() + user2List.size());
userList.addAll(user1List);
userList.addAll(user2List);
### 29. 尽量重复使用同一缓冲区
**针对缓冲区,Java虚拟机需要花时间生成对象,还要花时间进行垃圾回收处理。所以,尽量重复利用缓冲区**
反例:
StringBuilder builder1 = new StringBuilder(128);
builder1.append(“update t_user set name = '”).append(userName).append("’ where id = ").append(userId);
statement.executeUpdate(builder1.toString());
StringBuilder builder2 = new StringBuilder(128);
builder2.append("select id, name from t_user where id = ").append(userId);
ResultSet resultSet = statement.executeQuery(builder2.toString());
…
正例:
StringBuilder builder = new StringBuilder(128);
builder.append(“update t_user set name = '”).append(userName).append("’ where id = ").append(userId);
statement.executeUpdate(builder.toString());
builder.setLength(0);
builder.append("select id, name from t_user where id = ").append(userId);
ResultSet resultSet = statement.executeQuery(builder.toString());
…
### 30. 尽量使用缓冲流减少IO操作
**使用缓冲流BufferedReader、BufferedWriter、BufferedInputStream、BufferedOutputStream等,可以大幅较少IO次数并提升IO速度**
反例:
try (FileInputStream input = new FileInputStream(“a”);
FileOutputStream output = new FileOutputStream(“b”)) {
int size = 0;
byte[] temp = new byte[1024];
while ((size = input.read(temp)) != -1) {
output.write(temp, 0, size);
}
} catch (IOException e) {
log.error(“复制文件异常”, e);
}
正例:
try (BufferedInputStream input = new BufferedInputStream(new FileInputStream(“a”));
BufferedOutputStream output = new BufferedOutputStream(new FileOutputStream(“b”))) {
int size = 0;
byte[] temp = new byte[1024];
while ((size = input.read(temp)) != -1) {
output.write(temp, 0, size);
}
} catch (IOException e) {
log.error(“复制文件异常”, e);
}
### 31. 在单线程中,尽量使用非线程安全类
反例:
StringBuffer buffer = new StringBuffer(128);
buffer.append(“select * from “).append(T_USER).append(” where id = ?”);
正例:
StringBuilder buffer = new StringBuilder(128);
buffer.append(“select * from “).append(T_USER).append(” where id = ?”);
### 31. 在多线程中,尽量使用线程安全类
反例:
private volatile int counter = 0;
public void access(Long userId) {
synchronized (this) {
counter++;
}
…
}
正例:
private final AtomicInteger counter = new AtomicInteger(0);
public void access(Long userId) {
counter.incrementAndGet();
…
}
### 32. 尽量减少同步代码块范围
**在一个方法中,可能只有一小部分的逻辑是需要同步控制的,如果同步控制了整个方法会影响执行效率。所以,尽量减少同步代码块的范围,只对需要进行同步的代码进行同步**
反例:
private volatile int counter = 0;
public synchronized void access(Long userId) {
counter++;
… // 非同步操作
}
正例:
private volatile int counter = 0;
public void access(Long userId) {
synchronized (this) {
counter++;
}
… // 非同步操作
}
### 33. 尽量使用线程池减少线程开销
**多线程中两个必要的开销:线程的创建和上下文切换。采用线程池,可以尽量地避免这些开销**
反例:
public void executeTask(Runnable runnable) {
new Thread(runnable).start();
}
正例:
private static final ExecutorService EXECUTOR_SERVICE = Executors.newFixedThreadPool(10);
public void executeTask(Runnable runnable) {
executorService.execute(runnable);
}
## 让代码更优雅
### 1. 长整型常量后添加大写 L
反例:
long value = 1l;
long max = Math.max(1L, 5);
正例:
long value = 1L;
long max = Math.max(1L, 5L);
### 2. 不要使用魔法值
反例:
for (int i = 0; i < 100; i++){
…
}
if (a == 100) {
…
}
正例:
private static final int MAX_COUNT = 100;
for (int i = 0; i < MAX_COUNT; i++){
…
}
if (count == MAX_COUNT) {
…
}
### 3. 不要使用集合实现来赋值静态成员变量
反例:
private static Map<String, Integer> map = new HashMap<String, Integer>() {
{
put(“a”, 1);
put(“b”, 2);
}
};
private static List list = new ArrayList() {
{
add(“a”);
add(“b”);
}
};
正例:
private static Map<String, Integer> map = new HashMap<>();
static {
map.put(“a”, 1);
map.put(“b”, 2);
};
private static List list = new ArrayList<>();
static {
list.add(“a”);
list.add(“b”);
};
### 4. 建议使用 try-with-resources 语句
反例:
private void handle(String fileName) {
BufferedReader reader = null;
try {
String line;
reader = new BufferedReader(new FileReader(fileName));
while ((line = reader.readLine()) != null) {
…
}
} catch (Exception e) {
…
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
…
}
}
}
}
正例:
private void handle(String fileName) {
try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) {
String line;
while ((line = reader.readLine()) != null) {
…
}
} catch (Exception e) {
…
}
}
### 5. 删除未使用的方法、参数、变量
反例:
public class DoubleDemo1 {
private int unusedField = 100;
private void unusedMethod() {
…
}
public int sum(int a, int d, int d) {
int c = 100;
return a + b;
}
}
正例:
public class DoubleDemo1 {
public int sum(int a, int b) {
return a + b;
}
}
### 6. 公有静态常量应该通过类访问
反例:
public class User {
public static final String CONST_NAME = “name”;
…
}
User user = new User();
String nameKey = user.CONST_NAME;
正例:
public class User {
public static final String CONST_NAME = “name”;
…
}
String nameKey = User.CONST_NAME;
### 7. 使用String.valueOf(value)代替""+value
反例:
int i = 1;
String s = “” + i;
正例:
int i = 1;
String s = String.valueOf(i);
### 8. 过时代码添加 @Deprecated 注解
正例:
/**
* @deprecated 此方法效率较低,请使用{@link newSave()}方法替换它
*/
@Deprecated
public void save(){
// do something
}
### 9. 尽量避免在循环中捕获异常
反例:
public Double sum(List valueList) {
double sum = 0.0D;
for (String value : valueList) {
try {
sum += Double.parseDouble(value);
} catch (NumberFormatException e) {
return null;
}
}
return sum;
}
正例:
public Double sum(List valueList) {
double sum = 0.0D;
try {
for (String value : valueList) {
sum += Double.parseDouble(value);
}
} catch (NumberFormatException e) {
return null;
}
return sum;
}
## 让代码远离 bug
### 1. 禁止使用构造方法 BigDecimal(double)
反例:
BigDecimal value = new BigDecimal(0.1D); // 0.100000000000000005551115…
正例:
BigDecimal value = BigDecimal.valueOf(0.1D);; // 0.1
写在最后
可能有人会问我为什么愿意去花时间帮助大家实现求职梦想,因为我一直坚信时间是可以复制的。我牺牲了自己的大概十个小时写了这片文章,换来的是成千上万的求职者节约几天甚至几周时间浪费在无用的资源上。
上面的这些(算法与数据结构)+(Java多线程学习手册)+(计算机网络顶级教程)等学习资源
例:
public Double sum(List<String> valueList) {
double sum = 0.0D;
try {
for (String value : valueList) {
sum += Double.parseDouble(value);
}
} catch (NumberFormatException e) {
return null;
}
return sum;
}
让代码远离 bug
1. 禁止使用构造方法 BigDecimal(double)
反例:
BigDecimal value = new BigDecimal(0.1D); // 0.100000000000000005551115...
正例:
BigDecimal value = BigDecimal.valueOf(0.1D);; // 0.1
# 写在最后
可能有人会问我为什么愿意去花时间帮助大家实现求职梦想,因为我一直坚信时间是可以复制的。我牺牲了自己的大概十个小时写了这片文章,换来的是成千上万的求职者节约几天甚至几周时间浪费在无用的资源上。
[外链图片转存中...(img-EnjVtrCw-1715077534842)]
[外链图片转存中...(img-Sl3sXj3y-1715077534842)]
> 上面的这些(算法与数据结构)+(Java多线程学习手册)+(计算机网络顶级教程)等学习资源
> **本文已被[CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)收录**
**[需要这份系统化的资料的朋友,可以点击这里获取](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)**