Understanding Compile-Time vs. Run-Time Errors

In Java, there are two major types of errors: compile-time errors and run-time errors.

Compile-time errors are those preventing the code from being compiled. Such errors can be either a syntax error or an error in the structure of the application.

  • Syntax errors are those that break a fundamental rule of Java syntax such as no semicolon at the end of a statement.
  • Other compile-time errors are related to the fundamental rules of workflow. For example, a variable named x is declared twice in the same scope.

Run-time errors (often referred to as exceptions) are those only happen at run time and can’t be caught when the code is compiled. For instance, access to the element at index 5 of an array of length 4 throws a run-time error. The compiler says it looks good and compile the code; but when the application run, it is killed by an exception called ArrayIndexOutOfBoundsException.

// File Name : ExceptionTest.java
import java.io.*;
public class ExceptionTest{
   static double a[];
   public static void main(String args[]){
        a = new double[4];
        printElement(4); // the four accessible elements include 0, 1, 2, 3
   }
   static void printElement(int i) {
   	System.out.println("The 5th element is :" + a[i]);
   }
}

Above code produce:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 4

at ExceptionTest.printElement(ExceptionTest.java:10)

at ExceptionTest.main(ExceptionTest.java:7)

Exception Handling

What happens to the program and how to deal with such run-time error? The first thing you need to know is that when an exception occurs, an exception object is created. In general, Java platform throws the exception object, signaling an unexpected situation such as divided by zero or access non-existing elements like in the code above. Then, the best choice for the platform is to kill your program. But, you don't want to have your program killed unexpectedly, right? Let us tell Java to wait for you to handle the situation using a powerful tool called try/catch.

In the try block, you put the code that may throw predictable types of exceptions, or a general run-time exception. Then, add one or several catch blocks that can handle the exceptions. When the code in the try block throws an exception, that exception will be handled in the catch block whose argument is of the corresponding exception type.

// File Name : CatchExceptionTest.java
import java.io.*;
public class CatchExceptionTest{

   static double a[];
   public static void main(String args[]){
        a = new double[4];
        try {
            printElement(4);
        } catch(ArrayIndexOutOfBoundsException e){
        //Handle exception of type ArrayIndexOutOfBoundsException
         System.out.println("Catch exception :" + e);
      } catch(Exception e1)
      {
         //Handle exception of type Exception
      }
        
   }
   static void printElement(int i) {
   	System.out.println("The 5th element is :" + a[i]);
   }
}

Above code produce:

Catch exception  :java.lang.ArrayIndexOutOfBoundsException: 4

The throw and throws Keywords

To indicate a run-time error, you might intentionally throw an exception with customized attributes.

static void printElement(int i) {

   if (i >= a.length) {
	   throw new ArrayIndexOutOfBoundsException("Access element " + (i + 1) + " of an array of length " + a.length);
   }

   System.out.println("The 5th element is :" + a[i]);
}

Let us replace the snippet above into CatchExceptionTest.java to have the code produced the customized message

Catch exception :java.lang.ArrayIndexOutOfBoundsException: Access element 5 of an array of length 4

Despite being unable to catch run-time errors, the compile is actually smart enough to give warnings if possible exceptions are specified using the throws (not throw) keyword. In practice, it is advisable to state that your method might throw some certain types of exceptions. Here is how to write it:

static void printElement(int i) throws ArrayIndexOutOfBoundsException

The finally Keyword

Typically, we expect the try/catch block to do something or handle exceptions that occur, then continue the flow of code. What happens if the catch block throws an exception? It is okay to add another try/catch block inside the catch block. Yet, the code will look confusing if there are several nested catch blocks. Fortunately, Java allows you to specify a block of code that should be executed whatever happens inside the try/catch block. This block is called the finally block.

In other words, a finally block helps ensure that however the method exit, some cleanup code will be executed.

{
    InputStream in = new FileInputStream(inputFileName);
    
    OutputStream out = new FileOutputStream(outputFileName);    
    try {
        copy(in, out);
        out.flush(); // Doesn't actually do anything in this specific case.
    } catch (IOException exc) {
        throw exec;
    }finally {
        in.close();
        out.close();
    }
}

In the above code, in and out streams are always closed regardless of where or which exception raised.

Create your own Exception type

The Java platform provides a lot of exception classes you can use. If none of them satisfy your requirements, it is recommended that you write your own exception classes simply by extending the Exception class.

class MyException extends Exception{
   public MyException(String msg) {
   	message = msg;
   }
   private String message;
   public String what() {
   	return message;
   }
}

Then, you can throw the exception by typing the below statement and get the message using a method like what().

throw new MyException("The code is broken")

Summary

  • There are two types of errors: compile-time errors and run-time errors.
  • Run-time errors cause the Java platform to throw an exception.
  • To avoid the program being killed, the exceptions must be handled using a try-catch block.
  • The catch block is designed to catch only exceptions of the type specified.
  • Regardless of where and what exception occurs or no exception occurs at all, the finally block will be executed, offering a final chance to do cleanup code.
Polymorphism
Polymorphism
Previous Article
Data Structure
Data Structure
Next Article
Lakshay Sharma
I’M LAKSHAY SHARMA AND I’M A FULL-STACK TEST AUTOMATION ENGINEER. Have passed 16 years playing with automation in mammoth projects like O2 (UK), Sprint (US), TD Bank (CA), Canadian Tire (CA), NHS (UK) & ASOS(UK). Currently, I am working with RABO Bank as a Chapter Lead QA. I am passionate about designing Automation Frameworks that follow OOPS concepts and Design patterns.
Reviewers
Virender Singh's Photo
Virender Singh

Similar Articles

Feedback