1.Blocker规则(共14个)
编号 | 规则描述 | 不规范代码示例 | 建议修改 | 备注 |
---|---|---|---|---|
1 |
.equals()不能用在AtomicInteger、AtomicLong等原子类型的比较中 |
AtomicInteger aInt1 = new AtomicInteger(0); AtomicInteger aInt2 = new AtomicInteger(0); if (aInt1.equals(aInt2)) { ... } // 返回false |
如需比较,可先用原子类的.get()方法获得其值 if (aInt1.get() == aInt2.get()) { ... } | |
2 |
Double.longBitsToDouble不能处理int型变量
|
int i = 42; double d = Double.longBitsToDouble(i); // d=4.6311077918204232E18 |
int i = 42; double d =(double) i; // d=42.0 | |
3 |
equals(Object obj)和hashCode()必须同时被重写,以保证相等对象生成相等的哈希码(如果不重写hashCode方法,Object对象中的hashCode方法始终返回的是一个对象的hash地址,而这个地址是永远不相等的。所以这时候即使是重写了equals方法,也不会有特定的效果的) |
class MyClass { @Override public boolean equals(Object obj) { /* ... */ } // 没有重写hasCode方法 } |
class MyClass { @Override public boolean equals(Object obj) { /* ... */ } @Override public int hashCode() { /* ... */ } } | |
4 |
Iterator.hasNext()不应该写成Iterator.next(),而是hasNext(),因为hasNext()不会改变迭代器的状态, next()返回当前元素 hasNext()判断当前元素是否存在 |
@Override public boolean hasNext() {
if(next() != null) { // iterator为空的时候会出错
return true;
}
return false;
}
|
@Override public boolean hasNext() { if(hasNext() != null) { return true; } return false; } | |
5 |
Lock objects 不应该是synchronized的,synchronized会限制锁的灵活性 |
Lock lock = new MyLockImpl(); synchronized(lock) { // 会限制锁的灵活性 //... } |
Lock lock = new MyLockImpl(); lock.tryLock(); //... | |
6 |
同步锁:synchronized(xx),xx必须是object,不能是String,Integer等 |
private static final String sLock = "LOCK";
public void doSomething() {
synchronized(sLock) { //不能synchronized String变量
// ... } |
private static final Object sLock = "LOCK"; public void doSomething() { synchronized(sLock) { // ... } | |
7 |
java.util.concurrent.locks.Condition不能与wait()共同使用,可用await代替wait,因为await方法里加入了lock的东西,Condition与lock组合,代替了synchronized |
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
...
notFull.wait(); //wait方法里没有lock的概念
|
final Lock lock = new ReentrantLock(); final Condition notFull = lock.newCondition(); ... notFull.await(); | |
8 |
wait(...), notify()和notifyAll()不应该用在线程实例里,JVM依靠它们改变线程的状态,调用它们将会破坏JVM的行为 |
Thread myThread = new Thread(new RunnableJob());
...
myThread.wait(2000); //调用wait()会破坏JVM的行为
|
Thread myThread = new Thread(new RunnableJob()); ... myThread.sleep(2000); | |
9 |
ScheduledThreadPoolExecutor不能设置0个主线程 |
public void do(){ ScheduledThreadPoolExecutor stpe1 = new ScheduledThreadPoolExecutor(0); ScheduledThreadPoolExecutor stpe2 = new ScheduledThreadPoolExecutor(POOL_SIZE); stpe2.setCorePoolSize(0); //主线程池不能是0个
} |
stpe2.setCorePoolSize(n); //n>0 | |
10 |
finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值 |
public static void doSomethingWhichThrowsException() {
try {
throw new RuntimeException();
} finally {
/* ... */
return; //程序提前退出,返回值不是try或catch中的值
}
}
|
public static void doSomethingWhichThrowsException() { try { throw new RuntimeException(); } finally { /* ... */ } } | |
11 |
System.runFinalizersOnExit(true)是禁用的,因为该方法是不安全的,有可能导致死锁。 |
public static void main(String [] args) {
...
System.runFinalizersOnExit(true); //该方法是不安全的,可能导致死锁
...
}
protected void finalize(){
doSomething();
}
|
public static void main(String [] args) { Runtime.addShutdownHook(new Runnable() { public void run(){ doSomething(); } }); //... | |
12 |
super.finalize() 必须用在类的最后面,如果提前释放了,余下的方法执行可能会出错 |
protected void finalize() { releaseSomeResources(); //不用也是不合理的;
}
protected void finalize() {
super.finalize(); //没放在最后
releaseSomeResources();
}
|
protected void finalize() { releaseSomeResources(); super.finalize(); } | |
13 | for循环的计数器应该是正确的 |
for (int i = 0; i < strings.length; i--) { // i--不合法
String string = strings[i]; //... |
for (int i = 0; i < strings.length; i++) { String string = strings[i]; //... | |
14 |
Throwable不能被catch,否则会catch到系统未知的一些异常,导致try代码块里的程序执行受到影响 |
try { /* ... */ } catch (Throwable t) { /* ... */ } try { /* ... */ } catch (Error e) { /* ... */ } //会catch到系统未知的异常,导致try代码块里的程序受到影响
|
try { /* ... */ } catch (RuntimeException e) { /* ... */ } try { /* ... */ } catch (MyException e) { /* ... */ } |
2.Critical规则(共60个)
编号 | 规则描述 | 不规范代码示例 | 建议修改 | 备注 |
---|---|---|---|---|
1 |
BigDecimal主要处理超过16位有效位的数,一般用于商业计数,BigDecimal(double)不能使用,否则得不到想要的结果 |
double d = 1.1; BigDecimal bd1 = new BigDecimal(d); // bd1=1.10000000000000008881784 BigDecimal bd2 = new BigDecimal(1.1); //bd2=1.10000000000000008881784 |
double d = 1.1; BigDecimal bd1 = BigDecimal.valueOf(d); // bd1=1.1 BigDecimal bd2 = BigDecimal.valueOf(1.1); | |
2 |
Cloneables必须重写clone(),否则就会调用JVM的clone方法,导致clone不成功 |
class Team implements Cloneable { private Person coach; private List<Person> players; public void addPlayer(Person p) {...} public Person getCoach() {...} //没有重写clone() } |
class Team implements Cloneable { private Person coach; private List<Person> players; public void addPlayer(Person p) { ... } public Person getCoach() { ... } @Override public Object clone() { Team clone = (Team) super.clone(); //... } } | |
3 |
compareTo方法不能return Integer.MIN_VALUE,因为这样可能导致返回值从负数变为正数 |
public int compareTo(MyClass) { if (condition) { return Integer.MIN_VALUE; //不规范代码 } |
public int compareTo(MyClass) { if (condition) { return -1; } | |
4 |
ConcurrentLinkedQueue不能直接用size()方法,因为该队列的特殊性,确定当前元素的个数需要遍历这些元素 |
ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue(); //... //queue.size()不规范代码 log.info("Queue contains " + queue.size() + " elements"); | 遍历ConcurrentLinkedQueue | |
5 |
重写compareTo方法后应该重写equal方法,否则有可能发生未知错误,如Java5中PriorityQueue.remove()依赖compareTo方法,而Java6依赖equal方法 |
public class Foo implements Comparable<Foo> { @Override public int compareTo(Foo foo) { /* ... */ } //没有重写equal() } |
public class Foo implements Comparable<Foo> { @Override public int compareTo(Foo foo) { /* ... */ } @Override public boolean equals(Object obj) { /* ... */ } } | |
6 |
for循环的变量必须一致 |
for (i = 0; i < 10; j++) { //不规范代码 // ... } |
for (i = 0; i < 10; i++) { // ... } | |
7 | 数组的toString()和hashCode()方法应该传递给相关的静态数组方法 |
public static void main( String[] args ) { String argStr = args.toString(); //不规范代码 int argHash = args.hashCode(); //不规范代码 |
public static void main( String[] args ) { String argStr = Arrays.toString(args); int argHash = Arrays.hashCode(args); | |
8 |
HttpServletRequest.getRequestedSessionId()方法不应该使用,因为如果客户端没有指定会话标识,该方法会返回null |
if(isActiveSession(request.getRequestedSessionId()) ){ ... } | 可考虑用getSessionId()方法 | |
9 |
object == null,不应该写成object.equals(null) 因为如果写成equals,说明object的值是null |
if (variable.equals(null)) { /* ... */ } |
if (variable == null) { /* ... */ } | |
10 |
Object.wait(...)和Condition.await(...)应该放在while循环里而不是if循环里 |
synchronized (obj) { if (!suitableCondition()){ obj.wait(timeout); //条件是错的,线程依然有可能被唤起 } ... // Perform action appropriate to condition } |
synchronized (obj) { while (!suitableCondition()){ obj.wait(timeout); } ... // Perform action appropriate to condition } | |
12 |
public static常量必须是final型的 |
public class Greeter { public static Foo foo = new Foo(); ... } |
public class Greeter { public static final Foo FOO = new Foo(); ... } | |
13 |
不应该使用ResultSet.isLast(),因为结果集是空的时候,返回的值会出现问题 |
stmt.executeQuery("SELECT name, address FROM PERSON"); ResultSet rs = stmt.getResultSet(); while (! rs.isLast()) { //不规范代码 // process row } |
ResultSet rs = stmt.executeQuery("SELECT name, address FROM PERSON"); while (! rs.next()) { // process row } | |
14 | 在一个非序列化的类中实现内部类的序列化必须是静态的,否则会内部类序列化失败 |
public class Pomegranate { // ... public class Seed implements Serializable { // ... } } |
public class Pomegranate { // ... public static class Seed implements Serializable { // ... } } | |
15 |
数组前面如果加上final static,应该定义成private型的,final意味着数组只能被分配一次,public型数组依然有被恶意修改数组内容的风险 |
public class Estate { // 数组内容可被修改 public static final String [] HEIRS = new String [] { "Betty", "Suzy" }; } |
public class Estate { private static final String [] HEIRS = new String [] { "Betty", "Suzy" }; public String [] getHeirs() { // return copy of HEIRS } } | |
16 |
swith里面不应该包含非case标签 |
switch (day) { case MONDAY: case TUESDAY: WEDNESDAY: // 不规范代码 doSomething(); break; ... } |
switch (day) { case MONDAY: case TUESDAY: case WEDNESDAY: doSomething(); break; ... } | |
17 |
期望一个Runnables时不应该用Threads,因为Thread比Runnable范围广,一个Thread有可能包含其他Runnable |
public static void main(String[] args) { Thread r =new Thread() { //不规范代码 int p; @Override public void run() { while(true) System.out.println("a"); } }; new Thread(r).start(); // 不规范代码 |
public static void main(String[] args) { Runnable r =new Runnable() { int p; @Override public void run() { while(true) System.out.println("a"); } }; new Thread(r).start(); | |
18 |
toString()和clone()方法不能return null,因为这样不符合方法的隐形约束 |
public override string ToString () { if (this.collection.Count == 0) { return null; // 不规范代码 } else { // ... |
public override string ToString () { if (this.collection.Count == 0) { return ""; } else { // ... | |
19 |
应该用wait(...)代替Thread.sleep(...),否则可能会因线程的冻结而造成死锁 |
public void doSomething(){ synchronized(monitor) { while(notReady()){ Thread.sleep(200); //不规范代码 } process(); } ... } |
public void doSomething(){ synchronized(monitor) { while(notReady()){ monitor.wait(200); } process(); } ... } | |
20 | 集合的方法内应该传正确的参数 |
List<String> list = new ArrayList<String>(); Integer integer = Integer.valueOf(1); if (list.contains(integer)) { // Always false. list.remove(integer); // list.add(integer) doesn't compile, so this will always return false } | ||
21 | 不应该根据类名来获得对象类型,否则恶意用户会将同一名称的对象发送给受信任的类,从而获得信任访问。 |
package computer; class Pear extends Laptop { ... } package food; class Pear extends Fruit { ... } class Store { public boolean hasSellByDate(Object item) { if ("Pear".equals(item.getClass().getSimpleName())) { // 不规范代码 return true; } } } |
class Store { public boolean hasSellByDate(Object item) { if (item instanceof food.Pear) { return true; } } } | |
22 |
集合不应该作为参数传递给它们自己的方法,因为有可能程序执行过程中需要参数未修改,这样一来就会出现问题 |
List <Object> objs = new ArrayList<Object>(); objs.add("Hello"); objs.add(objs); // 不规范代码 | ||
23 |
Cookies 应该是安全的 |
Cookie c = new Cookie(SECRET, secret); // cookie不安全 response.addCookie(c); |
Cookie c = new Cookie(SECRET, secret); c.setSecure(true); //使Cookie安全 response.addCookie(c); | |
24 | 证书不应该被强制编码,因为很容易从一段程序中提取字符串,这样做不能保证安全性 |
Connection conn = null; try { conn = DriverManager.getConnection("jdbc:mysql://localhost/test?" + "user=steve&password=blue"); // 不规范代码 String uname = "steve"; String password = "blue"; conn = DriverManager.getConnection("jdbc:mysql://localhost/test?" + "user=" + uname + "&password=" + password); // 不规范代码 |
Connection conn = null; try { String uname = getEncryptedUser(); String password = getEncryptedPass(); conn = DriverManager.getConnection("jdbc:mysql://localhost/test?" + "user=" + uname + "&password=" + password); | |
25 |
RSA(公钥加密)算法应该包含OAEP(最优不对称加密填充),OAEP添加了随机元素使得其加密安全性更高 |
Cipher rsa = javax.crypto.Cipher.getInstance("RSA/NONE/NoPadding"); |
Cipher rsa = javax.crypto.Cipher.getInstance("RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING"); | |
26 |
自定义序列化方法签名应该满足需求,否则java会启动默认的序列化机制 |
public class Watermelon implements Serializable { // ... void writeObject(java.io.ObjectOutputStream out)// 应该是private throws IOException {...} private void readObject(java.io.ObjectInputStream in) {...} public void readObjectNoData() // Noncompliant; not private {...} static Object readResolve() throws ObjectStreamException // 方法可能被修改,不应该是static Watermelon writeReplace() throws ObjectStreamException //应该返回Object类型 {...} } |
public class Watermelon implements Serializable { // ... private void writeObject(java.io.ObjectOutputStream out) throws IOException {...} private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {...} private void readObjectNoData() throws ObjectStreamException {...} protected Object readResolve() throws ObjectStreamException {...} private Object writeReplace() throws ObjectStreamException {...} | |
27 | 不能使用未经显式转换的三元运算符 |
Integer i = 123456789; Float f = 1.0f; Number n = condition ? i : f; // n = 1.23456792E8 |
Integer i = 123456789; Float f = 1.0f; Number n = condition ? (Number) i : f; // n = 123456789 | |
28 |
异常处理时应该保持原有异常 |
// 不规范代码 try { /* ... */ } catch (Exception e) { LOGGER.info("context"); } // 不规范代码 try { /* ... */ } catch (Exception e) { LOGGER.info(e.getMessage()); } // 不规范代码 try { /* ... */ } catch (Exception e) { throw new RuntimeException("context"); } |
try { /* ... */ } catch (Exception e) { LOGGER.info(e); } try { /* ... */ } catch (Exception e) { throw new RuntimeException(e); } try { /* ... */ } catch (RuntimeException e) { doSomething(); throw e; } catch (Exception e) { // Conversion into unchecked exception is also allowed throw new RuntimeException(e); } | |
29 |
垃圾收集器的执行应当由JVM触发,手动触发不能保证在正确的时候回收 |
System.gc() 或者 Runtime.getRuntime().gc() | ||
30 | 不应该执行exit()方法,这样会退出整个java程序 |
System.exit(0); Runtime.getRuntime().exit(0); Runtime.getRuntime().halt(0); | ||
31 |
在一个序列化的类中,成员变量要么是短暂的要么是序列化的,因为可序列化的对象与非瞬态、非序列化的数据成员可能导致程序崩溃,并打开攻击者的大门 |
public class Address { //... } public class Person implements Serializable { private static final long serialVersionUID = 1905122041950251207L; private String name; private Address address; // Address类不是序列化的 } |
public class Address implements Serializable { private static final long serialVersionUID = 2405172041950251807L; } public class Person implements Serializable { private static final long serialVersionUID = 1905122041950251207L; private String name; private Address address; } | |
32 | float型数据不应该测试==或者equals |
float myNumber = 3.146; if ( myNumber == 3.146f ) { //false // ... } if ( myNumber != 3.146f ) { //true // ... } if (myNumber < 4 || myNumber > 4) { // 不规范代码 // ... } float zeroFloat = 0.0f; if (zeroFloat == 0) { // 不规范代码 } |
float zeroFloat = 0.0f; if (Float.floatToRawIntBits(zeroFloat) == 0) { } | |
33 |
二值操作符的两侧不应该使用相同的表达式 |
if ( a == a ) { // always true doZ(); } if ( a != a ) { // always false doY(); } if ( a == b && a == b ) { // if the first one is true, the second one is too doX(); } if ( a == b || a == b ) { // if the first one is true, the second one is too doW(); } int j = 5 / 5; //always 1 int k = 5 - 5; //always 0 |
doZ(); if ( a == b ) { doX(); } if ( a == b ) { doW(); } int j = 1; int k = 0; | |
34 | IllegalMonitorStateException表明某一线程已经试图等待对象的监视器,或者试图通知其他正在等待对象的监视器而本身没有指定监视器的线程,不应该被catch |
public void doSomething(){ ... try { ... anObject.notify(); ... } catch(IllegalMonitorStateException e) { ... } } |
public void doSomething(){ ... synchronized(anObject) { ... anObject.notify(); ... } } | |
35 |
wait(...)、notify()、notifyAll()方法只能在一个当前对象被锁上时调用,否则将会抛出IllegalMonitorStateException异常 |
private void removeElement() { while (!suitableCondition()){ wait(); } ... // Perform removal } |
private void removeElement() { synchronized(obj) { //当前对象 while (!suitableCondition()){ obj.wait(); } ... // Perform removal } } | |
36 |
Ints和longs整数转变不应该超过其自身位数的1位 |
public int shift(int a) { //int是32bit return a << 48;//不超过33 } |
public int shift(int a) { return a << 16; } | |
37 |
无效的“日期”值不应该被使用,规范如下: |
Date d = new Date(); d.setDate(25); d.setYear(2014); d.setMonth(12); // 12超出有效值 Calendar c = new GregorianCalendar(2014, 12, 25); if (c.get(Calendar.MONTH) == 12) { // ... } |
Date d = new Date(); d.setDate(25); d.setYear(2014); d.setMonth(11); Calendar c = new Gregorian Calendar(2014, 11, 25); if (c.get(Calendar.MONTH) == 11) { // ... } | |
38 |
循环条件至少应为一次 |
for (int i = 10; i < 10; i++) { // 不规范代码 // ... | ||
39 |
equals()方法必须重写Object.equals(Object),不然有可能识别不到正确的equals()方法 |
class MyClass { private int foo = 1; public boolean equals(MyClass o) { //没有重写 return o != null && o.foo == this.foo; } } |
@Override public boolean equals(Object o) { if (o == null || !(o instanceof MyClass)) { return false; } | |
40 |
方法名不应该命名为equals()和hashCode(),而是重写这两个方法 |
public int hashcode() { /* ... */ } //不规范代码 public boolean equal(Object obj) { /* ... */ } //不规范代码 |
@Override public int hashCode() { /* ... */ } public boolean equals(Object obj) { /* ... */ } | |
41 |
可变的变量不应该是public static |
public interface MyInterface { public static String [] strings; // 不规范代码 } public class A { public static String [] strings1 = {"first","second"}; // 不规范代码 public static String [] strings2 = {"first","second"}; // 不规范代码 public static List<String> strings3 = new ArrayList<>(); // 不规范代码 // ... } | ||
42 |
非公有方法不应该被@Transactional,因为spring的事务管理不能识别非公有方法,从而导致运行异常 |
@Transactional // 不规范代码 private void doTheThing(ArgClass arg) { // ... } |
@Transactional // 不规范代码 public void doTheThing(ArgClass arg) { // ... } | |
43 |
非序列化类不应该有写操作 |
public class Vegetable { // 需实现序列化 //... } public class Menu { public void meal() throws IOException { Vegetable veg; //... FileOutputStream fout = new FileOutputStream(veg.getName()); ObjectOutputStream oos = new ObjectOutputStream(fout); oos.writeObject(veg); // 不规范代码 } } |
public class Vegetable implements Serializable { // 可以被写 //... } public class Menu { public void meal() throws IOException { Vegetable veg; //... FileOutputStream fout = new FileOutputStream(veg.getName()); ObjectOutputStream oos = new ObjectOutputStream(fout); oos.writeObject(veg); } } | |
44 |
非序列化的对象不应该被储存在“httpsessions”,因为session将会被写进磁盘,非序列化的对象会导致写出错 |
public class Address { //... } //... HttpSession session = request.getSession(); session.setAttribute("address", new Address()); // Address isn't serializable | ||
45 |
Boolean方法不应该返回NULL,虽说null是一个有效的Boolean方法,但返回空的Boolean方法有可能导致程序出错 |
public Boolean isUsable() { // ... return null; // 不规范代码 } | ||
46 |
没有被使用的对象不应该被立即删除 |
if (x < 0) new IllegalArgumentException("x must be nonnegative"); |
if (x < 0) throw new IllegalArgumentException("x must be nonnegative"); | |
47 |
printf格式字符串在format时不应出现不合理的异常 |
String.format("The value of my integer is %d", "Hello World"); // 不规范代码 String.format("First {0} and then {1}", "foo", "bar"); //不规范代码 |
String.format("The value of my integer is %d", 3); String.format("First %s and then %s", "foo", "bar"); | |
48 |
if/else if 不应该有相同的循环条件 |
if (param == 1) openWindow(); else if (param == 2) closeWindow(); else if (param == 1) // 不规范代码 moveWindowToTheBackground(); } |
if (param == 1) openWindow(); else if (param == 2) closeWindow(); else if (param == 3) moveWindowToTheBackground(); } | |
49 |
关系运算符应该用在for循环的终止条件上,否则会造成无线循环 |
for (int i = 1; i != 10; i += 2) // 不规范代码 { //... } |
for (int i = 1; i <= 10; i += 2) { //... } | |
50 |
Servlets不应该有可变的实例变量,因为所有的线程共享servlet的实例,所以需要保证servlet的实例是static或final的 |
public class MyServlet extends HttpServlet { private String userName; //不规范代码 ... } | ||
51 |
布尔语境中应该用||,而不是| |
if(getTrue() | getFalse()) { ... } // 不规范代码 |
if(getTrue() || getFalse()) { ... } | |
52 |
switch语句中应该用break来终止程序 |
switch (myVariable) { case 1: foo(); break; case 2: //doSomethingElse也将会执行 doSomething(); default: doSomethingElse(); break; } |
switch (myVariable) { case 1: foo(); break; case 2: doSomething(); break; default: doSomethingElse(); break; } | |
53 |
Array的equals()方法不应该被使用,因为array没有重写equals方法,用equals来比较两个数组等同于比较两个数组的地址,没有任何意义 |
if(array1.equals(array2)){...} //不规范代码 |
if(Arrays.equals(array1, array2)){. ..} 或者 if(array1 == array2){...} | |
54 |
一个序列化类的非序列化超类应该有一个无参数的构造器,因为实现一个对象的序列化时,首先序列化对象的超类,如果一个非序列化的超类没有无参数的构造器,将不能实现序列化 |
public class Fruit { private Season ripe; //不规范代码,没有无参数的构造器 public Fruit (Season ripe) {...} public void setRipe(Season ripe) {...} public Season getRipe() {...} } public class Raspberry extends Fruit implements Serializable { private static final long serialVersionUID = 1; private String variety; public Raspberry(Season ripe, String variety) { ...} public void setVariety(String variety) {...} public String getVarity() {...} } |
public class Fruit { private Season ripe; public Fruit () {...}; public Fruit (Season ripe) {...} public void setRipe(Season ripe) {...} public Season getRipe() {...} } public class Raspberry extends Fruit implements Serializable { private static final long serialVersionUID = 1; private String variety; public Raspberry(Season ripe, String variety) {...} public void setVariety(String variety) {...} public String getVarity() {...} } | |
55 |
finalize()方法不应该被调用,垃圾回收器自动调用的一个方法 |
public void dispose() throws Throwable { this.finalize(); //不规范代码 } | ||
56 |
finalize()方法不应该被重写 |
public class MyClass { ... protected void finalize() { releaseSomeResources(); // 不规范代码 } ... } | ||
57 |
Thread和Runnable的run()方法不能被直接调用,这样会导致一直在当前线程执行 |
Thread myThread = new Thread(runnable); myThread.run(); // 不规范代码 |
Thread myThread = new Thread(runnable); myThread.start(); | |
58 |
printStackTrace(...)方法不应该被使用,而应该用log(),使用户更方便地浏览异常信息 |
try { /* ... */ } catch(Exception e) { e.printStackTrace(); // 不规范代码 } |
try { /* ... */ } catch(Exception e) { LOGGER.log("context", e); } | |
59 |
sql语句的执行过程中,参数不应该直接写在executeQuery()方法中,以防止敏感数据暴露 |
stmt2 = con.createStatement(); ResultSet rs2 = stmt2.executeQuery("select FNAME, LNAME, SSN " + "from USERS where UNAME=" + user); //不规范代码 |
try { stmt1 = con.createStatement(); ResultSet rs1 = stmt1.executeQuery("GETDATE()"); pstmt = con.prepareStatement(query); pstmt.setString(1, user); ResultSet rs2 = pstmt.executeQuery(); //... } | |
60 |
值不应该无效的增加 |
public int pickNumber() { int i = 0; int j = 0; i = i++; // i is still zero return j++; // 0 returned } |
public int pickNumber() { int i = 0; int j = 0; i++; return ++j; } |