专业的JAVA编程教程与资源

网站首页 > java教程 正文

Java编程的那些屎山代码分析之二_java 代码

temp10 2025-02-18 13:26:16 java教程 10 ℃ 0 评论

以下是个人总结的一些代码习惯问题和优化,单独一个也许不起眼,但堆积起来,就让一个项目代码变成一座屎山。


Java编程的那些屎山代码分析之二_java 代码


1.滥用`public`修饰符

? 重要性:滥用`public`修饰符可能导致类的成员变量或方法被不恰当地公开,增加不必要的暴露和模块间的耦合。? 避免方法:默认使用`private`或`package-private`访问控制符,仅当需要外部访问时提供公共的 getter 和 setter 方法。

举个正例:

public class MyClass {
? private int value;
? public int getValue() { return value; }
? public void setValue(int value) { this.value = value; }
}

举个反例:

public class MyClass {
  public int value;
}



2.字符串拼接使用`+`


? 重要性:在循环中使用`+`进行字符串拼接可能导致性能问题,因为每次拼接都会创建新的字符串对象。? 避免方法:使用`StringBuilder`或`String.format`来提高性能。

举个正例:

StringBuilder result = new StringBuilder();
for (int i = 0; i < 1000; i++) {
? result.append(i);
}

举个反例:

String result = "";
for (int i = 0; i < 1000; i++) {
? result += i;
}



3.在多线程中共享可变状态


? 重要性:在多线程环境中共享可变状态可能导致线程安全问题。? 避免方法:使用不可变对象或通过同步机制来管理状态。

举个正例:

import java.util.concurrent.atomic.AtomicInteger;

class Counter {
? private AtomicInteger count = new AtomicInteger(0);
? public int increment() {
??? return count.incrementAndGet();
? }
}

举个反例:

class Counter {
? int count = 0;
}



4.在集合中使用原始类型

? 重要性:使用原始类型可能导致`ClassCastException`。? 避免方法:使用泛型来避免类型转换问题。

举个正例:

List list = new ArrayList<>();
list.add("test");
String str = list.get(0);

举个反例:

List list = new ArrayList();
list.add("test");
String str = (String) list.get(0);



5.使用硬编码字符串

? 重要性:硬编码字符串使得代码难以维护和国际化。? 避免方法:使用常量或资源文件来管理字符串。

举个正例:

public static final String ADMIN = "admin";
if (userType.equals(ADMIN)) {
? // do something
}

举个反例:

if (userType.equals("admin")) {
? // do something
}



6.不使用日志框架

? 重要性:不使用日志框架可能导致调试和问题跟踪困难。? 避免方法:使用如 SLF4J 或 Log4j 等日志框架。

举个正例:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

private static final Logger logger = LoggerFactory.getLogger(MyClass.class);
logger.error("错误信息");

举个反例:

System.out.println("错误信息");



7.错误使用浮点数进行比较题

? 错误使用浮点数进行比较? 重要性:直接比较浮点数可能导致逻辑错误,因为浮点数的精度问题。? 避免方法:使用误差范围进行比较。

举个正例:

if (Math.abs(0.1 + 0.2 - 0.3) < 1e-9) {
? System.out.println("相等");
}

举个反例:

if (0.1 + 0.2 == 0.3) {
? System.out.println("相等");
}



8.循环中创建对象

? 重要性:在循环中创建对象可能导致性能问题和内存浪费。? 避免方法:将对象初始化移到循环外部。

举个正例:

StringBuilder sb = new StringBuilder();
for (int i = 0; i < 100; i++) {
? sb.append(i);
}

举个反例:

for (int i = 0; i < 100; i++) {
? StringBuilder sb = new StringBuilder();
}



9.过度依赖静态变量

? 重要性:过度依赖静态变量可能导致线程不安全。? 避免方法:限制静态变量的使用,优先使用实例变量或线程本地变量。

举个正例:

private int counter = 0;

举个反例:

public static int counter = 0;



10.不规范的命名

? 重要性:不规范的命名降低代码可读性。? 避免方法:遵循命名规范,如 CamelCase。

举个正例:

public void getData() { }

举个反例:

public void GETdata() { }



11.滥用反射

? 重要性:滥用反射可能导致性能差且不安全。? 避免方法:仅在必要时使用反射。

举个正例:

List list = new ArrayList<>();

举个反例:

Class clazz = Class.forName("java.util.ArrayList");
Object obj = clazz.newInstance();



12.在集合中存放过多元素

? 重要性:存放过多元素可能导致内存溢出。? 避免方法:设置合理的容量或限制集合大小。

举个正例:

List list = new ArrayList<>(1000); // 添加有限数量的元素

举个反例:

List list = new ArrayList<>();
for (int i = 0; i < Integer.MAX_VALUE; i++) {
  list.add(i);
}



13.使用双重检查锁定时未声明`volatile`

? 重要性:未声明`volatile`可能导致线程安全问题。? 避免方法:使用`volatile`或枚举单例模式。

举个正例:

class Singleton {
? private static volatile Singleton instance;
? public static Singleton getInstance() {
??? if (instance == null) {
????? synchronized (Singleton.class) {
??????? if (instance == null) {
????????? instance = new Singleton();
??????? }
????? }
??? }
??? return instance;
? }
}

举个反例:

class Singleton {
? private static Singleton instance;
? public static Singleton getInstance() {
??? if (instance == null) {
????? synchronized (Singleton.class) {
??????? if (instance == null) {
????????? instance = new Singleton();
??????? }
????? }
??? }
??? return instance;
? }
}



14.直接暴露内部数据结构

