美文网首页
Java规范之Sonar规则的汉化【BUG类】

Java规范之Sonar规则的汉化【BUG类】

作者: onmeiei | 来源:发表于2020-08-23 16:39 被阅读0次

    规则S1111 : 不可调用Object.finalize()

    根据JAVADOC的定义,方法Object.finalize()应该由垃圾回收器在进行垃圾回收时调用。
    在代码中调用该方法,将会影响到垃圾回收。

    • 错误的代码示例
    public void dispose() throws Throwable {
      this.finalize();                       // 错误的使用方式
    }
    

    规则S1114 : “super.finalize()”应该在"Object.finalize()"的最后被调用

    只有在会导致资源泄漏时,才进行 Object.finalize() 的重写。

    非常建议在该方法的最后,调用 super.finalize() 以保证父类的资源被合理的释放。

    • 错误的代码示例
    protected void finalize() {   // 错误的使用方式; no call to super.finalize();
      releaseSomeResources();
    }
    
    protected void finalize() {
      super.finalize();  // 错误的使用方式; this call should come last
      releaseSomeResources();
    }
    
    • 正确的代码示例
    protected void finalize() {
      releaseSomeResources();
      super.finalize();
    }
    

    规则S1143 : 在"finally"代码块中不可出现跳转

    finally代码块中,使用 return, break, throw等进行跳转,将导致异常trycatch中抛出的异常,无法被正确处理。

    • 错误的代码示例
    public static void main(String[] args) {
      try {
        doSomethingWhichThrowsException();
        System.out.println("OK");   // incorrect "OK" message is printed
      } catch (RuntimeException e) {
        System.out.println("ERROR");  // this message is not shown
      }
    }
    
    public static void doSomethingWhichThrowsException() {
      try {
        throw new RuntimeException();
      } finally {
        for (int i = 0; i < 10; i ++) {
          //...
          if (q == i) {
            break; // ignored
          }
        }
    
        /* ... */
        return;      // 错误的使用方式 - prevents the RuntimeException from being propagated
      }
    }
    
    • 正确的代码示例
    public static void main(String[] args) {
      try {
        doSomethingWhichThrowsException();
        System.out.println("OK");
      } catch (RuntimeException e) {
        System.out.println("ERROR");  // "ERROR" is printed as expected
      }
    }
    
    public static void doSomethingWhichThrowsException() {
      try {
        throw new RuntimeException();
      } finally {
        for (int i = 0; i < 10; i ++) {
          //...
          if (q == i) {
            break; // ignored
          }
        }
    
        /* ... */
      }
    }
    

    规则S1145 : 无用的 "if(true) {...}"和"if(false){...}"代码块应当被移除

    永远为true或false的代码块,将影响代码的可读性及维护性。

    • 错误的代码示例
    if (true) {
      doSomething();
    }
    ...
    if (false) {
      doSomethingElse();
    }
    
    if (2 < 3 ) { ... }  // 错误的使用方式; always false
    
    int i = 0;
    int j = 0;
    // ...
    j = foo();
    
    if (j > 0 && i > 0) { ... }  // 错误的使用方式; always false - i never set after initialization
    
    boolean b = true;
    //...
    if (b || !b) { ... }  // 错误的使用方式
    
    • 正确的代码示例
    doSomething();
    ...
    

    This rule is deprecated; use {rule:java:S2583} instead.

    规则S1175 : 禁止使用方法名"finalize()"

    Object.finalize() 会被垃圾回收调用,以释放对象使用的系统资源。禁止非特殊需要而重写该方法。如果使用该方法名,将可能导致错误的垃圾回收行为。

    • 错误的代码示例
    public int finalize(int someParameter) {        // 错误的使用方式
      /* ... */
    }
    
    • 正确的代码示例
    public int someBetterName(int someParameter) {  // Compliant
      /* ... */
    }
    

    规则S1201 : "equals"方法应当使用"Object"类型作为参数

    "equals"用于对比两个对象 Object.equals(Object) 以避免对象冲突。所以,需要传入Object类型作为参数。

    • 错误的代码示例
    class MyClass {
      private int foo = 1;
    
      public boolean equals(MyClass o) {  // 错误的使用方式; does not override Object.equals(Object)
        return o != null && o.foo == this.foo;
      }
    
      public static void main(String[] args) {
        MyClass o1 = new MyClass();
        Object o2 = new MyClass();
        System.out.println(o1.equals(o2));  // Prints "false" because o2 an Object not a MyClass
      }
    }
    
    class MyClass2 {
      public boolean equals(MyClass2 o) {  // Ignored; `boolean equals(Object)` also present
        //..
      }
    
      public boolean equals(Object o) {
        //...
      }
    }
    
    • 正确的代码示例
    class MyClass {
      private int foo = 1;
    
      @Override
      public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
          return false;
        }
    
        MyClass other = (MyClass)o;
        return this.foo == other.foo;
      }
    
      /* ... */
    }
    
    class MyClass2 {
      public boolean equals(MyClass2 o) {
        //..
      }
    
      public boolean equals(Object o) {
        //...
      }
    }
    

    规则S1206 : "equals(Object obj)"和 "hashCode()"应该同时定义,不可只定义其中一个

    根据Java官方文档的定义,这两个方法被同时用于对象的比较。所以在定义equals或hashcode方法是,需要同时定义两个方法。

    • 错误的代码示例
    class MyClass {    // 错误的使用方式 - should also override "hashCode()"
    
      @Override
      public boolean equals(Object obj) {
        /* ... */
      }
    
    }
    
    • 正确的代码示例
    class MyClass {    // Compliant
    
      @Override
      public boolean equals(Object obj) {
        /* ... */
      }
    
      @Override
      public int hashCode() {
        /* ... */
      }
    
    }
    

    规则S1217 : 禁止直接使用"Thread.run()"

    Thread.run()的设计目的时在专用的额外线程中执行该方法,直接调用将导致在当前同一个线程中执行方法。需要使用Thread.start()

    • 错误的代码示例
    Thread myThread = new Thread(runnable);
    myThread.run(); // 错误的使用方式
    
    • 正确的代码示例
    Thread myThread = new Thread(runnable);
    myThread.start(); // Compliant
    

    规则S1221 : 方法不应被定义为 "tostring", "hashcode"或"equal"

    如此定义,将导致代码的误解,与对象的方法toStringhashCode以及equals混淆。

    • 错误的代码示例
    public int hashcode() { /* ... */ }  // 错误的使用方式
    
    public String tostring() { /* ... */ } // 错误的使用方式
    
    public boolean equal(Object obj) { /* ... */ }  // 错误的使用方式
    
    • 正确的代码示例
    @Override
    public int hashCode() { /* ... */ }
    
    @Override
    public String toString() { /* ... */ }
    
    @Override
    public boolean equals(Object obj) { /* ... */ }
    

    规则S1226 : 不可赋值给:方法参数、捕获到的异常、foreach的变量

    赋值给这些变量将导致代码可维护性差,代码逻辑混乱。

    • 错误的代码示例
    public void doTheThing(String str, int i, List<String> strings) {
      str = Integer.toString(i); // 错误的使用方式
    
      for (String s : strings) {
        s = "hello world"; // 错误的使用方式
      }
    }
    

    规则S1244 : 不可以对浮点数使用==!=进行判断。

    不可以对浮点数(float或double)进行==!=进行判断,将导致结果不可预期。

    • 错误的代码示例
    float myNumber = 3.146;
    if ( myNumber == 3.146f ) { // 错误示范. Because of floating point imprecision, this will be false
      // ...
    }
    if ( myNumber != 3.146f ) { // 错误示范. Because of floating point imprecision, this will be true
      // ...
    }
    
    if (myNumber < 4 || myNumber > 4) { // 错误的使用方式; indirect inequality test
      // ...
    }
    
    float zeroFloat = 0.0f;
    if (zeroFloat == 0) {  // 错误的使用方式. Computations may end up with a value close but not equal to zero.
    }
    
    • 情况情况

    由于 NaN与其本身进行比较,会得到false,因此可以使用==!=进行判断。

    不过,依然更推荐使用 Double.isNaN进行判断,而不是使用==!=

    float f;
    double d;
    if(f != f) { // Compliant; test for NaN value
      System.out.println("f is NaN");
    } else if (f != d) { // 错误的使用方式
      // ...
    }
    

    规则S1317 : 不可以使用char进行"StringBuilder"和"StringBuffer"的初始化

    使用单个char进行初始化,其实会使用char对应的数字,对StringBuilder和StringBuffer进行初始化,而不是使用char进行初始化。

    • 错误的代码示例
    StringBuffer foo = new StringBuffer('x');   //equivalent to StringBuffer foo = new StringBuffer(120);
    
    • 正确的代码示例
    StringBuffer foo = new StringBuffer("x");
    

    规则S1656 : 变量不可以赋值给自身

    赋值给自身将导致,代码逻辑易读性差,无法维护。

    • 错误的代码示例
    public void setName(String name) {
      name = name;
    }
    
    • 正确的代码示例
    public void setName(String name) {
      this.name = name;
    }
    

    规则S1751 : 最多执行一次的循环逻辑,必须被重构

    循环逻辑是用于多次执行的,如果一个逻辑只执行一次,但是使用了循环语法,将会导致代码的误解。

    没有程序员会故意设计只执行一次的循环逻辑。

    • 错误的代码示例
    for (int i = 0; i < 10; i++) { // 错误的使用方式, loop only executes once
      printf("i is %d", i);
      break;
    }
    ...
    for (int i = 0; i < 10; i++) { // 错误的使用方式, loop only executes once
      if (i == x) {
        break;
      } else {
        printf("i is %d", i);
        return;
      }
    }
    
    • 正确的代码示例
    for (int i = 0; i < 10; i++) {
      printf("i is %d", i);
    }
    ...
    for (int i = 0; i < 10; i++) {
      if (i == x) {
        break;
      } else {
        printf("i is %d", i);
      }
    }
    

    规则S1764 : 二元操作符的两元,不可以相同

    如果二元操作符的两元相同,将导致逻辑永远为错误或正确。导致代码逻辑与设计不同。

    • 错误的代码示例
    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
    
    c.equals(c); //always true
    
    • 例外情况
      • 使用*,+,=时,可以相同
      • 如果判断浮点数是否NaN时,可以相同;PS:推荐使用Double.isNaN方法
      • 位移操作,两侧均为数字时,可以相同。
    float f;
    if(f != f) { //test for NaN value
      System.out.println("f is NaN");
    }
    
    int i = 1 << 1; // Compliant
    int j = a << a; // 错误的使用方式
    

    规则S1849 : "Iterator.hasNext()"中,不可调用"Iterator.next()"方法

    在实现hasNext()方法时,可以调用next()方法;否则将导致游标发生变化。

    • 错误的代码示例
    public class FibonacciIterator implements Iterator<Integer>{
    ...
    @Override
    public boolean hasNext() {
      if(next() != null) {
        return true;
      }
      return false;
    }
    ...
    }
    

    规则S1850 : 不可以使用永远为true或false的"instanceof" 判断

    会导致代码误解,可读性差。

    • 错误的代码示例
    public boolean isSuitable(Integer param) {
    ...
      String name = null;
    
      if (name instanceof String) { // 错误的使用方式; always false since name is null
        //...
      }
    
      if(param instanceof Number) {  // 错误的使用方式; always true unless param is null, because param is an Integer
        doSomething();
      }
    ...
    }
    
    • 正确的代码示例
    public boolean isSuitable(Integer param) {
    ...
      doSomething();
    ...
    }
    

    规则S1860 : Synchronized不可以使用String、Int、Long等原始对象

    由于JVM对这一类对象的缓存行为,将导致整个系统的线程同步不可控。

    • 错误的代码示例
    private static final Boolean bLock = Boolean.FALSE;
    private static final Integer iLock = Integer.valueOf(0);
    private static final String sLock = "LOCK";
    
    public void doSomething() {
    
      synchronized(bLock) {  // 错误的使用方式
        // ...
      }
      synchronized(iLock) {  // 错误的使用方式
        // ...
      }
      synchronized(sLock) {  // 错误的使用方式
        // ...
      }
    
    • 正确的代码示例
    private static final Object lock1 = new Object();
    private static final Object lock2 = new Object();
    private static final Object lock3 = new Object();
    
    public void doSomething() {
    
      synchronized(lock1) {
        // ...
      }
      synchronized(lock2) {
        // ...
      }
      synchronized(lock3) {
        // ...
      }
    

    规则S1862 : "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();
    }
    
    

    规则S1872 : 不可以使用类名进行类的比较

    需要使用 instanceofClass.isAssignableFrom() 进行判断。

    • 错误的代码示例
    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;  // Results in throwing away week-old computers
        }
        return false;
      }
    
      public boolean isList(Class<T> valueClass) {
        if (List.class.getName().equals(valueClass.getName())) {  // 错误的使用方式
          return true;
        }
        return false;
      }
    }
    
    • 正确的代码示例
    class Store {
    
      public boolean hasSellByDate(Object item) {
        if (item instanceof food.Pear) {
          return true;
        }
        return false;
      }
    
      public boolean isList(Class<T> valueClass) {
        if (valueClass.isAssignableFrom(List.class)) {
          return true;
        }
        return false;
      }
    }
    

    规则S2055 : 不可序列化的"Serializable"必须设计无参构造函数

    • 错误的代码示例
    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 {  // 错误的使用方式; nonserializable ancestor doesn't have no-arg constructor
      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 () {...};  // Compliant; no-arg constructor added to ancestor
      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() {...}
    }
    

    规则S2060 : "Externalizable"类必须设计无参构造函数

    • 错误的代码示例
    public class Tomato implements Externalizable {  // 错误的使用方式; no no-arg constructor
    
      public Tomato (String color, int weight) { ... }
    }
    
    • 正确的代码示例
    public class Tomato implements Externalizable {
    
      public Tomato() { ... }
      public Tomato (String color, int weight) { ... }
    }
    

    规则S2061 : 自定义序列化方法的权限需要符合要求

    • 错误的代码示例
    public class Watermelon implements Serializable {
      // ...
      void writeObject(java.io.ObjectOutputStream out)// 错误的使用方式; not private
            throws IOException
      {...}
    
      private void readObject(java.io.ObjectInputStream in)
      {...}
    
      public void readObjectNoData()  // 错误的使用方式; not private
      {...}
    
      static Object readResolve() throws ObjectStreamException  // 错误的使用方式; this method may have any access modifier, may not be static
    
      Watermelon writeReplace() throws ObjectStreamException // 错误的使用方式; this method may have any access modifier, but must return 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
      {...}
    

    规则S2066 : "Serializable"内部类必须声明为"static"

    • 错误的代码示例
    public class Pomegranate {
      // ...
    
      public class Seed implements Serializable {  // 错误的使用方式; serialization will fail
        // ...
      }
    }
    
    • 正确的代码示例
    public class Pomegranate {
      // ...
    
      public static class Seed implements Serializable {
        // ...
      }
    }
    

    规则S2095 : 所有"Closeable"资源必须关闭

    连接、文件、网络等资源,必须调用close()进行关闭。

    • 错误的代码示例
    private void readTheFile() throws IOException {
      Path path = Paths.get(this.fileName);
      BufferedReader reader = Files.newBufferedReader(path, this.charset);
      // ...
      reader.close();  // 错误的使用方式
      // ...
      Files.lines("input.txt").forEach(System.out::println); // 错误的使用方式: The stream needs to be closed
    }
    
    private void doSomething() {
      OutputStream stream = null;
      try {
        for (String property : propertyList) {
          stream = new FileOutputStream("myfile.txt");  // 错误的使用方式
          // ...
        }
      } catch (Exception e) {
        // ...
      } finally {
        stream.close();  // Multiple streams were opened. Only the last is closed.
      }
    }
    
    • 正确的代码示例
    private void readTheFile(String fileName) throws IOException {
        Path path = Paths.get(fileName);
        try (BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
          reader.readLine();
          // ...
        }
        // ..
        try (Stream<String> input = Files.lines("input.txt"))  {
          input.forEach(System.out::println);
        }
    }
    
    private void doSomething() {
      OutputStream stream = null;
      try {
        stream = new FileOutputStream("myfile.txt");
        for (String property : propertyList) {
          // ...
        }
      } catch (Exception e) {
        // ...
      } finally {
        stream.close();
      }
    }
    

    可以使用try-with-resource语法进行自动关闭。

    try (BufferedReader br = new BufferedReader(new FileReader(fileName))) {
      //...
    }
    catch ( ... ) {
      //...
    }
    

    规则S2097 : "equals(Object obj)"方法需要先判断对象类型

    • 错误的代码示例
    public boolean equals(Object obj) {
      MyClass mc = (MyClass)obj;  // 错误的使用方式
      // ...
    }
    
    • 正确的代码示例
    public boolean equals(Object obj) {
      if (obj == null)
        return false;
    
      if (this.getClass() != obj.getClass())
        return false;
    
      MyClass mc = (MyClass)obj;
      // ...
    }
    

    规则S2109 : 非Runtime注解,不可以使用反射

    • 错误的代码示例
    Method m = String.class.getMethod("getBytes", new Class[] {int.class,
    int.class, byte[].class, int.class});
    if (m.isAnnotationPresent(Override.class)) {  // 错误的使用方式; test will always return false, even when @Override is present in the code
    

    规则S2110 : 不可以使用非法"Date"值

    由于计数都是从0开始的,所以Date值应严格参考可用范围。

    字段 取值范围
    month 0-11
    date/day 0-31
    hour 0-23
    minute 0-60
    second 0-61
    • 错误的代码示例
    Date d = new Date();
    d.setDate(25);
    d.setYear(2014);
    d.setMonth(12);  // 错误的使用方式; rolls d into the next year
    
    Calendar c = new GregorianCalendar(2014, 12, 25);  // 错误的使用方式
    if (c.get(Calendar.MONTH) == 12) {  // 错误的使用方式; invalid comparison
      // ...
    }
    
    • 正确的代码示例
    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) {
      // ...
    }
    

    规则S2111 : 不可使用"BigDecimal(double)"构造函数

    因为float和double的精度问题,使用该构造函数会导致不可控的问题。应当使用valueOf和字符串参数进行构建。

    • 错误的代码示例
    double d = 1.1;
    
    BigDecimal bd1 = new BigDecimal(d); // 错误的使用方式; see comment above
    BigDecimal bd2 = new BigDecimal(1.1); // 错误的使用方式; same result
    
    • 正确的代码示例
    double d = 1.1;
    
    BigDecimal bd1 = BigDecimal.valueOf(d);
    BigDecimal bd2 = new BigDecimal("1.1"); // using String constructor will result in precise value
    

    规则S2114 : "Collections"不可作为方法参数传给自己

    • 错误的代码示例
    List <Object> objs = new ArrayList<Object>();
    objs.add("Hello");
    
    objs.add(objs); // 错误的使用方式; StackOverflowException if objs.hashCode() called
    objs.addAll(objs); // 错误的使用方式; behavior undefined
    objs.containsAll(objs); // 错误的使用方式; always true
    objs.removeAll(objs); // 错误的使用方式; confusing. Use clear() instead
    objs.retainAll(objs); // 错误的使用方式; NOOP
    

    规则S2116 : 不可对数组对象进行"hashCode" 和 "toString"

    • 错误的代码示例
    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);
    
    

    规则S2118 : Non-serializable类不可以进行写入。

    • 错误的代码示例
    public class Vegetable {  // neither implements Serializable nor extends a class that does
      //...
    }
    
    public class Menu {
      public void meal() throws IOException {
        Vegetable veg;
        //...
        FileOutputStream fout = new FileOutputStream(veg.getName());
        ObjectOutputStream oos = new ObjectOutputStream(fout);
        oos.writeObject(veg);  // 错误的使用方式. Nothing will be written
      }
    }
    
    • 正确的代码示例
    public class Vegetable implements Serializable {  // can now be serialized
      //...
    }
    
    public class Menu {
      public void meal() throws IOException {
        Vegetable veg;
        //...
        FileOutputStream fout = new FileOutputStream(veg.getName());
        ObjectOutputStream oos = new ObjectOutputStream(fout);
        oos.writeObject(veg);
      }
    }
    

    规则S2119 : "Random"对象必须进行复用

    不复用,将导致Random不可控,会返回相同的值。

    • 错误的代码示例
    public void doSomethingCommon() {
      Random rand = new Random();  // 错误的使用方式; new instance created with each invocation
      int rValue = rand.nextInt();
      //...
    
    • 正确的代码示例
    private Random rand = SecureRandom.getInstanceStrong();  // SecureRandom is preferred to Random
    
    public void doSomethingCommon() {
      int rValue = this.rand.nextInt();
      //...
    

    规则S2121 : 不可进行无效的"String"操作

    • 错误的代码示例
    String speech = "Now is the time for all good people to come to the aid of their country.";
    
    String s1 = speech.substring(0); // 错误的使用方式. Yields the whole string
    String s2 = speech.substring(speech.length()); // 错误的使用方式. Yields ";
    String s3 = speech.substring(5,speech.length()); // 错误的使用方式. Use the 1-arg version instead
    
    if (speech.contains(speech)) { // 错误的使用方式
     // always true
    }
    
    • 正确的代码示例
    String speech = "Now is the time for all good people to come to the aid of their country.";
    
    String s1 = speech;
    String s2 = ";
    String s3 = speech.substring(5);
    

    规则S2122 : "ScheduledThreadPoolExecutor"不可以设置线程

    • 错误的代码示例
    public void do(){
    
      ScheduledThreadPoolExecutor stpe1 = new ScheduledThreadPoolExecutor(0); // 错误的使用方式
    
      ScheduledThreadPoolExecutor stpe2 = new ScheduledThreadPoolExecutor(POOL_SIZE);
      stpe2.setCorePoolSize(0);  // 错误的使用方式
    

    规则S2123 : 不可以无用的进行值加操作

    • 错误的代码示例
    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;
    }
    

    规则S2127 : "Double.longBitsToDouble"的参数可用"int"

    参数必须为long,不可以为int

    • 错误的代码示例
    int i = 42;
    double d = Double.longBitsToDouble(i);  // 错误的使用方式
    

    规则S2134 : "java.lang.Thread"的子类,必须重写"run"

    • 错误的代码示例
    public class MyRunner extends Thread { // 错误的使用方式; run method not overridden
    
      public void doSometing() {...}
    }
    
    • 例外情况:

      如果线程将Runnable传给super,可以不重写run方法

    class MyThread extends Thread { // Compliant - calling super constructor with a Runnable
      MyThread(Runnable target) {
        super(target); // calling super constructor with a Runnable, which will be used for when Thread.run() is executed
        // ...
      }
    }
    

    规则S2141 : 未自定义"hashCode()"方法的类,不可用于Hash操作

    Object的hashCode不可控,所以未自定义hashCode方法的类不可用于Hash操作。否则,结果具有不可预测性。

    • 错误的代码示例
    public class Student {  // no hashCode() method; not hash-able
      // ...
    
      public boolean equals(Object o) {
        // ...
      }
    }
    
    public class School {
      private Map<Student, Integer> studentBody = // okay so far
              new HashTable<Student, Integer>(); // 错误的使用方式
    
      // ...
    
    • 正确的代码示例
    public class Student {  // has hashCode() method; hash-able
      // ...
    
      public boolean equals(Object o) {
        // ...
      }
      public int hashCode() {
        // ...
      }
    }
    
    public class School {
      private Map<Student, Integer> studentBody = new HashTable<Student, Integer>();
    
      // ...
    

    规则S2142 : 不可以忽略"InterruptedException",只能重新抛出或调用Thread.currentThread().interrupt()。

    • 错误的代码示例
    public void run () {
      try {
        while (true) {
          // do stuff
        }
      }catch (InterruptedException e) { // 错误的使用方式; logging is not enough
        LOGGER.log(Level.WARN, "Interrupted!", e);
      }
    }
    
    • 正确的代码示例
    public void run () {
      try {
        while (true) {
          // do stuff
        }
      }catch (InterruptedException e) {
        LOGGER.log(Level.WARN, "Interrupted!", e);
        // Restore interrupted state...
        Thread.currentThread().interrupt();
      }
    }
    

    规则S2151 : 不可以调用"runFinalizersOnExit"

    使用Runtime.addShutdownHook代替。

    • 错误的代码示例
    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();
        }
      });
      //...
    

    规则S2153 : 不应显式进行封箱和拆箱

    JVM会自动进行封箱和拆箱操作,不可显式进行操作。

    • 错误的代码示例
    public void examineInt(int a) {
      //...
    }
    
    public void examineInteger(Integer a) {
      // ...
    }
    
    public void func() {
      int i = 0;
      Integer iger1 = Integer.valueOf(0);
      double d = 1.0;
    
      int dIntValue = new Double(d).intValue(); // 错误的使用方式
    
      examineInt(new Integer(i).intValue()); // 错误的使用方式; explicit box/unbox
      examineInt(Integer.valueOf(i));  // 错误的使用方式; boxed int will be auto-unboxed
    
      examineInteger(i); // Compliant; value is boxed but not then unboxed
      examineInteger(iger1.intValue()); // 错误的使用方式; unboxed int will be autoboxed
    
      Integer iger2 = new Integer(iger1); // 错误的使用方式; unnecessary unboxing, value can be reused
    }
    
    • 正确的代码示例
    public void examineInt(int a) {
      //...
    }
    
    public void examineInteger(Integer a) {
      // ...
    }
    
    public void func() {
      int i = 0;
      Integer iger1 = Integer.valueOf(0);
      double d = 1.0;
    
      int dIntValue = (int) d;
    
      examineInt(i);
    
      examineInteger(i);
      examineInteger(iger1);
    }
    

    规则S2154 : 不同类型的基本类型变量,不可以直接进行赋值,需要显式进行强转

    • 错误的代码示例
    Integer i = 123456789;
    Float f = 1.0f;
    Number n = condition ? i : f;  // 错误的使用方式; i is coerced to float. n = 1.23456792E8
    
    • 正确的代码示例
    Integer i = 123456789;
    Float f = 1.0f;
    Number n = condition ? (Number) i : f;  // n = 123456789
    

    规则S2159 : 不可进行无效的equals比较

    无效的equals操作包括:

    • 与null进行比较
    • 不同类型进行equals比较
    • 不同基本类型进行equals比较
    • 不同classinterface进行比较
    • 不同的interface类型进行比较
    • 数组与非数组进行比较
    • 数组之间进行比较
    • 错误的代码示例
    interface KitchenTool { ... };
    interface Plant {...}
    
    public class Spatula implements KitchenTool { ... }
    public class Tree implements Plant { ...}
    //...
    
    Spatula spatula = new Spatula();
    KitchenTool tool = spatula;
    KitchenTool [] tools = {tool};
    
    Tree tree = new Tree();
    Plant plant = tree;
    Tree [] trees = {tree};
    
    if (spatula.equals(tree)) { // 错误的使用方式; unrelated classes
      // ...
    }
    else if (spatula.equals(plant)) { // 错误的使用方式; unrelated class and interface
      // ...
    }
    else if (tool.equals(plant)) { // 错误的使用方式; unrelated interfaces
      // ...
    }
    else if (tool.equals(tools)) { // 错误的使用方式; array & non-array
      // ...
    }
    else if (trees.equals(tools)) { // 错误的使用方式; incompatible arrays
      // ...
    }
    else if (tree.equals(null)) { // 错误的使用方式
      // ...
    }
    

    规则S2162 : "equals"方法应当保证父子类的对象之间的比较具有对等性

    典型的操作,比如a.equals(b)b.equals(a)的结果需要一致,具有对等性。

    使用instanceof进行判断,将破坏这种对等性,例如,父类对象 instanceof 子类是false,而子类对象 instanceof 父类是true。
    例如:

    Fruit fruit = new Fruit();
    Raspberry raspberry = new Raspberry();
    
    if (raspberry instanceof Fruit) { ... } // true
    if (fruit instanceof Raspberry) { ... } // false
    

    如果instanceof用于了两个类的equals方法,将导致:

    raspberry.equals(fruit); // false
    fruit.equals(raspberry); //true
    

    final类,中使用Class.equals,如果equals方法被继承,也将导致类似的情况。

    • 错误的代码示例
    public class Fruit extends Food {
      private Season ripe;
    
      public boolean equals(Object obj) {
        if (obj == this) {
          return true;
        }
        if (obj == null) {
          return false;
        }
        if (Fruit.class == obj.getClass()) { // 错误示范; broken for child classes
          return ripe.equals(((Fruit)obj).getRipe());
        }
        if (obj instanceof Fruit ) {  // 错误示范; broken for child classes
          return ripe.equals(((Fruit)obj).getRipe());
        }
        else if (obj instanceof Season) { // 错误示范; symmetry broken for Season class
          // ...
        }
        //...
    
    • 正确的代码示例
    public class Fruit extends Food {
      private Season ripe;
    
      public boolean equals(Object obj) {
        if (obj == this) {
          return true;
        }
        if (obj == null) {
          return false;
        }
        if (this.getClass() == obj.getClass()) {
          return ripe.equals(((Fruit)obj).getRipe());
        }
        return false;
    }
    

    规则S2164 : 不要在float上进行数学操作

    使用BigDecimal 进行代理,如果必须使用基本数据类型,则使用double进行操作

    • 错误的代码示例
    float a = 16777216.0f;
    float b = 1.0f;
    float c = a + b; // 错误示范; yields 1.6777216E7 not 1.6777217E7
    
    double d = a + b; // 错误示范; addition is still between 2 floats
    
    • 正确的代码示例
    float a = 16777216.0f;
    float b = 1.0f;
    BigDecimal c = BigDecimal.valueOf(a).add(BigDecimal.valueOf(b));
    
    double d = (double)a + (double)b;
    
    • Exceptions

    This rule doesn't raise an issue when the mathematical expression is only used to build a string.

    System.out.println("["+getName()+"] " +
               "\n\tMax time to retrieve connection:"+(max/1000f/1000f)+" ms.");
    

    规则S2167 : "compareTo" 不可以返回"Integer.MIN_VALUE"

    • 错误的代码示例
    public int compareTo(MyClass) {
      if (condition) {
        return Integer.MIN_VALUE;  // 错误示范
      }
    
    • 正确的代码示例
    public int compareTo(MyClass) {
      if (condition) {
        return -1;
      }
    

    规则S2168 : 不可以使用锁进行双重检查

    懒加载中经常使用的手段是“加锁双重检查”,但是该操作在不同的JVM版本中表现不一致,导致结果具有不可预测性。所以不要使用这种操作。

    • 错误的代码示例
    @NotThreadSafe
    public class DoubleCheckedLocking {
        private static Resource resource;
    
        public static Resource getInstance() {
            if (resource == null) {
                synchronized (DoubleCheckedLocking.class) {
                    if (resource == null)
                        resource = new Resource();
                }
            }
            return resource;
        }
    
        static class Resource {
    
        }
    }
    
    • 正确的代码示例
    @ThreadSafe
    public class SafeLazyInitialization {
        private static Resource resource;
    
        public static synchronized Resource getInstance() {
            if (resource == null)
                resource = new Resource();
            return resource;
        }
    
        static class Resource {
        }
    }
    

    使用内部类进行懒加载:

    @ThreadSafe
    public class ResourceFactory {
        private static class ResourceHolder {
            public static Resource resource = new Resource(); // This will be lazily initialised
        }
    
        public static Resource getResource() {
            return ResourceFactory.ResourceHolder.resource;
        }
    
        static class Resource {
        }
    }
    

    使用关键字"volatile":

    class ResourceFactory {
      private volatile Resource resource;
    
      public Resource getResource() {
        Resource localResource = resource;
        if (localResource == null) {
          synchronized (this) {
            localResource = resource;
            if (localResource == null) {
              resource = localResource = new Resource();
            }
          }
        }
        return localResource;
      }
    
      static class Resource {
      }
    }
    

    规则S2175 : 不可进行不恰当的"Collection" 操作

    有一些集合的设计中,如果传入不恰当的参数变量,只会返回false或null,而不会报错。例如:

    • Collection.remove(Object o)
    • Collection.removeAll(Collection<?>)
    • Collection.contains(Object o)
    • List.indexOf(Object o)
    • List.lastIndexOf(Object o)
    • Map.containsKey(Object key)
    • Map.containsValue(Object value)
    • Map.get(Object key)
    • Map.getOrDefault(Object key, V defaultValue)
    • Map.remove(Object key)
    • Map.remove(Object key, Object value)
    • 错误的代码示例
    public class S2175 {
    
      public static void main(String[] args) {
        String foo = "42";
        Map<Integer, Object> map = new HashMap<>();
        map.remove(foo); // 错误示范; will return 'null' for sure because 'map' is handling only Integer keys
    
        // ...
    
        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'
        }
      }
    
    }
    

    规则S2177 : 子类重写父类方法,必须添加override注解

    如果不添加注解,父类子类方法定义一致,但是参数类型虽然名字一致,但是引用自不同的package,将导致override失败。

    • 错误的代码示例
    // Parent.java
    import computer.Pear;
    public class Parent {
    
      public void doSomething(Pear p) {
        //,,,
      }
    
      public static void doSomethingElse() {
        //...
      }
    }
    
    // Child.java
    import fruit.Pear;
    public class Child extends Parent {
    
      public void doSomething(Pear p) {  // 错误示范; this is not an override
        // ...
      }
    
      public void doSomethingElse() {  // 错误示范; parent method is static
        //...
      }
    }
    
    • 正确的代码示例
    // Parent.java
    import computer.Pear;
    public class Parent {
    
      public void doSomething(Pear p) {
        //,,,
      }
    
      public static void doSomethingElse() {
        //...
      }
    }
    
    // Child.java
    import computer.Pear;  // import corrected
    public class Child extends Parent {
    
      public void doSomething(Pear p) {  // true override (see import)
        //,,,
      }
    
      public static void doSomethingElse() {
        //...
      }
    }
    

    规则S2183 : 位移操作的范围需要正确,Int和long进行位移,位移必须大于0且小于类型bits - 1

    • 错误的代码示例
    public int shift(int a) {
      int x = a >> 32; // 错误示范
      return a << 48;  // 错误示范
    }
    
    • 正确的代码示例
    public int shift(int a) {
      int x = a >> 31;
      return a << 16;
    }
    
    bytes[loc+0] = (byte)(value >> 8);
    bytes[loc+1] = (byte)(value >> 0);
    

    规则S2184 : 数学操作需要先进行强转再操作

    • 错误的代码示例
    float twoThirds = 2/3; // 错误示范; int division. Yields 0.0
    long millisInYear = 1_000*3_600*24*365; // 错误示范; int multiplication. Yields 1471228928
    long bigNum = Integer.MAX_VALUE + 2; // 错误示范. Yields -2147483647
    long bigNegNum =  Integer.MIN_VALUE-1; // 错误示范, gives a positive result instead of a negative one.
    Date myDate = new Date(seconds * 1_000); // 错误示范, won't produce the expected result if seconds > 2_147_483
    ...
    public long compute(int factor){
      return factor * 10_000;  // 错误示范, won't produce the expected result if factor > 214_748
    }
    
    public float compute2(long factor){
      return factor / 123;  // 错误示范, will be rounded to closest long integer
    }
    
    • 正确的代码示例
    float twoThirds = 2f/3; // 2 promoted to float. Yields 0.6666667
    long millisInYear = 1_000L*3_600*24*365; // 1000 promoted to long. Yields 31_536_000_000
    long bigNum = Integer.MAX_VALUE + 2L; // 2 promoted to long. Yields 2_147_483_649
    long bigNegNum =  Integer.MIN_VALUE-1L; // Yields -2_147_483_649
    Date myDate = new Date(seconds * 1_000L);
    ...
    public long compute(int factor){
      return factor * 10_000L;
    }
    
    public float compute2(long factor){
      return factor / 123f;
    }
    

    or

    float twoThirds = (float)2/3; // 2 cast to float
    long millisInYear = (long)1_000*3_600*24*365; // 1_000 cast to long
    long bigNum = (long)Integer.MAX_VALUE + 2;
    long bigNegNum =  (long)Integer.MIN_VALUE-1;
    Date myDate = new Date((long)seconds * 1_000);
    ...
    public long compute(long factor){
      return factor * 10_000;
    }
    
    public float compute2(float factor){
      return factor / 123;
    }
    

    规则S2189 : 不可以无限循环

    • 错误的代码示例
    for (;;) {  // 错误示范; end condition omitted
      // ...
    }
    
    int j;
    while (true) { // 错误示范; end condition omitted
      j++;
    }
    
    int k;
    boolean b = true;
    while (b) { // 错误示范; b never written to in loop
      k++;
    }
    
    • 正确的代码示例
    int j;
    while (true) { // reachable end condition added
      j++;
      if (j  == Integer.MIN_VALUE) {  // true at Integer.MAX_VALUE +1
        break;
      }
    }
    
    int k;
    boolean b = true;
    while (b) {
      k++;
      b = k < Integer.MAX_VALUE;
    }
    

    规则S2200 : "compareTo"的结果,不可以进行特定值比较

    虽然大部分都返回 -1,0,1,但是根据实现不同也有其他的情况存在。

    • 错误的代码示例
    if (myClass.compareTo(arg) == -1) {  // 错误示范
      // ...
    }
    
    • 正确的代码示例
    if (myClass.compareTo(arg) < 0) {
      // ...
    }
    

    规则S2201 : 方法的返回,不应当被忽略掉

    • 错误的代码示例
    public void handle(String command){
      command.toLowerCase(); // 错误示范; result of method thrown away
      ...
    }
    
    • 正确的代码示例
    public void handle(String command){
      String formattedCommand = command.toLowerCase();
      ...
    }
    
    • 特殊情况说明

    如果同时满足如下两个条件,则可以忽略返回值

    • 方法在try catch块中,并且catch了该方法的异常
    • 如果方法名以"parse", "format", "decode"开始 或为 "valueOf" 或为String.getBytes(Charset)
    private boolean textIsInteger(String textToCheck) {
    
        try {
            Integer.parseInt(textToCheck, 10); // OK
            return true;
        } catch (NumberFormatException ignored) {
            return false;
        }
    }
    

    规则S2204 : "Atomic"对象,不可以使用".equals()"方法

    • 错误的代码示例
    AtomicInteger aInt1 = new AtomicInteger(0);
    AtomicInteger aInt2 = new AtomicInteger(0);
    
    if (aInt1.equals(aInt2)) { ... }  // 错误示范
    
    • 正确的代码示例
    AtomicInteger aInt1 = new AtomicInteger(0);
    AtomicInteger aInt2 = new AtomicInteger(0);
    
    if (aInt1.get() == aInt2.get()) { ... }
    

    规则S2222 : 所有的"Lock"必须保证正确释放

    • 错误的代码示例
    public class MyClass {
      private Lock lock = new Lock();
    
      public void doSomething() {
        lock.lock(); // 错误示范
        if (isInitialized()) {
          // ...
          lock.unlock();
        }
      }
    }
    
    • 正确的代码示例
    public class MyClass {
      private Lock lock = new Lock();
    
      public void doSomething() {
        if (isInitialized()) {
          lock.lock();
          // ...
          lock.unlock();
        }
      }
    }
    

    规则S2225 : "toString()" 和 "clone()"不可以返回null

    • 错误的代码示例
    public String toString () {
      if (this.collection.isEmpty()) {
        return null; // 错误示范
      } else {
        // ...
    
    • 正确的代码示例
    public String toString () {
      if (this.collection.isEmpty()) {
        return ";
      } else {
        // ...
    

    规则S2226 : "Servlet"或"Controller"或"Service"等共享对象,所有属性必须不可修改

    • 错误的代码示例
    public class MyServlet extends HttpServlet {
      private String userName;  //As this field is shared by all users, it's obvious that this piece of information should be managed differently
      ...
    }
    

    or

    public class MyAction extends Action {
      private String userName;  //Same reason
      ...
    }
    

    规则S2229 : 同一个类中的方法,不可以调用有"@Transactional"的方法

    由于Spring事务传递的设计,不可以调用的方法顺序如下:

    起始方法 被调用方法
    non-@Transactional MANDATORY, NESTED, REQUIRED, REQUIRES_NEW
    MANDATORY NESTED, NEVER, NOT_SUPPORTED, REQUIRES_NEW
    NESTED NESTED, NEVER, NOT_SUPPORTED, REQUIRES_NEW
    NEVER MANDATORY, NESTED, REQUIRED, REQUIRES_NEW
    NOT_SUPPORTED MANDATORY, NESTED, REQUIRED, REQUIRES_NEW
    REQUIRED or @Transactional NESTED, NEVER, NOT_SUPPORTED, REQUIRES_NEW
    REQUIRES_NEW NESTED, NEVER, NOT_SUPPORTED, REQUIRES_NEW
    SUPPORTS MANDATORY, NESTED, NEVER, NOT_SUPPORTED, REQUIRED, REQUIRES_NEW
    • 错误的代码示例
    
    @Override
    public void doTheThing() {
      // ...
      actuallyDoTheThing();  // 错误示范
    }
    
    @Override
    @Transactional
    public void actuallyDoTheThing() {
      // ...
    }
    

    规则S2230 : 非public方法,不可以声明为"@Transactional"

    因为会导致@Transactional注解不起作用。

    • 错误的代码示例
    @Transactional  // 错误示范
    private void doTheThing(ArgClass arg) {
      // ...
    }
    

    规则S2236 : 不可以调用Thread对象的方法"wait(...)", "notify()"以及 "notifyAll()"

    • 错误的代码示例
    Thread myThread = new Thread(new RunnableJob());
    ...
    myThread.wait(2000);
    

    规则S2251 : "for"循环需要正确的进行变量的变化

    • 错误的代码示例
    public void doSomething(String [] strings) {
      for (int i = 0; i < strings.length; i--) { // 错误示范;
        String string = strings[i];  // ArrayIndexOutOfBoundsException when i reaches -1
        //...
      }
    
    • 正确的代码示例
    public void doSomething(String [] strings) {
      for (int i = 0; i < strings.length; i++) {
        String string = strings[i];
        //...
      }
    

    规则S2252 : 循环条件至少可以满足一次

    • 错误的代码示例
    for (int i = 10; i < 10; i++) {  // 错误示范
      // ...
    

    规则S2259 : 不可引用或访问"Null"

    • 错误的代码示例
    @CheckForNull
    String getName(){...}
    
    public boolean isNameEmpty() {
      return getName().length() == 0; // 错误示范; the result of getName() could be null, but isn't null-checked
    }
    
    Connection conn = null;
    Statement stmt = null;
    try{
      conn = DriverManager.getConnection(DB_URL,USER,PASS);
      stmt = conn.createStatement();
      // ...
    
    }catch(Exception e){
      e.printStackTrace();
    }finally{
      stmt.close();   // 错误示范; stmt could be null if an exception was thrown in the try{} block
      conn.close();  // 错误示范; conn could be null if an exception was thrown
    }
    
    private void merge(@Nonnull Color firstColor, @Nonnull Color secondColor){...}
    
    public  void append(@CheckForNull Color color) {
        merge(currentColor, color);  // 错误示范; color should be null-checked because merge(...) doesn't accept nullable parameters
    }
    
    void paint(Color color) {
      if(color == null) {
        System.out.println("Unable to apply color " + color.toString());  // 错误示范; NullPointerException will be thrown
        return;
      }
      ...
    }
    

    规则S2272 : "Iterator.next()"应当抛出"NoSuchElementException",而不应该返回null

    • 错误的代码示例
    public class MyIterator implements Iterator<String>{
      ...
      public String next(){
        if(!hasNext()){
          return null;
        }
        ...
      }
    }
    
    • 正确的代码示例
    public class MyIterator implements Iterator<String>{
      ...
      public String next(){
        if(!hasNext()){
          throw new NoSuchElementException();
        }
        ...
      }
    }
    

    规则S2273 : "wait", "notify" 以及 "notifyAll"只能对象被当前代码块所持有时访问

    当前Thread必须持有一个对象的监听器,才可以调用对象的wait,notify,notifyAll方法。

    • 错误的代码示例
    private void removeElement() {
      while (!suitableCondition()){
        obj.wait();
      }
      ... // Perform removal
    }
    

    or

    private void removeElement() {
      while (!suitableCondition()){
        wait();
      }
      ... // Perform removal
    }
    
    • 正确的代码示例
    private void removeElement() {
      synchronized(obj) {
        while (!suitableCondition()){
          obj.wait();
        }
        ... // Perform removal
      }
    }
    

    or

    private synchronized void removeElement() {
      while (!suitableCondition()){
        wait();
      }
      ... // Perform removal
    }
    

    规则S2275 : Printf样式的代码,必须符合参数类型。

    • 错误的代码示例
    String.format("The value of my integer is %d", "Hello World");  // 错误示范; an 'int' is expected rather than a String
    String.format("Duke's Birthday year is %tX", c);  // 错误示范; X is not a supported time conversion character
    String.format("Display %0$d and then %d", 1);   // 错误示范; arguments are numbered starting from 1
    String.format("Not enough arguments %d and %d", 1);  // 错误示范; the second argument is missing
    String.format("%< is equals to %d", 2);   // 错误示范; the argument index '<' refers to the previous format specifier but there isn't one
    
    MessageFormat.format("Result {1}.", value); // 错误示范; Not enough arguments. (first element is {0})
    MessageFormat.format("Result {{0}.", value); // 错误示范; Unbalanced number of curly brace (single curly braces should be escaped)
    MessageFormat.format("Result ' {0}", value); // 错误示范; Unbalanced number of quotes (single quote must be escaped)
    
    java.util.logging.Logger logger;
    logger.log(java.util.logging.Level.SEVERE, "Result {1}!", 14); // 错误示范 - Not enough arguments.
    
    org.slf4j.Logger slf4jLog;
    org.slf4j.Marker marker;
    
    slf4jLog.debug(marker, "message {}"); // 错误示范 - Not enough arguments.
    
    org.apache.logging.log4j.Logger log4jLog;
    log4jLog.debug("message {}"); // 错误示范 - Not enough arguments.
    
    • 正确的代码示例
    String.format("The value of my integer is %d", 3);
    String.format("Duke's Birthday year is %tY", c);
    String.format("Display %1$d and then %d", 1);
    String.format("Not enough arguments %d and %d", 1, 2);
    String.format("%d is equals to %<", 2);
    
    MessageFormat.format("Result {0}.", value);
    MessageFormat.format("Result {0} & {1}.", value, value);
    MessageFormat.format("Result {0}.", myObject);
    
    java.util.logging.Logger logger;
    logger.log(java.util.logging.Level.SEVERE, "Result {1},{2}!", 14, 2);
    
    org.slf4j.Logger slf4jLog;
    org.slf4j.Marker marker;
    
    slf4jLog.debug(marker, "message {}", 1);
    
    org.apache.logging.log4j.Logger log4jLog;
    log4jLog.debug("message {}", 1);
    

    规则S2276 : 如果持有对象锁,则应当使用"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();
      }
      ...
    }
    

    规则S2441 : "HttpSession"中只可以存储”可序列化对象“

    • 错误的代码示例
    public class Address {
      //...
    }
    
    //...
    HttpSession session = request.getSession();
    session.setAttribute("address", new Address());  // 错误示范; Address isn't serializable
    

    规则S2445 : synchronized只能用于"private final"属性

    否则无法保证有序性。

    • 错误的代码示例
    private String color = "red";
    
    private void doSomething(){
      synchronized(color) {  // 错误示范; lock is actually on object instance "red" referred to by the color variable
        //...
        color = "green"; // other threads now allowed into this block
        // ...
      }
      synchronized(new Object()) { // 错误示范 this is a no-op.
         // ...
      }
    }
    
    • 正确的代码示例
    private String color = "red";
    private final Object lockObj = new Object();
    
    private void doSomething(){
      synchronized(lockObj) {
        //...
        color = "green";
        // ...
      }
    }
    

    规则S2446 : 应当使用"notifyAll",而非”notify“

    • 错误的代码示例
    class MyThread extends Thread{
    
      @Override
      public void run(){
        synchronized(this){
          // ...
          notify();  // 错误示范
        }
      }
    }
    
    • 正确的代码示例
    class MyThread extends Thread{
    
      @Override
      public void run(){
        synchronized(this){
          // ...
          notifyAll();
        }
      }
    }
    

    规则S2583 : 条件代码必须保证可达性

    • 错误的代码示例
    a = false;
    if (a) { // 错误示范
      doSomething(); // never executed
    }
    
    if (!a || b) { // 错误示范; "!a" is always "true", "b" is never evaluated
      doSomething();
    } else {
      doSomethingElse(); // never executed
    }
    
    • 特殊情况

    如果满足如下任一条件,不构成错误。

    1. 如果变量为final
    final boolean debug = false;
    //...
    if (debug) {
      // Print something
    }
    
    1. 如果不使用变量,而直接使用true或false
    if (true) {
      // do something
    }
    

    如上代码,可以认为是开发人员有意而为之。

    规则S2637 : "@NonNull"不可以设置为null

    • 错误的代码示例
    public class MainClass {
    
      @Nonnull
      private String primary;
      private String secondary;
    
      public MainClass(String color) {
        if (color != null) {
          secondary = null;
        }
        primary = color;  // 错误示范; "primary" is Nonnull but could be set to null here
      }
    
      public MainClass() { // 错误示范; "primary" Nonnull" but is not initialized
      }
    
      @Nonnull
      public String indirectMix() {
        String mix = null;
        return mix;  // 错误示范; return value is Nonnull, but null is returned.}}
      }
    

    规则S2639 : 不可以使用非法的表达式

    例如

    • .用于匹配任意字符,如果用于String的replaceAll,则匹配所有的字符,而不是一个字符。

    • |会匹配任意两个字符之间的间隔。

    • File.separator匹配所有路径分隔符,但是在Windows中会匹配转义字符。

    • 错误的代码示例

    String str = "/File|Name.txt";
    
    String clean = str.replaceAll(".",""); // 错误示范; probably meant to remove only dot chars, but returns an empty string
    String clean2 = str.replaceAll("|","_"); // 错误示范; yields _/_F_i_l_e_|_N_a_m_e_._t_x_t_
    String clean3 = str.replaceAll(File.separator,"); // 错误示范; exception on Windows
    
    String clean4 = str.replaceFirst(".","); // 错误示范;
    String clean5 = str.replaceFirst("|","_"); // 错误示范;
    String clean6 = str.replaceFirst(File.separator,"); // 错误示范;
    

    规则S2674 : stream操作的所有返回值必须进行检查

    • 错误的代码示例
    public void doSomething(String fileName) {
      try {
        InputStream is = new InputStream(file);
        byte [] buffer = new byte[1000];
        is.read(buffer);  // 错误示范
        // ...
      } catch (IOException e) { ... }
    }
    
    • 正确的代码示例
    public void doSomething(String fileName) {
      try {
        InputStream is = new InputStream(file);
        byte [] buffer = new byte[1000];
        int count = 0;
        while (count = is.read(buffer) > 0) {
          // ...
        }
      } catch (IOException e) { ... }
    }
    

    规则S2676 : "Math.abs"以及负号不得用于所有可能为"MIN_VALUE"的变量

    • 错误的代码示例
    public void doSomething(String str) {
      if (Math.abs(str.hashCode()) > 0) { // 错误示范
        // ...
      }
    }
    
    • 正确的代码示例
    public void doSomething(String str) {
      if (str.hashCode() != 0) {
        // ...
      }
    }
    

    规则S2677 : "read" 以及 "readLine" 返回值必须被使用。

    • 错误的代码示例
    public void doSomethingWithFile(String fileName) {
      BufferedReader buffReader = null;
      try {
        buffReader = new BufferedReader(new FileReader(fileName));
        while (buffReader.readLine() != null) { // 错误示范
          // ...
        }
      } catch (IOException e) {
        // ...
      }
    }
    
    • 正确的代码示例
    public void doSomethingWithFile(String fileName) {
      BufferedReader buffReader = null;
      try {
        buffReader = new BufferedReader(new FileReader(fileName));
        String line = null;
        while ((line = buffReader.readLine()) != null) {
          // ...
        }
      } catch (IOException e) {
        // ...
      }
    }
    

    规则S2689 : 使用“append”模式打开的文件,不可以用于"ObjectOutputStream"

    • 错误的代码示例
    FileOutputStream fos = new FileOutputStream (fileName , true);  // fos opened in append mode
    ObjectOutputStream out = new ObjectOutputStream(fos);  // 错误示范
    
    • 正确的代码示例
    FileOutputStream fos = new FileOutputStream (fileName);
    ObjectOutputStream out = new ObjectOutputStream(fos);
    

    规则S2695 : "PreparedStatement" 以及 "ResultSet" 方法必须使用有效的下标

    这两个类的下标从1开始,而不是从0开始。

    • 错误的代码示例
    PreparedStatement ps = con.prepareStatement("SELECT fname, lname FROM employees where hireDate > ? and salary < ?");
    ps.setDate(0, date);  // 错误示范
    ps.setDouble(3, salary);  // 错误示范
    
    ResultSet rs = ps.executeQuery();
    while (rs.next()) {
      String fname = rs.getString(0);  // 错误示范
      // ...
    }
    
    • 正确的代码示例
    PreparedStatement ps = con.prepareStatement("SELECT fname, lname FROM employees where hireDate > ? and salary < ?");
    ps.setDate(1, date);
    ps.setDouble(2, salary);
    
    ResultSet rs = ps.executeQuery();
    while (rs.next()) {
      String fname = rs.getString(1);
      // ...
    }
    

    规则S2757 : "=+" 不可以用于替换"+="

    • 错误的代码示例
    int target = -5;
    int num = 3;
    
    target =- num;  // 错误示范; target = -3. Is that really what's meant?
    target =+ num; // 错误示范; target = 3
    
    • 正确的代码示例
    int target = -5;
    int num = 3;
    
    target = -num;  // Compliant; intent to assign inverse value of num is clear
    target += num;
    

    规则S2761 : 一元操作不可以重复

    一元操作包括:!, ~, -, and +.

    • 错误的代码示例
    int i = 1;
    
    int j = - - -i;  // 错误示范; just use -i
    int k = ~~~i;    // 错误示范; same as i
    int m = + +i;    // 错误示范; operators are useless here
    
    boolean b = false;
    boolean c = !!!b;   // 错误示范
    
    • 正确的代码示例
    int i =  1;
    
    int j = -i;
    int k = ~i;
    int m =  i;
    
    boolean b = false;
    boolean c = !b;
    

    规则S2789 : "Optional"本身不可以为null

    • 错误的代码示例
    public void doSomething () {
      Optional<String> optional = getOptional();
      if (optional != null) {  // 错误示范
        // do something with optional...
      }
    }
    
    @Nullable // 错误示范
    public Optional<String> getOptional() {
      // ...
      return null;  // 错误示范
    }
    
    • 正确的代码示例
    public void doSomething () {
      Optional<String> optional = getOptional();
      optional.ifPresent(
        // do something with optional...
      );
    }
    
    public Optional<String> getOptional() {
      // ...
      return Optional.empty();
    }
    

    规则S2885 : static变量必须保证线程安全性

    • 错误的代码示例
    public class MyClass {
      private static SimpleDateFormat format = new SimpleDateFormat("HH-mm-ss");  // 错误示范
      private static Calendar calendar = Calendar.getInstance();  // 错误示范
    
    • 正确的代码示例
    public class MyClass {
      private SimpleDateFormat format = new SimpleDateFormat("HH-mm-ss");
      private Calendar calendar = Calendar.getInstance();
    

    规则S2886 : Getters和Setters需要成对进行synchronized

    • 错误的代码示例
    public class Person {
      String name;
      int age;
    
      public synchronized void setName(String name) {
        this.name = name;
      }
    
      public String getName() {  // 错误示范
        return this.name;
      }
    
      public void setAge(int age) {  // 错误示范
        this.age = age;
      }
    
      public int getAge() {
        synchronized (this) {
          return this.age;
        }
      }
    }
    
    • 正确的代码示例
    public class Person {
      String name;
      int age;
    
      public synchronized void setName(String name) {
        this.name = name;
      }
    
      public synchronized String getName() {
        return this.name;
      }
    
      public void setAge(int age) {
        synchronized (this) {
          this.age = age;
       }
      }
    
      public int getAge() {
        synchronized (this) {
          return this.age;
        }
      }
    }
    

    规则S3020 : "toArray"需要传入类型参数

    • 错误的代码示例
    public String [] getStringArray(List<String> strings) {
      return (String []) strings.toArray();  // 错误示范; ClassCastException thrown
    }
    
    • 正确的代码示例
    public String [] getStringArray(List<String> strings) {
      return strings.toArray(new String[0]);
    }
    

    规则S3032 : JEE 应用不可以使用"getClassLoader"

    • 错误的代码示例
    ClassLoader cl = this.getClass().getClassLoader();  // 错误示范
    
    • 正确的代码示例
    ClassLoader cl = Thread.currentThread().getContextClassLoader();
    

    规则S3034 : 原始byte数据,不可以直接用于组合位操作

    • 错误的代码示例
      int intFromBuffer() {
        int result = 0;
        for (int i = 0; i < 4; i++) {
          result = (result << 8) | readByte(); // 错误示范
        }
        return result;
      }
    
    • 正确的代码示例
      int intFromBuffer() {
        int result = 0;
        for (int i = 0; i < 4; i++) {
          result = (result << 8) | (readByte() & 0xff);
        }
        return result;
      }
    

    规则S3039 : "String"操作不可以越界

    • 错误的代码示例
    String speech = "Now is the time for all good people to come to the aid of their country.";
    
    String substr1 = speech.substring(-1, speech.length());  // 错误示范; start and end values both bad
    String substr2 = speech.substring(speech.length(), 0); // 错误示范, start value must be < end value
    char ch = speech.charAt(speech.length());  // 错误示范
    
    • 正确的代码示例
    String speech = "Now is the time for all good people to come to the aid of their country.";
    
    String substr1 = speech; // Closest correct values to original code yield whole string
    String substr2 = new StringBuilder(speech).reverse().toString()
    char ch = speech.charAt(speech.length()-1);
    

    规则S3046 : 如果同时持有多个对象锁,则不应该调用"wait"

    否则有可能导致死锁。

    • 错误的代码示例
    synchronized (this.mon1) {  // threadB can't enter this block to request this.mon2 lock & release threadA
        synchronized (this.mon2) {
            this.mon2.wait();  // 错误示范; threadA is stuck here holding lock on this.mon1
        }
    }
    

    规则S3064 : 如果使用双锁检查机制,则懒加载的赋值必须最后进行

    • 错误的代码示例
    public class MyClass {
    
      private volatile List<String> strings;
    
      public List<String> getStrings() {
        if (strings == null) {  // check#1
          synchronized(MyClass.class) {
            if (strings == null) {
              strings = new ArrayList<>();  // 错误示范
              strings.add("Hello");  //When threadA gets here, threadB can skip the synchronized block because check#1 is false
              strings.add("World");
            }
          }
        }
        return strings;
      }
    }
    
    • 正确的代码示例
    public class MyClass {
    
      private volatile List<String> strings;
    
      public List<String> getStrings() {
        if (strings == null) {  // check#1
          synchronized(MyClass.class) {
            if (strings == null) {
              List<String> tmpList = new ArrayList<>();
              tmpList.add("Hello");
              tmpList.add("World");
              strings = tmpList;
            }
          }
        }
        return strings;
      }
    }
    
    

    规则S3065 : "Min"和"Max"用于组合操作时,不应该返回同一个值

    • 错误的代码示例
      private static final int UPPER = 20;
      private static final int LOWER = 0;
    
      public int doRangeCheck(int num) {    // Let's say num = 12
        int result = Math.min(LOWER, num);  // result = 0
        return Math.max(UPPER, result);     // 错误示范; result is now 20: even though 12 was in the range
      }
    
    • 正确的代码示例
      private static final int UPPER = 20;
      private static final int LOWER = 0;
    
      public int doRangeCheck(int num) {    // Let's say num = 12
        int result = Math.max(LOWER, num);  // result = 12
        return Math.min(UPPER, result);     // Compliant; result is still 12
      }
    

      private static final int UPPER = 20;
      private static final int LOWER = 0;
    
      public int doRangeCheck(int num) {    // Let's say num = 12
        int result = Math.min(UPPER, num);  // result = 12
        return Math.max(LOWER, result);     // Compliant; result is still 12
      }
    

    规则S3067 : 不可以将"getClass"用于synchronized

    • 错误的代码示例
    public class MyClass {
      public void doSomethingSynchronized(){
        synchronized (this.getClass()) {  // 错误示范
          // ...
        }
      }
    
    • 正确的代码示例
    public class MyClass {
      public void doSomethingSynchronized(){
        synchronized (MyClass.class) {
          // ...
        }
      }
    

    规则S3077 : "volatile"只用于基本类型(int、bool等)

    • 错误的代码示例
    private volatile int [] vInts;  // 错误示范
    private volatile MyObj myObj;  // 错误示范
    
    • 正确的代码示例
    private AtomicIntegerArray vInts;
    private MyObj myObj;
    

    规则S3078 : "volatile"不可用于复合赋值运算符

    • 错误的代码示例
    private volatile int count = 0;
    private volatile boolean boo = false;
    
    public void incrementCount() {
      count++;  // 错误示范
    }
    
    public void toggleBoo(){
      boo = !boo;  // 错误示范
    }
    
    • 正确的代码示例
    private AtomicInteger count = 0;
    private boolean boo = false;
    
    public void incrementCount() {
      count.incrementAndGet();
    }
    
    public synchronized void toggleBoo() {
      boo = !boo;
    }
    

    规则S3306 : 使用构造函数注入代替属性值注入

    • 错误的代码示例
    class MyComponent {  // Anyone can call the default constructor
    
      @Inject MyCollaborator collaborator;  // 错误示范
    
      public void myBusinessMethod() {
        collaborator.doSomething();  // this will fail in classes new-ed by a caller
      }
    }
    
    • 正确的代码示例
    class MyComponent {
    
      private final MyCollaborator collaborator;
    
      @Inject
      public MyComponent(MyCollaborator collaborator) {
        Assert.notNull(collaborator, "MyCollaborator must not be null!");
        this.collaborator = collaborator;
      }
    
      public void myBusinessMethod() {
        collaborator.doSomething();
      }
    }
    

    规则S3346 : "assert"操作不应当对数据进行操作和影响

    • 错误的代码示例
    assert myList.remove(myList.get(0));  // 错误示范
    
    • 正确的代码示例
    boolean removed = myList.remove(myList.get(0));
    assert removed;
    

    规则S3422 : "Dependencies"不可使用"system" 作用域

    • 错误的代码示例
    <dependency>
      <groupId>javax.sql</groupId>
      <artifactId>jdbc-stdext</artifactId>
      <version>2.0</version>
      <scope>system</scope>  <!-- Noncompliant -->
      <systemPath>/usr/bin/lib/rt.jar</systemPath>  <!-- remove this -->
    </dependency>
    

    规则S3436 : 值传递类(Optional等)不可用于锁操作

    • 错误的代码示例
    Optional<Foo> fOpt = doSomething();
    synchronized (fOpt) {  // 错误示范
      // ...
    }
    

    规则S3438 : Spring的"SingleConnectionFactory" 应当设置"reconnectOnException"

    • 错误的代码示例
     <bean id="singleCF" class="org.springframework.jms.connection.SingleConnectionFactory">  <!-- Noncompliant -->
       <constructor-arg ref="dummyConnectionFactory" />
     </bean>
    
    • 正确的代码示例
     <bean id="singleCF" class="org.springframework.jms.connection.SingleConnectionFactory" p:reconnectOnException="true">
       <constructor-arg ref="dummyConnectionFactory" />
     </bean>
    

    or

     <bean id="singleCF" class="org.springframework.jms.connection.SingleConnectionFactory">
       <constructor-arg ref="dummyConnectionFactory" />
       <property name="reconnectOnException"><value>true</value></property>
     </bean>
    

    规则S3439 : "DefaultMessageListenerContainer" 在重启期间不应丢弃消息

    • 错误的代码示例
    <bean id="listenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">  <!-- Noncompliant -->
       <property name="connectionFactory" ref="connFactory" />
       <property name="destination" ref="dest" />
       <property name="messageListener" ref="serviceAdapter" />
       <property name="autoStartup" value="true" />
       <property name="concurrentConsumers" value="10" />
       <property name="maxConcurrentConsumers" value="10" />
       <property name="clientId" value="myClientID" />
    </bean>
    
    • 正确的代码示例
    <bean id="listenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
       <property name="connectionFactory" ref="connFactory" />
       <property name="destination" ref="dest" />
       <property name="messageListener" ref="serviceAdapter" />
       <property name="autoStartup" value="true" />
       <property name="concurrentConsumers" value="10" />
       <property name="maxConcurrentConsumers" value="10" />
       <property name="clientId" value="myClientID" />
       <property name="acceptMessagesWhileStopping" value="true" />
    </bean>
    

    规则S3518 : 不可以除以0

    • 错误的代码示例
    void test_divide() {
      int z = 0;
      if (unknown()) {
        // ..
        z = 3;
      } else {
        // ..
      }
      z = 1 / z; // 错误示范, possible division by zero
    }
    
    • 正确的代码示例
    void test_divide() {
      int z = 0;
      if (unknown()) {
        // ..
        z = 3;
      } else {
        // ..
        z = 1;
      }
      z = 1 / z;
    }
    

    规则S3546 : 自定义资源应当关闭

    自定义资源必须关闭,否则将导致资源泄露。

    <ul>
    <li> {rule:java:S2095} - Resources should be closed </li>
    </ul>

    规则S3551 : 子类对父类的线程同步的操作需要具有继承性

    • 错误的代码示例
    public class Parent {
    
      synchronized void foo() {
        //...
      }
    }
    
    public class Child extends Parent {
    
     @Override
      public foo () {  // 错误示范
        // ...
        super.foo();
      }
    }
    
    • 正确的代码示例
    public class Parent {
    
      synchronized void foo() {
        //...
      }
    }
    
    public class Child extends Parent {
    
      @Override
      synchronized foo () {
        // ...
        super.foo();
      }
    }
    

    规则S3599 : "Double Brace Initialization"不可以使用

    会造成内存泄漏。

    • 错误的代码示例
    Map source = new HashMap(){{ // 错误示范
        put("firstName", "John");
        put("lastName", "Smith");
    }};
    
    • 正确的代码示例
    Map source = new HashMap();
    // ...
    source.put("firstName", "John");
    source.put("lastName", "Smith");
    // ...
    

    规则S3655 : 只能在"isPresent()"判断之后进行,"Optional"变量的访问。

    • 错误的代码示例
    Optional<String> value = this.getOptionalValue();
    
    // ...
    
    String stringValue = value.get(); // 错误示范
    
    • 正确的代码示例
    Optional<String> value = this.getOptionalValue();
    
    // ...
    
    if (value.isPresent()) {
      String stringValue = value.get();
    }
    

    or

    Optional<String> value = this.getOptionalValue();
    
    // ...
    
    String stringValue = value.orElse("default");
    

    规则S3750 : Spring "@Controller"类不应当使用"@Scope"

    • 错误的代码示例
    @Scope("prototype")  // 错误示范
    @Controller
    public class HelloWorld {
    
    • 正确的代码示例
    @Controller
    public class HelloWorld {
    

    规则S3753 : Spring "@Controller"类中,如果使用"@SessionAttributes",则必须调用"SessionStatus"的"setComplete"方法

    • 错误的代码示例
    @Controller
    @SessionAttributes("hello")  // 错误示范; this doesn't get cleaned up
    public class HelloWorld {
    
      @RequestMapping("/greet", method = GET)
      public String greet(String greetee) {
    
        return "Hello " + greetee;
      }
    }
    
    • 正确的代码示例
    @Controller
    @SessionAttributes("hello")
    public class HelloWorld {
    
      @RequestMapping("/greet", method = GET)
      public String greet(String greetee) {
    
        return "Hello " + greetee;
      }
    
      @RequestMapping("/goodbye", method = POST)
      public String goodbye(SessionStatus status) {
        //...
        status.setComplete();
      }
    
    }
    

    规则S3822 : "Hibernate"不可以更新"schemas"

    • 错误的代码示例
    <session-factory>
      <property name="hibernate.hbm2ddl.auto">update</property>  <!-- Noncompliant -->
    </session-factory>
    
    • 正确的代码示例
    <session-factory>
      <property name="hibernate.hbm2ddl.auto">validate</property>  <!-- Compliant -->
    </session-factory>
    

    or

    <session-factory>
      <!-- Property deleted -->
    </session-factory>
    

    规则S3923 : 条件代码中,不同的分支内部的代码逻辑不能完全一致

    • 错误的代码示例
    if (b == 0) {  // 错误示范
      doOneMoreThing();
    } else {
      doOneMoreThing();
    }
    
    int b = a > 12 ? 4 : 4;  // 错误示范
    
    switch (i) {  // 错误示范
      case 1:
        doSomething();
        break;
      case 2:
        doSomething();
        break;
      case 3:
        doSomething();
        break;
      default:
        doSomething();
    }
    
    • 特殊情况,可以存在同样的代码块

    如果if逻辑没有else,只有else-if;或者,switch没有default的逻辑。

    if(b == 0) {    //no issue, this could have been done on purpose to make the code more readable
      doSomething();
    } else if(b == 1) {
      doSomething();
    }
    

    规则S3958 : 中间流的返回值必须被使用

    • 错误的代码示例
    widgets.stream().filter(b -> b.getColor() == RED); // 错误示范
    
    • 正确的代码示例
    int sum = widgets.stream()
                          .filter(b -> b.getColor() == RED)
                          .mapToInt(b -> b.getWeight())
                          .sum();
    Stream<Widget> pipeline = widgets.stream()
                                     .filter(b -> b.getColor() == GREEN)
                                     .mapToInt(b -> b.getWeight());
    sum = pipeline.sum();
    

    规则S3959 : "Consumed Stream"的结果不可以重复使用。

    • 错误的代码示例
    Stream<Widget> pipeline = widgets.stream().filter(b -> b.getColor() == RED);
    int sum1 = pipeline.sum();
    int sum2 = pipeline.mapToInt(b -> b.getWeight()).sum(); // 错误示范
    

    规则S3981 : 集合的大小和数组的长度的比较操作必须有效

    • 错误的代码示例
    if (myList.size() >= 0) { ... }
    
    if (myList.size() < 0) { ... }
    
    boolean result = myArray.length >= 0;
    
    if (0 > myArray.length) { ... }
    
    • 正确的代码示例
    if (!myList.isEmpty()) { ... }
    
    if (myArray.length >= 42) { ... }
    

    规则S3984 : "Exception"如果被创建,则必须被抛出。

    • 错误的代码示例
    if (x < 0)
      new IllegalArgumentException("x must be nonnegative");
    
    • 正确的代码示例
    if (x < 0)
      throw new IllegalArgumentException("x must be nonnegative");
    

    规则S3986 : 不应当使用【周年】格式 ("YYYY")

    • 错误的代码示例
    Date date = new SimpleDateFormat("yyyy/MM/dd").parse("2015/12/31");
    String result = new SimpleDateFormat("YYYY/MM/dd").format(date);   // 错误示范; yields '2016/12/31'
    
    • 正确的代码示例
    Date date = new SimpleDateFormat("yyyy/MM/dd").parse("2015/12/31");
    String result = new SimpleDateFormat("yyyy/MM/dd").format(date);   //Yields '2015/12/31' as expected
    
    • Exceptions
    Date date = new SimpleDateFormat("yyyy/MM/dd").parse("2015/12/31");
    String result = new SimpleDateFormat("YYYY-ww").format(date);  //compliant, 'Week year' is used along with 'Week of year'. result = '2016-01'
    

    规则S4143 : 不应当重复的进行数据的重复写

    • 错误的代码示例
    letters.put("a", "Apple");
    letters.put("a", "Boy");  // 错误示范
    
    towns[i] = "London";
    towns[i] = "Chicago";  // 错误示范
    

    规则S4275 : Getters和Setters应当访问适当的属性

    • 错误的代码示例
    class A {
      private int x;
      private int y;
    
      public void setX(int val) { // 错误示范: field 'x' is not updated
        this.y = val;
      }
    
      public int getY() { // 错误示范: field 'y' is not used in the return value
        return this.x;
      }
    }
    
    • 正确的代码示例
    class A {
      private int x;
      private int y;
    
      public void setX(int val) {
        this.x = val;
      }
    
      public int getY() {
        return this.y;
      }
    }
    

    规则S4348 : "iterator"不可以返回"this"

    • 错误的代码示例
    class FooIterator implements Iterator<Foo>, Iterable<Foo> {
      private Foo[] seq;
      private int idx = 0;
    
      public boolean hasNext() {
        return idx < seq.length;
      }
    
      public Foo next() {
        return seq[idx++];
      }
    
      public Iterator<Foo> iterator() {
        return this; // 错误示范
      }
      // ...
    }
    
    • 正确的代码示例
    class FooSequence implements Iterable<Foo> {
      private Foo[] seq;
    
      public Iterator<Foo> iterator() {
        return new Iterator<Foo>() {
          private int idx = 0;
    
          public boolean hasNext() {
            return idx < seq.length;
          }
    
          public Foo next() {
            return seq[idx++];
          }
        };
      }
      // ...
    }
    

    规则S4351 : "compareTo"不可以重载,只允许重写

    • 错误的代码示例
    public class Foo {
      static class Bar implements Comparable<Bar> {
        public int compareTo(Bar rhs) {
          return -1;
        }
      }
    
      static class FooBar extends Bar {
        public int compareTo(FooBar rhs) {  // 错误示范: Parameter should be of type Bar
          return 0;
        }
      }
    }
    
    • 正确的代码示例
    public class Foo {
      static class Bar implements Comparable<Bar> {
        public int compareTo(Bar rhs) {
          return -1;
        }
      }
    
      static class FooBar extends Bar {
        public int compareTo(Bar rhs) {
          return 0;
        }
      }
    }
    

    规则S4517 : "InputSteam.read()"的实现,不应该返回一个signed byte

    • 错误的代码示例
    @Override
    public int read() throws IOException {
      if (pos == buffer.length()) {
        return -1;
      }
      return buffer.getByte(pos++); // 错误示范, a signed byte value is returned
    }
    
    • 正确的代码示例
    @Override
    public int read() throws IOException {
      if (pos == buffer.length()) {
        return -1;
      }
      return buffer.getByte(pos++) & 0xFF; // The 0xFF bitmask is applied
    }
    

    规则S4602 : "@SpringBootApplication"和"@ComponentScan"不应该在default package

    • 错误的代码示例
    import org.springframework.boot.SpringApplication;
    
    @SpringBootApplication // 错误示范; RootBootApp is declared in the default package
    public class RootBootApp {
    ...
    }
    
    @ComponentScan(")
    public class Application {
    ...
    }
    
    • 正确的代码示例
    package hello;
    
    import org.springframework.boot.SpringApplication;
    
    @SpringBootApplication // Compliant; RootBootApp belongs to the "hello" package
    public class RootBootApp {
    ...
    }
    

    规则S4973 : "String"以及封箱的数据类型应当使用"equals()"进行比较

    • 错误的代码示例
    String firstName = getFirstName(); // String overrides equals
    String lastName = getLastName();
    
    if (firstName == lastName) { ... }; // Non-compliant; false even if the strings have the same value
    
    • 正确的代码示例
    String firstName = getFirstName();
    String lastName = getLastName();
    
    if (firstName != null && firstName.equals(lastName)) { ... };
    

    规则S5164 : 在不使用的时候,"ThreadLocal"应当及时清理

    • 错误的代码示例
    public class ThreadLocalUserSession implements UserSession {
    
      private static final ThreadLocal<UserSession> DELEGATE = new ThreadLocal<>();
    
      public UserSession get() {
        UserSession session = DELEGATE.get();
        if (session != null) {
          return session;
        }
        throw new UnauthorizedException("User is not authenticated");
      }
    
      public void set(UserSession session) {
        DELEGATE.set(session);
      }
    
       public void incorrectCleanup() {
         DELEGATE.set(null); // 错误示范
       }
    
      // some other methods without a call to DELEGATE.remove()
    }
    
    • 正确的代码示例
    public class ThreadLocalUserSession implements UserSession {
    
      private static final ThreadLocal<UserSession> DELEGATE = new ThreadLocal<>();
    
      public UserSession get() {
        UserSession session = DELEGATE.get();
        if (session != null) {
          return session;
        }
        throw new UnauthorizedException("User is not authenticated");
      }
    
      public void set(UserSession session) {
        DELEGATE.set(session);
      }
    
      public void unload() {
        DELEGATE.remove(); // Compliant
      }
    
      // ...
    }
    
    • 特殊情况

    非私有的 ThreadLocal 变量,将不会被检查,因为对象有可能被其他的类。

    相关文章

      网友评论

          本文标题:Java规范之Sonar规则的汉化【BUG类】

          本文链接:https://www.haomeiwen.com/subject/llxwjktx.html