Java最新Java优雅编码(持续更新)_java 优雅编码,java面试两年工作经验的

总结

阿里伤透我心,疯狂复习刷题,终于喜提offer 哈哈~好啦,不闲扯了

image

1、JAVA面试核心知识整理(PDF):包含JVMJAVA集合JAVA多线程并发,JAVA基础,Spring原理微服务,Netty与RPC,网络,日志,ZookeeperKafkaRabbitMQ,Hbase,MongoDB,Cassandra,设计模式负载均衡数据库一致性哈希JAVA算法数据结构,加密算法,分布式缓存,Hadoop,Spark,Storm,YARN,机器学习,云计算共30个章节。

image

2、Redis学习笔记及学习思维脑图

image

3、数据面试必备20题+数据库性能优化的21个最佳实践

image

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

if (list.containsAll(list)) { // 无意义,总是返回true

}
list.removeAll(list); // 性能差, 直接使用clear()


### 4. 集合初始化尽量指定大小


**Java集合初始化时都会指定一个默认大小,当默认大小不再满足数据需求时就会扩容,每次扩容的时间复杂度有可能是O(n)**  
 反例:



List userDOList = …;
Set userSet = new HashSet<>();
Map<Long, UserDO> userMap = new HashMap<>();
List userList = new ArrayList<>();
for (UserDO userDO : userDOList) {
userSet.add(userDO.getId());
userMap.put(userDO.getId(), userDO);
userList.add(transUser(userDO));
}


正例:



List userDOList = …;
int userSize = userDOList.size();
Set userSet = new HashSet<>(userSize);
Map<Long, UserDO> userMap = new HashMap<>((int) Math.ceil(userSize * 4.0 / 3));
List userList = new ArrayList<>(userSize);
for (UserDO userDO : userDOList) {
userSet.add(userDO.getId());
userMap.put(userDO.getId(), userDO);
userList.add(transUser(userDO));
}


### 5. 字符串拼接使用 StringBuilder


反例:



String s = “”;
for (int i = 0; i < 10; i++) {
s += i;
}


正例:



String a = “a”;
String b = “b”;
String c = “c”;
String s = a + b + c; // 没问题,java编译器会进行优化
StringBuilder sb = new StringBuilder(50); //尽量设置初始化大小
for (int i = 0; i < 10; i++) {
sb.append(i);
}


### 6. 判断链表还是数组


正例:



// 调用别人的服务获取到list
List list = otherService.getList();
if (list instanceof RandomAccess) {
// 内部数组实现,可以随机访问
System.out.println(list.get(list.size() - 1));
} else {
// 内部可能是链表实现,随机访问效率低
}


### 7. 频繁调用 Collection.contains 方法请使用 Set


反例:



ArrayList list = otherService.getList();
for (int i = 0; i <= Integer.MAX_VALUE; i++) {
// 时间复杂度O(n)
list.contains(i);
}


正例:



ArrayList list = otherService.getList();
Set set = new HashSet(list);
for (int i = 0; i <= Integer.MAX_VALUE; i++) {
// 时间复杂度O(1)
set.contains(i);
}


### 8. 直接赋值常量值,禁止声明新对象


**直接赋值常量值,只是创建了一个对象引用,而这个对象引用指向常量值。**  
 反例:



Long i = new Long(1L);
String s = new String(“abc”);


正例:



Long i = 1L;
String s = “abc”;


### 9. 当成员变量值无需改变时,尽量定义为静态常量


**在类的每个对象实例中,每个成员变量都有一份副本,而成员静态常量只有一份实例**  
 反例:



public class HttpConnection {
private final long timeout = 5L;

}


正例:



public class HttpConnection {
private static final long TIMEOUT = 5L;

}


### 10. 尽量使用基本数据类型,避免自动装箱和拆箱


**装箱和拆箱都是需要CPU和内存资源的,所以应尽量避免使用自动装箱和拆箱**  
 反例:



Integer sum = 0;
int[] values = …;
for (int value : values) {
sum += value; // 相当于result = Integer.valueOf(result.intValue() + value);
}


正例:



int sum = 0;
int[] values = …;
for (int value : values) {
sum += value;
}


### 11. 如果变量的初值会被覆盖,就没有必要给变量赋初值


反例:



List userList = new ArrayList<>();
if (isAll) {
userList = userDAO.queryAll();
} else {
userList = userDAO.queryActive();
}


正例:



List userList;
if (isAll) {
userList = userDAO.queryAll();
} else {
userList = userDAO.queryActive();
}


### 12. 尽量使用函数内的基本类型临时变量


**在函数内,基本类型的参数和临时变量都保存在栈(Stack)中,访问速度较快;对象类型的参数和临时变量的引用都保存在栈(Stack)中,内容都保存在堆(Heap)中,访问速度较慢。在类中,任何类型的成员变量都保存在堆(Heap)中,访问速度较慢**  
 反例:



public final class Accumulator {
private double result = 0.0D;
public void addAll(@NonNull double[] values) {
for(double value : values) {
result += value;
}
}

}


正例:



public final class Accumulator {
private double result = 0.0D;
public void addAll(@NonNull double[] values) {
double sum = 0.0D;
for(double value : values) {
sum += value;
}
result += sum;
}

}


### 13. 尽量不要在循环体外定义变量


**在老版JDK中,建议“尽量不要在循环体内定义变量”,但是在新版的JDK中已经做了优化,根据“ 局部变量作用域最小化 ”原则,变量定义在循环体内更科学更便于维护,避免了延长大对象生命周期导致延缓回收问题**  
 反例:



UserVO userVO;
List userDOList = …;
List userVOList = new ArrayList<>(userDOList.size());
for (UserDO userDO : userDOList) {
userVO = new UserVO();
userVO.setId(userDO.getId());

userVOList.add(userVO);
}


正例:



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);

最后

码字不易,觉得有帮助的可以帮忙点个赞,让更多有需要的人看到

又是一年求职季,在这里,我为各位准备了一套Java程序员精选高频面试笔试真题,来帮助大家攻下BAT的offer,题目范围从初级的Java基础到高级的分布式架构等等一系列的面试题和答案,用于给大家作为参考

以下是部分内容截图
架构面试专题及架构学习笔记导图.png

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

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);

最后

码字不易,觉得有帮助的可以帮忙点个赞,让更多有需要的人看到

又是一年求职季,在这里,我为各位准备了一套Java程序员精选高频面试笔试真题,来帮助大家攻下BAT的offer,题目范围从初级的Java基础到高级的分布式架构等等一系列的面试题和答案,用于给大家作为参考

以下是部分内容截图
[外链图片转存中…(img-W9tRS9HS-1715375304004)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值