The introduction of the JVM in the architecture also helped developers in creating robust and secure Java applications. So what is meant by “robust and secure”? As described in previous posts, bytecode is interpreted by a JVM, and a JVM contains a bytecode verifier. The bytecode verifier not only verifies the validity of the bytecode, but also maintains the integrity of the memory space used by each application running on it. If the bytecode is invalid, JVM simply refuses to run the code. Similarly, if the bytecode tries to access a memory location that does not belong to the memory space of the current application, the JVM rejects the code.
Now, in the first place, how can we have invalid bytecode or an invalid memory reference in a compiled Java application? The bytecode may be modified by a malicious hacker by opening the code in a binary editor, or it may simply get modified due to noise as it is transmitted over a network. Accordingly, even the memory references may get modified in the executable before it is referenced by the JVM at run time. Fortunately, the JVM traps such intentional and non-intentional errors before the code is executed on a real CPU, resulting in a very robust application that won’t crash our operating system. Java code is highly secure in the sense that it cannot be used to spread a virus on a target machine. Java code that runs under the tight surveillance of the JVM does not have direct access to the operating system resources. Such access is made through the JVM, which ensures all the necessary security for the operating system. Java has omitted one of the important features of C++, and that is pointer arithmetic. Java does not support the declaration of pointers and pointer arithmetic.
The lack of pointers also makes Java programs more robust and secure. Pointers are notorious for allowing malicious access to locations outside the executing program’s memory space. They can also be used for spreading viruses on the system. The elimination of pointers has helped developers in creating robust and secure applications in Java.
Java is both a statically and strongly typed language. The term static refers to compile time or the source code, whereas dynamic refers to the run time or the bytecode. A programming language is said to use static typing when type checking is performed during compile time as opposed to run time. In static typing, all expressions have their types determined at compile time, prior to when the program is executed. The word strong in the context of typing means that rules about the type system are enforced prior to the code being run. Thus, Java is considered to be both statically and strongly typed.
Another important consideration in making an application robust is the proper allocation and deallocation of memory and other system resources at run time. In C++, memory allocation and deallocation are the responsibility of the programmer. A developer may sometimes forget to deallocate a memory resource after it has been used. The worst case is when he deallocates memory that is still in use by some other part of the application. This results in chaos and hard-to track run time errors. Java eliminates this issue totally by providing automatic garbage collection. The Java run time assumes the responsibility of tracking the allocations and freeing memory resources when they are no longer referenced by any part of the application. This automatic garbage collection makes Java applications very robust.
Another reason behind why Java programs are so robust is the exception-handling mechanism. Whenever an error occurs in our running program, it will be handled by an exception handler in our code, provided us have one. As a developer, we are required to provide exception handlers at all appropriate places in our program. Java has an exception mechanism with two types of exceptions—checked and unchecked. The compiler makes the developer provide code to handle the checked exceptions, but not the run time (unchecked) ones. This mandatory requirement for processing checked exceptions results in more robust applications with fewer application crashes.