code-review guidelines

Key points to check during code review of a class

  • Use singleton in a smart way so it is well managed in multi thread.

      public static class SingleTonClassHolder{
          public static MultyThreadSingleTon multyThreadSingleTon = new MultyThreadSingleTon();
      }
      
      public static MultyThreadSingleTon getInstance(){
              return SingleTonClassHolder.multyThreadSingleTon;
          }
    
  • Use static block to load any thing that is necessary to load during JVM loads the class in memory.

      private static int count;
      
          static{
              // code in this static block will be executed when
              // the JVM loads the class into memory
              count =1;
          }
      
          public Counter(){
              //A constructor will be invoked when an instance of the
              //class is created, while the static block will be invoked when the JVM loads the corresponding class.
              count++;
          }
    
  • Java 8 has introduced default keyword which is susceptible to define method body inside interface.

      public interface Interface1 {
      
          default void foo(){
              System.out.println("Interface1's foo");
          }
      }
    
  • If an interface contain only one abstract method then use @FunctionalInterface annotation.

      @FunctionalInterface // that has one abstract method, so it will compile cleanly
      public interface AnnotationTest {
      
          abstract int foo();
      }
    
  • If 2 different interfaces contain method that has same name then it is called diamond problem and in that case we can use super Interface1.super.method() like this.

      @Override
          public void foo() {
              //resolve the conflict manually by using the super keyword within the Diamond class to
              //explicitly mention which method definition to use:
              Interface1.super.foo();
          }
    
  • To initialize collections always use Interface type in this way

      List<String> myList = new ArrayList<String>()
    
  • Use isEmpty() to check list size

      if (!myList.isEmpty()) {
          // dos something if the list is not empty
      }   
    
  • Use enhanced for loop rather using classic for loop

      for(Person p: personList)  {
      // dos something
      } 
    
  • Use Comparable Interface to compare one object to other

      public class Person implements Comparable<Person>{
      
          @Override
          public int compareTo(Person person) {
              if(this.getAge() > person.getAge() ){
                 return 1;
              }else if(this.getAge() < person.getAge()){
                  return -1;
              }
              else
                 return 0;
          }  
          
      }
    
  • compare(obj1, obj2) is the method of the Comparator interface that is called on some object to compare two other objects

      The Comparator interface is typically used for sorting data structures (such as Collections.sort or Arrays.sort).             
    
  • Use stream api on collections (filter the list of people who is upper or equal to age 50)

      List<Person> olderList = new ArrayList<>();
      for(Person person: l ){
           if(person.getAge() >= 50){
               olderList.add(person);
           }
      }
      olderList.forEach(person -> System.out.println(person.getAge()));
    
    
      // now using stream api to filter the list using one conditions
      olderList = l.stream()
                   .filter(p->p.getAge()>= 50)
                   .collect(Collectors.toList());
      olderList.stream().forEach(person -> System.out.println(person.getAge()));  
    
  • Lambda expression need to use on methods

      ()-> {block statement} 
    

    Example:

      // without Lamda expression
      State state1 = new State(new OnStateChangeListener() {
          @Override
          public int onStateChange() {
              return 5;
          }
      });
    
      // with Lambda expression
      State state11 = new State(()-> {
          return 5;
      });  
    
  • Method reference in lambda expression
    There are four types of method references (assuming a class named Person with getName() method and a value named p of that type)

Type Method Reference Lambda Expression Traditional
Reference to a static method Math::square n-> Math.square(n) void square(n) {Math.square(n)}
Reference to a constructor Capital::new i-> new Capital(i) public Capital(i) { new Capital(i)}
Reference to an instance method Person::getName p-> p.getName() public String getName(Person p){p.getName()}
  • Use Callable and Future with ExecutorService because Runnable does not return any value after execution.

      ExecutorService executor = Executors.newSingleThreadExecutor();
    
      //The Callable interface is similar to Runnable,
      // they're both designed to be executed by another thread,
      // a Runnable however, does not return a result and cannot throw a checked exception.
      Callable c = () -> {
    
          int n=0;
          for (int i=0; i< 100; i++){n+= i;}
          return n;
    
      };
    
    
      Future<Long> future = executor.submit(c);
      try {
    
          Long result = future.get(); //waits for the thread to complete
          System.out.println(result);
    
      } catch (ExecutionException e) {
          e.printStackTrace();
      } catch (InterruptedException e) {
          e.printStackTrace();
      }
    
  • We can use Atomic that support lock-free and thread-safe programming on single variables. Among them, the AtomicInteger class is a wrapper class for an int value that allows it to be updated atomically.

      AtomicInteger at = new AtomicInteger(0); 
    
  • It is a fairly common mistake by Java programmers to forget releasing resources, even in the finally block.

    • Normally, a finally block is used to ensure that a resource is closed whether the try statement completes normally or not.

              BufferedReader br = new BufferedReader(new FileReader(path));
              try {
                  return br.readLine();
              } catch(IOException e) {
                  e.printStackTrace();
              } finally {
                  if (br != null) br.close();
              }
      
  • However, Java 7 introduced the try-with-resources statement, which ensures that each resource is closed at the end of the statement

              try (BufferedReader br = new BufferedReader(new FileReader(path))) {
                     return br.readLine();
                 }