? 重要性:直接暴露内部数据结构容易破坏封装性。? 避免方法:提供不可变集合或深拷贝。

举个正例:

public List getItems() {
? return Collections.unmodifiableList(items);
}

举个反例:

public List getItems() {
? return items;
}



15. 滥用`instanceof`

? 重要性:滥用`instanceof`可能导致代码难以维护。? 避免方法:使用多态。

举个正例:

abstract class Shape {
? abstract void draw();
}
class Circle extends Shape {
? void draw() {
??? System.out.println("Drawing Circle");
? }
}
Shape shape = new Circle();
shape.draw();

举个反例:

if (obj instanceof Circle) {
? Circle circle = (Circle) obj;
? circle.draw();
}



16.在`HashMap`中使用可变键

? 重要性:使用可变键可能导致数据丢失或行为异常。? 避免方法:使用不可变对象作为键。

举个正例:

Map map = new HashMap<>();
String key = "constantKey";
map.put(key, "value");
System.out.println(map.get(key)); // 返回 value

举个反例:

Map, String> map = new HashMap<>();
List key = new ArrayList<>();
map.put(key, "value");
key.add("newKey");
System.out.println(map.get(key)); // 可能返回 null



17.直接调用线程的`run()`方法

? 重要性:直接调用`run()`方法可能导致逻辑错误,原因详见备注1。


? 避免方法:使用`start()`方法启动线程。

举个正例:

Thread thread = new Thread(() -> System.out.println("Running"));
thread.start();

举个反例:

Thread thread = new Thread(() -> System.out.println("Running"));
thread.run();



18.滥用`System.exit()`

? 重要性:滥用`System.exit()`可能导致资源未释放。? 避免方法:避免使用`System.exit()`,正常流程中结束程序。

举个正例:

if (error) {
? throw new RuntimeException("程序出现错误");
}

举个反例:

if (error) {
? System.exit(1);
}



19.在循环中频繁调用`get`方法

? 重要性:频繁调用`get`方法可能导致性能问题。? 避免方法:使用局部变量存储返回值。

举个正例:

List list = new ArrayList<>();
int size = list.size();
for (int i = 0; i < size; i++) {
? System.out.println(list.get(i));
}

举个反例:

List list = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
? System.out.println(list.get(i));
}



20.在同步代码块中使用`String`锁

? 重要性:使用`String`锁可能引发死锁。? 避免方法:使用私有的锁对象。

举个正例:

代码private final Object lock = new Object();
synchronized (lock) {
  System.out.println("Locked");
}

举个反例:

synchronized ("lock") {
? System.out.println("Locked");
}



21.使用过时的类或方法

? 重要性:使用过时的类或方法可能存在安全问题或性能低下。? 避免方法:使用现代替代方案。

举个正例:

LocalDate date = LocalDate.of(202

举个反例:

Date date = new Date(2022, 1, 1);



22.未对集合进行空检查


? 重要性:未进行空检查可能引发`NullPointerException`。? 避免方法:使用`Objects.isNull`或`Objects.nonNull`检查。

举个正例:

import java.util.Objects;

List list = null;
if (Objects.nonNull(list)) {
??? System.out.println(list.size());
}
//或者使用Java 8 的 Optional 类来避免空检查:
import java.util.List;
import java.util.Optional;
List list = null;
Optional.ofNullable(list).ifPresent(l -> System.out.println(l.size()));

举个反例:

List list = null;
System.out.println(list.size());



23.递归调用未限制深度

? 重要性:未限制深度可能导致栈溢出。? 避免方法:添加递归终止条件或改为迭代。

举个正例:

void recursive(int depth) {
??? if (depth == 0) return;
??? recursive(depth - 1);
}

举个反例:

void recursive() {
??? recursive();
}




备注:

一,线程使用run方法执行的问题

1. 生命周期管理:

? 当你创建一个线程并调用其 run() 方法时,这个线程并没有被当作一个线程来执行,而是作为一个普通的对象方法调用。这意味着线程的生命周期并没有被正确管理,它没有被放置在线程调度器的控制之下。

? 线程的启动和执行应该由 Java 虚拟机(JVM)的线程调度器来管理。通过调用 start() 方法而不是 run() 方法,线程会被正确地放入 JVM 的线程调度队列中,按照线程的优先级和调度策略被执行。


2. 并发执行:

? start() 方法会创建一个新的线程,并在这个新线程中调用 run() 方法,从而实现并发执行。这意味着主线程和新线程可以同时运行,这是多线程编程的核心优势之一。

? 如果直接调用 run() 方法,就不会创建新的线程, run() 方法的执行会阻塞当前线程,直到 run() 方法执行完成,这失去了并发执行的意义。

3. 线程局部变量:

? 在多线程环境中,线程局部变量(ThreadLocal)是每个线程独有的,它们通过 start() 方法启动的线程来隔离和管理。

? 如果直接调用 run() 方法,线程局部变量可能不会按预期工作,因为实际上并没有创建新线程,因此无法保证变量的线程安全性和隔离性。

4. 异常处理:

? 当线程通过 start() 方法启动时,在其 run() 方法中抛出的任何未捕获异常都会作为线程的运行时异常被捕获,并且可以通过 getStackTrace() 方法从外部获取堆栈跟踪,这有助于调试。

? 如果直接调用 run() 方法,任何在 run() 方法中抛出的异常都会导致当前线程(可能是主线程)崩溃,这可能导致程序的其他部分无法正常执行,并且可能使得异常处理更加困难。



如果不注意以上相关规范,写出这样一座屎山代码,对后续接手的人来说,是多大的伤害啊!


本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表