Showing posts with label Exception. Show all posts
Showing posts with label Exception. Show all posts

Saturday, January 16, 2016

Extracting root cause from Stack Trace

Don't tell me the problem; show me the logs first!

Whether you are a fresh graduate, an experienced programmer, QA engineer, production engineer or even a product manager - a good understanding of stack trace is vital to crack critical issues. Your ability to find the real culprit from a lengthy stack trace will be instrumental in resolving a problem. This is even more important if you work on a distributed system where you use many libraries so stack trace is not well structured. Let's start with a simple scenario-

Scenario 1: Simple

This is the most trivial case, where the exception gets thrown by a method of your project and during the call duration, it doesn't go out of your code base. This is the most trivial scenario which you will encounter but very important to understand how the stack trace gets printed.

Shown below is Eclipse screenshot of MyController.java which two classes. Right click and run the program. 

Let's Decode Above stack trace:
  • RuntimeException is shown in line number 29, in method MyService.four()
  • Method MyService.four() gets called by MyService.three() in line number 25
  • Method MyService.three() gets called by MyController.two() in line 11
  • Method MyController.two() gets called by MyController.one() in line 6
  • Method MyController.one() gets called by MyController.main() in line 17


First frame of stack trace holds all important information required to know the root cause. 
Be mindful of the very important line number 

Scenario 2: Chain Of Exception

Let's modify above code a bit by catching exception at the origin and then throwing a brand new Exception. 


Let's Decode Above stack trace:

This stack trace has a caused by section. It has only one caused by but in real applications you can have multiple caused by sections. The last caused by will have the root cause of the exception.


Caused by: java.lang.RuntimeException: here, comes the exception!
at MyService.four(MyController.java:30)


... 4 more


But, if you are using external jars or libraries, finding the root cause could be bit tricky as the real reason might be nested deep inside. In such case you should look for Class.method name which belongs to your application. Also, you should look the complete stack trace carefully as the real root cause could lie in any part of stack trace. 


References:
http://www.nurkiewicz.com/2011/09/logging-exceptions-root-cause-first.html
http://stackoverflow.com/questions/12688068/how-to-read-and-understand-the-java-stack-trace
http://stackoverflow.com/questions/3988788/what-is-a-stack-trace-and-how-can-i-use-it-to-debug-my-application-errors


Saturday, February 23, 2013

Runtime Exception in Java

Runtime Exceptions occur mostly due to some programming error, so as a programmer you need to be careful. Runtime exceptions (java.lang.RuntimeException) are unchecked; so compilers don't enforce you to handle them (either catch or throw). 

Below diagram shows the hierarchy of the Exception tree.


 

NullPointerException [api doc]

Thrown when an application attempts to use in null a case where an object is required. 

Below snippet throws NPE :

         String a = null;
         a.toString();

Java 7 adds a new utility class Objects [Java Doc];  Objects class has a method to perform the null check on an object.

           public foo(Bar bar){
                  this.bar = Objects.requireNonNull(bar);
           }

ClassCastException [api doc]

Thrown to indicate that the code has attempted to cast an object to a subclass of which it is not an instance.
        
Java allows you to cast one type to another provided they are compatible. And if the casting is done between two incompatible types (and compiler is unable to detect it); then you get this exception at Runtime. So this Exception is thrown when you try to downcast an object, but the actual type of class is not of that type. 

  1. Let's see below example:
          Object x = new Integer(0);
          System.out.println((String)x);
At compile time the type of x is Object, so x could be reference to String also (as Object is super class). But at execution time the type of x is Integer so its cast to String fails.  
    2.   Another case; you use code written before Java 1.5 with later version and mix Generics :

          List lll = new ArrayList();
          lll.add("sid");
          lll.add(2);
            
          Iterator<String> itr = lll.iterator();
          while(itr.hasNext()){
                System.out.println(" val "+ itr.next());  //Expects String only, but 2 is not
          } 

          String tmp = lll.get(1); //Throws ClassCastException; as type doesn't match

    3.   Casting an incompatible types
         
          class A {...}
          class B extends A {...}
          class C extends A {...}

          You can't cast a B to a C even though they're both of type A's.

IllegalArgumentException [api doc]

Thrown to indicate that a method has been passed an illegal or inappropriate argument.

 This Exception is usually thrown if the arguments of a method are invalid. This way it fails at the earliest if the argument is invalid. This is usually not done for private methods; as class Author can ensure their validity. When argument check fails IllegalArgumentException, NullPointerException or IllegalStateException is thrown. 

   public class IllegalArgumentTest{
        public IllegalArgumentTest ( String name, double age ) {
            if ( name == null ) {
                throw new IllegalArgumentException("Name has no content.");
            }
            if ( age < 18.0f ) {
                 throw new IllegalArgumentException(" Person is not adult");
            }
            fname = name;
            fage = age;
        }
    //other methods..
  }
  You can document these exceptions in @throw clause of the method javadoc as they clearly state method requirement to the caller.

IllegalStateException [api doc]

Signals that a method has been invoked at an illegal or inappropriate time. In other words, the Java environment or Java application is not in an appropriate state for the requested operation.

 This Exception is thrown in below situations:
  1. When you try to notify a thread that isn't in waiting state mode.
  2. When you try to run an already running thread. 
  3. When you try to call remove method twice while iterating a Collection (i.e. iterator.remove())
  4. ArrayBlockingQueue.add() throws this Exception if Queue is already full.

And Effective Java says (Item 60, page 248):
Another commonly reused exception is IllegalStateException. This is generally the exception to throw if the invocation is illegal because of the state of the receiving object. For example, this would be the exception to throw if the caller attempted to use some object before it had been properly initialized.

ConcurrentModificationException [api doc]

This exception may be thrown by methods that have detected concurrent modification of an object when such modification is not permissible.
  1. Between creating an iterator and actually iterating the content you shouldn't modify the collection.        
            List<String> list = new ArrayList<String>();
            list.add("a1");
            list.add("a2");
           
            Iterator<String> iterator = list.iterator();
            list.add("a3");  //CME
           
            while(iterator.hasNext()){
                System.out.println(iterator.next());

            }         
  1.  Even if you try to modify list during iteration other than by using iteraot.remove(); you will get this exception.                                                                                                         
                 while(iterator.hasNext()){
                      System.out.println(iterator.next());
                      list.add("d1"); 
//CME

                     list.remove(0);  //CME
                }

UnsupportedOperationException [api doc]

Thrown to indicate that the requested operation is not supported. 

This is used by Collection framework to notify that a particular operation is not supported for the given Object.


        List<String> list = new ArrayList<String>();
        list.add("a1");
        list.add("a2");
       
        List<String> readList =  Collections.unmodifiableList(list);
        readList.add("a3");


Above snippet will throw UnsupportedOperationException because it's modifying a read only list.

CloneNotSupportedException [api doc]

Thrown to indicate that the clone method in class Object has been called to clone an object, but that the object's class does not implement the Cloneable interface.