0% found this document useful (0 votes)
10 views

Java Language Basics

The document provides an overview of Java language basics, focusing on the main method, the differences between JDK, JRE, and JVM, and the execution flow of Java programs. It explains the architecture of the JVM, including class loaders, memory areas, and the execution engine, as well as the components of a Java class and the difference between classes and objects. Additionally, it outlines the importance of JDK for development and JRE for running Java applications.

Uploaded by

dotuyen174
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
10 views

Java Language Basics

The document provides an overview of Java language basics, focusing on the main method, the differences between JDK, JRE, and JVM, and the execution flow of Java programs. It explains the architecture of the JVM, including class loaders, memory areas, and the execution engine, as well as the components of a Java class and the difference between classes and objects. Additionally, it outlines the importance of JDK for development and JRE for running Java applications.

Uploaded by

dotuyen174
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 79

Java Language Basics

1. Java main() Method


Why Java main Method is public?
the main method is public so that it can be accessible everywhere and to every object which may desire to use it for launching the application.
There is no reason why it should not be public, and be any other modifier(default/protected/private).
Notice that if we do not make main() method public, there is no compilation error. You will runtime error
because the matching main() method is not present.

Why static?
Notice that if you do not make main() method static, there is no compilation error. You will runtime error.

Why void?
Then there is no use of returning any value to JVM, who actually invokes this method. It simply doesn’t need any returning value.

2. Difference between JDK, JRE and


JVM in Java
Learn the differences between JDK, JRE and JVM. How JVM works inside? What are class
loaders, interpreters and JIT compilers? Also check out some Java interview questions.

1. Execution Flow of a Java Program


Before jumping into the internals of Java, let’s understand how a Java source file is executed.

 We write the Java source code in Simple.Java file using an editor or IDE (integrated
development environment) e.g. Eclipse or IntelliJ Idea.
 Program has to be compiled into bytecode. Java compiler (javac) compiles the sourcecode
to Simple.class file.
 This class file can be executed in any platform/OS by JVM (Java virtual machine).
 JVM translates bytecode into native machine code which machines can execute.

Java Execution Flow


2. What is JVM?
Java Virtual machine (JVM) is the virtual machine that runs the Java bytecodes. You get this
bytecode by compiling the .java files into .class files. .class files contain the bytecodes
understood by the JVM.

In the real world, JVM is a specification that provides a runtime environment in which Java
bytecode can be executed. Different vendors provide different implementations of this
specification. For example, this wiki page lists down different JVM implementations.

The most popular implementation of JVM is Hotspot which is owned and provided by Oracle
Corporation. (Previously by Sun Microsystems, Inc.).

JVM delivers the optimal performance for Java applications using many advanced techniques,
incorporating a state-of-the-art memory model, garbage collector, and adaptive optimizer.

JVM comes in two different flavors – client and server. Although the Server and the Client VMs
are similar, the Server VM has been specially tuned to maximize peak operating speed. It is
intended for executing long-running server applications, which need the fastest possible
operating speed more than a fast start-up time or smaller runtime memory footprint. Developers
can choose which system they want by specifying -client or -server.

The JVM is called virtual because it provides a machine interface that does not depend on the
underlying operating system and machine hardware architecture. This independence from
hardware and the operating system is a cornerstone of the write-once-run-anywhere value of Java
programs.

2.1. JVM Architecture

JVM Architecture
2.1.1. Class Loader
The class loader is a subsystem used for loading class files. It performs three primary functions,
i.e. class loading, linking, and initialization.
Loading
 To load classes, JVM has 3 kind of class loaders. Bootstrap, extension and application class
loader.
 When loading a class file, JVM finds out a dependency for some arbitrary class XYZ.class.
 First bootstrap class loader tries to find the class. It scans the rt.jar file in JRE lib folder.
 If class is not found then extension class loader searches the class file in inside jre\lib\
ext folder.
 Again if class is not found then application classloader searches all the Jar files and classes
in CLASSPATH environment variable of system.
 If class is found by any loader then class is loaded by class loader;
else ClassNotFoundException is thrown.
Linking
After class is loaded by the classloader, linking is performed. A bytecode verifier will verify
whether the generated bytecode is proper or not. If verification fails we will get a verification
error. It also performs the memory allocation to static variables and methods found in the class.
Initialization
This is the final phase of class loading, here all static variable will be assigned with the
original values, and the static blocks will be executed.

2.1.2. JVM Memory Areas


The memory area inside JVM is divided into multiple parts to store specific pieces of application
data.

 Method Area stores class structures like metadata, the constant runtime pool, and the code for
methods.
 Heap stores all objects that are created during application execution.
 Stacks store local variables, and intermediate results. All such variables are local to the thread by
which they are created. Each thread has its own JVM stack, created simultaneously as the thread
is created. So all such local variable are called thread-local variables.
 PC register store the physical memory address of the statements which is currently executing. In
Java, each thread has its separate PC register.
 Java supports and uses native code as well. Many low level code is written in languages like C
and C++. Native method stacks hold the instruction of native code.
2.2. JVM Execution Engine
All code assigned to JVM is executed by an execution engine. The execution engine reads the
byte code and executes one by one. It uses two inbuilt interpreter and JIT compiler to convert
the bytecode to machine code and execute it.
Platform Specific Interpreters

With JVM, both interpreter and compiler produce native code. The difference is in how they
generate the native code, how optimized it is as well how costly the optimization is.

2.2.1. Interpreter
A JVM interpreter pretty much converts each byte-code instruction to corresponding native
instruction by looking up a predefined JVM-instruction to machine instruction mapping.
It directly executes the bytecode and does not perform any optimization.

2.2.2. JIT Compiler


To improve performance, JIT compilers interact with the JVM at runtime and compile
appropriate bytecode sequences into native machine code. Typically, the JIT compiler takes a
block of code (not one statement at a time as interpreter), optimizes the code, and then translates
it to optimized machine code.

The JIT compiler is enabled by default. You can disable the JIT compiler, in which case the
entire Java program will be interpreted. Disabling the JIT compiler is not recommended except
to diagnose or workaround JIT compilation problems.

3. What is JRE?
The Java Runtime Environment (JRE) is a software package that bundles the libraries (jars)
and the Java Virtual Machine, and other components to run applications written in Java. JVM is
just a part of JRE distributions.

To execute any Java application, you need JRE installed in the machine. It’s the minimum
requirement to run Java applications on any computer.

JRE bundles the following components –

 DLL files used by the Java HotSpot Client Virtual Machine.


 DLL files used by the Java HotSpot Server Virtual Machine.
 Code libraries, property settings, and resource files used by the Java runtime environment.
e.g. rt.jar and charsets.jar.
 Java extension files such as localedata.jar.
 Contains files used for security management. These include the security policy (java.policy)
and security properties (java.security) files.
 Jar files containing support classes for applets.
 Contains TrueType font files for use by the platform.
JREs can be downloaded as part of JDKs, or you can download them separately. JREs are
platform dependent. It means that based on the type of machine (OS and architecture), you will
have to select the JRE bundle to import and install.

For example, you cannot install a 64-bit JRE distribution on 32-bit machine. Similarly, JRE
distribution for Windows will not work in Linux; and vice-versa.
4. What is JDK?
JDK is a superset of JRE. JDK contains everything that JRE has along with development tools
for developing, debugging, and monitoring Java applications. You need JDK when you need to
develop Java applications.

A few important components shipped with JDKs are as follows:

 appletviewer – this tool can be used to run and debug Java applets without a web browser
 apt – the annotation-processing tool
 extcheck – a utility that detects JAR file conflicts
 javadoc – the documentation generator, which automatically generates documentation from
source code comments
 jar – the archiver, which packages related class libraries into a single JAR file. This tool also
helps manage JAR files
 jarsigner – the jar signing and verification tool
 javap – the class file disassembler
 javaws – the Java Web Start launcher for JNLP applications
 JConsole – Java Monitoring and Management Console
 jhat – Java Heap Analysis Tool
 jrunscript – Java command-line script shell
 jstack – utility that prints Java stack traces of Java threads
 keytool – tool for manipulating the keystore
 policytool – the policy creation and management tool
 xjc – Part of the Java API for XML Binding (JAXB) API. It accepts an XML schema and
generates Java classes
Same as JREs, JDKs are also platform dependent. So take care when you download the JDK
package for your machine.

5. Difference between JDK, JRE and JVM


Based on the above discussions, we can draw a relationship between these three as below –

JRE = JVM + libraries to run Java application.

JDK = JRE + tools to develop Java Application.

JDK vs JRE vs JVM


In short, if you are a Java application developer who writes code, you will need JDK installed in
your machine. But, if you only want to run applications built in Java, you only need JRE
installed into your computer.

6. Interview questions related to JDK, JRE and JVM


If you understood whatever we have discussed so far in this post, then facing any interview
question will not be difficult. Still, be prepared to answer questions like below:

What is JVM architecture?


It’s already explained in detail.

How many types of class loaders are in Java?


There are 3 class loaders. Bootstrap, extension and application class loaders.

How does class loader work in Java?


Class loaders scan their pre-defined locations for jar files and classes. They scan all those class
files in the path and look for the required class. If found, they load, link, and initialize the class
file.

What is the difference between JRE and JVM?


JVM is the specification for a runtime environment that executes the Java applications. Hotspot
JVM is such one implementation of the specification. It loads the class files and uses the
interpreter and JIT compiler to convert bytecode into machine code and execute it.

What is the difference between an interpreter and JIT compiler?


The interpreter interprets the bytecode line by line and executes it sequentially. It results in poor
performance. JIT compiler add optimization to this process by analyzing the code in blocks and
then prepare more optimized machine code.
3. Java Class and Object
1. Difference between a Class and an Object
In Java, objects are containers like data structures that have state and behavior. Ideally,
objects represent the actors in the system or the application.

For example, in a Human Resource application, the main actors


are Employee, Manager, Department, Report, etc.

The classes are the template that describes the state and behavior of its objects. A class can
be used to create multiple objects. which are similar in structure but can have different states.

An object is an instance of a class.


2. How to Create a Class?
2.1. Syntax
The general syntax for declaring a class in Java is as follows:

<<modifiers>> class <<class name>> {

// fields and members of the class

}
 A class declaration may have zero or more modifiers.
 The keyword class is used to declare a class.
 The <<class name>> is a user-defined name of the class, which should be a valid identifier.
 Each class has a body, which is specified inside a pair of braces ({ … }).
 The body of a class contains its different components, for example, fields, methods, etc.
For example,

public class Main {

// Empty body for now

}
2.2. Types of Classes
In Java, we can have two types of classes:
1. Abstract class – These classes are abstract. These are incomplete classes. It means you cannot
create an instance of this class. You can only extend these classes to complete their specification.
2. Non-abstract class – These classes define their full state and behavior. They are complete
classes. You can create objects of this class.
3. Components of a Java Class
In Java, classes are used as templates to create objects. A class in Java may consist of five
primary components. i.e.

 Fields
 Methods
 Constructors
 Static initializers
 Instance initializers
Fields and methods are also known as class members. Constructors and both initializers are
used during the initialization of the class i.e. creating objects using the class template.

Constructors are used for creating objects of a class. We must have at least one constructor for a
class (if we don’t declare explicitly then JVM injects the default constructor for us).

Initializers are used to initialize fields of a class. We can have zero or more initializers of static
or instance types.

3.1. Fields
Fields of a class represent properties (also called state attributes) of objects of that class. The
fields are declared inside the body of the class. The general syntax to declare a field in a class is:

<<modifiers>> <<data type>> <<field name>> = <<initial value>>;

Suppose every object of the ‘Human‘ class has two properties: name and gender.
The Human class should include declarations of two fields: one to represent the name and one to
express gender.

public class Human {

private String name;

private String gender;

}
Here the Human class declares two fields: name and gender. Both fields are of the String type.
Every instance (or object) of the Human class will have a copy of these two fields.

3.2. Methods or Functions


A Java method is a collection of statements that are grouped together to operate. Methods are
generally used to modify the state of class fields. Methods also can be used to delegate tasks by
calling methods in other objects.

In Java, methods may –

 accept zero or more arguments


 return void or a single value
 be overloaded – means we can define more than one method with the same name but different
syntax
 be overridden – means we can define methods with the same syntax in parent and child classes
public class Human {

private String name;

private String gender;

public void eat() {

System.out.println("I am eating");

3.3. Constructors
A constructor is a named block of code that is used to initialize an object of a class immediately
after the object is created. The general syntax for a constructor declaration is:

<<Modifiers>> <<Constructor Name>>(<<parameters list>>) throws <<Exceptions list>> {


// Body of constructor goes here

}
 A constructor can have its access modifier as public, private, protected, or default (no modifier).
 The constructor name is the same as the simple name of the class.
 The constructor name is followed by a pair of opening and closing parentheses, which may
include parameters.
 Optionally, the closing parenthesis may be followed by the keyword throws, which in turn is
followed by a comma-separated list of exceptions.
 Unlike a method, a constructor does not have a return type.
 We cannot even specify void as a return type for a constructor. If there is any return type, then it
is a method.
 Remember that if the name of a construct is the same as the simple name of the class, it could be
a method or a constructor. If it specifies a return type, it is a method. If it does not specify a return
type, it is a constructor.
3.4. Instance Initialization Block
We saw that a constructor is used to initialize an instance of a class. An instance initialization
block, also called instance initializer, is also used to initialize objects of a class.

An instance initializer is simply a block of code inside the body of a class, but outside of any
methods or constructors. An instance initializer does not have a name. Its code is simply placed
inside an opening brace and a closing brace.

Note that an instance initializer is executed in the instance context, and the keyword this is
available inside the instance initializer.

public class Main

//instance initializer block

}
 we can have multiple instance initializers for a class.
 All initializers are executed automatically in textual order for every object we create.
 Code for all instance initializers is executed before any constructor.
 An instance initializer cannot have a return statement.
 It cannot throw checked exceptions unless all declared constructors list those checked exceptions
in their throws clause.
public class Main {

//instance initializer

System.out.println("Inside instance initializer");

//constructor

public Main()

System.out.println("Inside constructor");

public static void main(String[] args) {

new Main();

}
Program output:

Inside instance initializer

Inside constructor

3.5. Static Initialization Block


 A static initialization block is also known as a static initializer.
 It is similar to an instance initialization block except it is used to initialize a class.
 An instance initializer is executed once per object whereas a static initializer is executed only
once for a class when the class definition is loaded into JVM.
 To differentiate it from an instance initializer, we need to use the static keyword in the beginning
of its declaration.
 we can have multiple static initializers in a class.
 All static initializers are executed in the textual order in which they appear and execute before
any instance initializers.
A static initializer cannot throw checked exceptions. It cannot have a return statement.

public class Main {


//static initializer

static {

System.out.println("Inside static initializer");

//constructor

public Main()

System.out.println("Inside constructor");

public static void main(String[] args) {

new Main();

}
The program output:

Inside static initializer

Inside constructor

4. How to Create a New Object


In Java, to create an object from a class, use new keyword along with one of its constructors.

<<Class>> <<variable>> = new <<Call to Class Constructor>>;

//e.g.

Human human = new Human();


Remember, when we do not add a constructor to a class, the Java compiler adds one for us. The
constructor that is added by the Java compiler is called a default constructor. The default
constructor accepts no arguments. The name of the constructor of a class is the same as the class
name.

The new operator is followed by a call to the constructor of the class whose instance is being
created. The new operator creates an instance of a class by allocating the memory in a heap.
5. The ‘null’ Reference Type
Java has a special reference type called null type. It has no name. Therefore, we cannot define a
variable of the null reference type. The null reference type has only one value defined by Java,
which is the null literal. It is simply null.

The null reference type is assignment compatible with any other reference type. That is, we can
assign a null value to a variable of any reference type. Practically, a null value stored in
a reference type variable means that the reference variable is referring to no object.

// Assign the null value to john

Human john = null; // john is not referring to any object

john = new Human(); // Now, john is referring to a valid Human object


Note that null is a literal of the null type. We cannot assign null to a primitive type variable, and
that’s why the Java compiler does not allow us to compare a primitive value to a null value.

That’s all for this very basic tutorial about creating classes in java.
4. Java Data Types with Examples
1. How to Declare a Variable in Java?
In Java, typically datatypes are associated with variables. A variable declaration has three parts:

1. A variable name (also called identifier) to refer to the memory location


2. The variable type stored at the memory location (it is called datatype)
3. A memory location to hold the value of the variable
The second property is called data type.

Java Data Type

The data type of the variable determines the range of the values that the memory location can
hold. Therefore, the amount of memory allocated for a variable depends on its data type.
For example, 32 bits of memory is allocated for a variable of the 'int' data type.

Java is a statically-typed language. This means all variables MUST be declared before they
can be used.

boolean flag = true;

int counter = 20;

2. Java Data Types


Java supports two kinds of data types:

1. Primitive data type


2. Non-primitive or reference data type.
2.1. Primitive Data Types
 A primitive data type directly holds a value in memory. For instance, a number or a character.
 Primitive data types are not objects, as well as no references to the objects.
 The values stored in primitives are called literals.
A literal is the source code representation of a fixed value; literals are represented directly in
your code without requiring computation.

Java has eight primitive data types.

Data Type Description Default Value Memory Size

boolean A binary value of either true or false false 1 bit

char Any Unicode character \u0000 (0) 16-bit Unicode character

byte Values from -128 to 127 0 8-bit signed value

short Values from -32768 to 32767 0 16-bit signed value

int Values from -231 to 231-1 0 32-bit signed value

long Values from -263 to 263-1 0 64-bit signed value

float IEEE 754 floating point 0.0 32-bit floating-point value

double IEEE 754 floating point 0.0 64-bit floating-point value

In Java SE 7 and later, any number of underscore characters ('_') can appear anywhere between
digits in a numerical literal. e.g. 10_000_000 is a valid number in Java. Read More
2.1.1. Type Conversion between Primitives
Except boolean, we can assign a primitive value to another primitive type. Though, sometimes it
may result in data loss when a primitive of large memory capacity is assigned to a primitive with
a smaller memory capacity.

It’s just like you are transferring water from a large vessel and putting it in a smaller vessel, so
water loss is natural.
int counter = 20_000_000;

//Assign int to short (data loss)

short shortCounter = (short) counter;

//assign int to long (no data loss)

long longCounter = counter;

System.out.println(counter); //20000000

System.out.println(shortCounter); //11520

System.out.println(longCounter); //20000000
Notice that when Java detects that type conversion may result in data loss (bigger data type to
smaller one), then gives a type-mismatch error and explicitly asks for type casting (e.g. ‘int’ to
‘short’ assignment). It helps in detecting and resolving accidental data loss assignments.

2.2. Non-primitive Data Types


A non-primitive or reference data type holds the reference to an object in memory. Using the
reference stored in the variable, you can access the fields and methods of the referenced object.

For example, java.lang.String is a class defined in the Java library and you can use it to
manipulate text (sequence of characters). You declare a reference variable of type String as:

String str = "Hello World !!";

What happens when this code is executed?

 First, a memory block is allocated, and the name of the variable str is associated with that
memory location. This process is the same as declaring a primitive data type variable.
 The second part of code creates a new String object in memory with text "Hello World !!" and
stores the reference (or memory address) of the String object into the variable 'str'.
2.2.1. Multiple variables can refer to the same object
You can also assign the reference of an object stored in one reference variable to another
reference variable. In such cases, both reference variables will refer to the same object in
memory.

// Declares String reference variable str1 and str2

String str1;

String str2;

// Assigns the reference of a String object "Hello" to str1


str1 = new String( "Hello World !!" );

// Assigns the reference stored in str1 to str2

str2 = str1;

System.out.println( str1 ); //Hello World !!

System.out.println( str2 ); //Hello World !!


There is a reference constant (also known as reference literal) null, which can be assigned to any
reference variable. If null is assigned to a reference variable, which means that the reference
variable is not referring to any object in memory.

3. Wrapper Classes
A wrapper class is a class whose object wraps or contains primitive data types. In other words,
we can wrap a primitive value into a wrapper class object.

Please note that Java has one wrapper class mapped to each primitive data type.
For example, java.lang.Integer class is the object version of int data type. Similarly, we have a
total of 8 wrapper classes for all 8 primitive data types.

The wrapper class names are the same as primitive data types, only starting with capital letters.
These wrapper classes are Boolean, Byte, Short, Character, Integer, Long, Float and Double.

4. Auto-boxing
In Java, you can assign a primitive type value to a wrapper class, directly. For example, you can
assign an int value to Integer class reference.

Integer counter = 20;

static Float PI = 3.14f;

It’s worth mentioning that all wrapper class instances are immutable. They also maintain
an internal cache for performance reason.

5. Difference between primitive and non-primitive data types


 Primitives store values directly, which are called literals. Reference types store references to
actual objects in the memory area.
 There are 8 fixed primitive data types. In Java, each class is a data type including wrapper classes.
6. Best practices
 Use Java variable naming conventions and follow best practices.
 Use primitives for variables that are local in scope. e.g. inside methods, counter for loops and
intermediate results.
 When data is transferred among methods or classes, it’s better to use objects because only their
references will be copied, so no memory overhead will be added.
 When dealing with collections (which need objects), you shall be using Objects.
 While sending data over the network, use objects and make them Serializable. Wrapper classes
are automatically Serializable.
 Always know the size of the data type you will need. Use appropriate data sizes. Using int to
store boolean values (0 and 1) is a waste of memory.
 Use underscores (above Java 7) in numbers. It makes them more readable.
5. Java Variables
In traditional programming languages, such as Java, a variable is a placeholder
for storing a value of a particular type: a string, a number, or something else. This
Java tutorial discusses what a variable is and the types of variables. Also, look at the
example of how to declare a variable in Java. We will also see some best practices for
naming the variables in Java.

The Java programming language uses both “fields” and “variables” as part of its
terminology. Fields refer to variables declared outside methods, and variables are
referred to declarations inside methods, including method arguments.
1. What is a Variable?
As the term suggests, a variable is a placeholder whose value can vary during the
runtime. In Java, a variable is a named reference to a memory area where the value
of the variable is stored.

How a
variable works

1.1. How to Declare a Variable?


Every variable has a name (also known as an identifier) to distinguish it from others.
Before you start using a variable, you must declare it.

The given syntax explains how to declare a variable in Java. The left part of this
statement describes the variable, and the right part describes something that is
assigned to it.

[data_type] [variable_name] = [variable_value];


 data_type – refers to the type of information stored in the memory area. It determines
the possible operations that can be performed on the variable and which values can be
stored in it.
 variable_name – refers to the name of the variable and distinguishes it from other
variables. The name of a variable cannot start with a digit; it usually starts with a letter.
Always try to choose meaningful and readable names for variables to make your code
easy to understand.
 variable_value – refers to the value to be stored in the memory area.
For example, the below statements are valid variable declarations in Java.

Examples of variable declaration

int i = 10; //Variable of int type

String str = "howtodoinjava.com"; //Variable of String type

Object obj = new Object(); //Variable of Object type

int[] scores = [1,2,3,4,5,6,7,8,9]; //Variable of int array type


Java allows several flexible syntaxes for declaring the variables. For example, we can
declare several variables of the same type as a single statement:

int i = 1, j = 2;

We can also separate the declaration and initialization in separate statements.

int i;

i = 1;

1.2. Example
Once a variable has been declared, its value can be accessed and modified using the
name.

In the following example below, we declare two ‘int‘ variables and assign their addition
result to a third variable ‘sum‘.

int i = 10;

int j = 10;
int sum = i + j;

System.out.println( sum ); // Prints 20


There is one restriction for variables: you can only assign a value of the same type as
the type of the initial variable. In the previous example, ‘sum‘ has to be int or other
number type. It cannot be a String, Boolean or any other type.

2. Type Inference
Since Java 10, you can write var instead of a specific type to force automatic type
inference based on the type of assigned value:

var [variable_name] = [variable_value];

Here are two examples below:

var language = "Java"; // String

var num = 1; // int


Although it allows the code to be more concise, it may affect the code readability in a
bad way.

See Also: Java ‘var’ Keyword


3. Widening and Narrowing
3.1. Widening
When a small primitive type value is automatically accommodated in a bigger/wider
primitive data type, this is called the widening of the variable. In given example, int type
variable is assigned to long type variable without any data loss or error.

int i = 10;

long j = i;

System.out.println( i );

System.out.println( j );
Program output.

10

10

3.2. Narrowing
When a larger primitive type value is assigned in a smaller size primitive data type, this
is called the narrowing of the variable. It can cause some data loss due to fewer bits
available to store the data. It requires explicit type-casting to the required data type.

In the given example, int type variable is assigned to byte type variable with data loss.

int i=198;

byte j=(byte)i;

System.out.println( i );

System.out.println( j );

Program output.

198

-58

4. Types of Variables in Java


In Java, there are four types of variables. These variables can be either of primitive
types, class types or array types. All variables are divided based on the scope of
variables where they can be accessed.

4.1. Instance Variables


Variables declared (in class) without static keyword. Non-static fields are also known as
instance variables because their values are unique to each instance of a class. They
are also called state variables.

public class VariableExample


{

int counter = 20; //1 - Instance variable

}
4.2. Static Variables
Also, known as class variables. It is any field declared with the static modifier. It means
that there is exactly one copy of this variable in existence, regardless of how many
times the class has been instantiated.

public class VariableExample

static float PI = 3.14f; //2 - Class variable

}
A variable declared as “public static” can be treated as global variable in java.

4.3. Local Variables


These are used inside methods as temporary variables exist during the method
execution. The syntax for declaring a local variable is similar to declaring a field. Local
variables are only visible to the methods in which they are declared; they are not
accessible from the rest of the class.

public class VariableExample

public static void main( String[] args ) {

int age = 30; //3 - Local variable (inside method body)

}
4.4. Method Arguments
An argument is a variable that is passed to a method when the method is called.
Arguments are also only accessible inside the method that declares them, although
a value is assigned to them when the method is called.

public class VariableExample


{

public static void main( String[] args ) {

print( 40 );

public static void print ( int param ) { //4 - Method Argument

System.out.println ( param );

}
5. Difference between Instance and Class Variables
 Instance variables (non-static fields) are unique to each instance of a class.
 Class variables (static fields) are fields declared with the static modifier; there is
exactly one copy of a class variable, regardless of how many times the class has been
instantiated.
 To access the instance variable, you MUST create a new instance of the class. Class
variables are accessible through class reference, and do not require creating an object
instance. Take an example. We have a class Data with one instance variable and one
class variable.
public class Data

int counter = 20;

static float PI = 3.14f;

}
We can access both variables in a given way.

public class Main

public static void main(String[] args)

Data dataInstance = new Data();

//Need new instance

System.out.println( dataInstance.counter ); //20

//Can access using class reference

System.out.println( Data.PI ); //3.14

}
6. Variable Naming Conventions in Java
There are a few rules and conventions related to how to define variable names.

 Java variable names are case-sensitive. The variable name employee is not the
same as Employee or EMPLOYEE.
 Java variable names must start with a letter, or the $ or _ character.
 After the first character in a Java variable name, the name can also contain
numbers, $ or _ characters.
 Variable names cannot be reserved keywords in Java. For instance, the words break
or continue are reserved words in Java. Therefore you cannot name your variables to
them.
 Variable names should written in lowercase. For instance, variable or apple.
 If variable names consist of multiple words, then follow camelcase notation. For
instance, deptName or firstName.
 Static final fields (constants) should be named in all UPPERCASE, typically using an
(underscore) _ to separate the words in the name. For
example LOGGER or INTEREST_RATE.
7. Summary
Variables in Java are used to store values of different data types. They need to be
declared with a type and a name. Variables can be modified after declaration, but the
new value must be of the same type as the old one. In Java 10, the var keyword was
introduced for automatic type inference.
6. How to Pass and Access Command
Line Arguments in Java
When a Java program is launched from the terminal or command line, the
arguments passed at the time of launching are called command-line arguments.

A Java program can be launched either from a console or an editor e.g. Eclipse.
To launch a program we use “java ClassName” command from the command
prompt or system console.

1. How to Pass Arguments from Command Line


While launching the program, we can pass the additional arguments (no limit on
the number of arguments) in the below syntax.

In the given example, we are passing 5 parameters to the Main class MyClass.
MyClass has the main() method which accepts these arguments in form of
a String array.

$ java MyClass arg1 arg2 arg3 arg4 arg5

2. How to Access Command Line Arguments


Let’s create an example to understand how command-line program arguments work in
Java. This class simply accepts the arguments and prints them in the console.

As a programmer, we can use these arguments as startup parameters to customize the


behavior of the application in runtime.

public class Main {

public static void main(String[] args) {

for(int i = 0; i < args.length; i++) {

System.out.println( args[i] );
}

Now run this class from the console.

$ java Main 1 2 3 4

#prints

Since Java 5, we can use varargs in the main() method. Even though, accessing the
variables remains the same.

public static void main(String... args) {

//...

}
3. Conclusion
 Command line args can be used to specify configuration information while launching the
application.
 There is no restriction on the maximum number of arguments. We can specify any
number of arguments.
 Arguments are passed as strings.
 Passed arguments are retrieved as the string array in the main() method argument.

7. Java Wrapper Classes, Autoboxing


and Unboxing
Learn about Java wrapper classes, their usage, conversion between primitives and
objects; and autoboxing and unboxing with examples.

1. Java Wrapper Classes


In Java, we have 8 primitive data types. Java provides type wrappers, which are
classes that encapsulate a primitive type within an Object.

 A wrapper class wraps (encloses) around a primitive datatype and gives it an object
appearance. Wherever the primitive datatype is required as an object type, this type
wrapper can be used.
 Wrapper classes include methods to unwrap the object and give back the data type.
 The type wrappers classes are part of java.lang package.
 Each primitive type has a corresponding wrapper class.

Primitive Type Wrapper Class

double Double

float Float

long Long

int Integer

short Short

byte Byte

char Character
boolean Boolean

2. When to use Wrapper Classes


Java wrapper classes are used in scenarios –

 When two methods wants to refer to the same instance of an primitive type, then pass
wrapper class as method arguments.
 Java Generics works only with object types and does not support primitive types.
 Java Collections deal only with objects; to store a primitive type in one of these
classes, you need to wrap the primitive type in a class.
 When you want to refer null from data type, the you need object. Primitives cannot
have null as value.
3. Conversions
3.1. Converting Primitive Types to Wrapper Classes
There are two ways for converting a primitive type into an instance of the corresponding
wrapper class –

1. Using constrcutors
2. Using static factory methods
// 1. using constructor

Integer object = new Integer(10);

// 2. using static factory method

Integer anotherObject = Integer.valueOf(10);


In the above example, the valueOf() method is a static factory method that returns an
instance of Integer class representing the specified int value.

Similarly, we can convert the other primitive types


like boolean to Boolean, char to Character, short to Short, etc.

Java wrapper classes use internal caching which returns internally cached values upto
a limit. This internal caching of instances makes the wrapper classes more efficient in
perfomance and memory unilization.
3.2. Converting Wrapper Class to Primitive Type
Converting from wrapper class to primitive type is simple. We can use the
corresponding instance methods to get the primitive type.
e.g. intValue(), doubleValue(), shortValue() etc.

Integer object = new Integer(10);


int val = object.intValue(); //wrapper to primitive
4. Autoboxing and Unboxing
Beginning with JDK 5, Java added two important features:

 Autoboxing
 Auto-Unboxing
4.1. Autoboxing
Autoboxing is the automatic conversion of the primitive types into their
corresponding wrapper class.
For example, converting an int to an Integer, a char to a Character, and so on.

We can simply pass or assign a primitive type to an argument or reference accepting


wrapper class type.

Java Autoboxing Example

List<Integer> integerList = new ArrayList<>();

for (int i = 1; i < 10; i ++)

integerList.add(i); //int to Integer

}
In given example, integerList is a List of Integers. It is not a list of primitive type int
values.

Here compiler automatically creates an Integer object from int and adds the object
to integerList. Thus, the previous code turns into the following at runtime:

List<Integer> integerList = new ArrayList<>();


for (int i = 1; i < 10; i ++)

integerList.add(Integer.valueOf(i)); //autoboxing

}
4.2. Unboxing
Unboxing happens when the conversion happens from wrapper class to its
corresponding primitive type. It means we can pass or assign a wrapper object to an
argument or reference accepting primitive type.

Java Unboxing Example

public static int sumOfEven(List<Integer> integerList)

int sum = 0;

for (Integer i: integerList) {

if (i % 2 == 0)

sum += i; //Integer to int

return sum;

}
In the above example, the remainder (%) and unary plus (+=) operators do not
apply on Integer objects. The compiler automatically converts an Integer to an int at
runtime by invoking the intValue() method.

Autoboxing and unboxing lets developers write cleaner code, make it easier to read.
8. Types of Statements in Java
A statement specifies an action in a Java program. For example, a statement may
tell the add of values of x and y and assign their sum to the variable z. It then prints a
message to the standard output or writes data to a file, etc.

Java statements can be broadly classified into three categories:

 Declaration statement
 Expression statement
 Control flow statement

1. Declaration Statement
A declaration statement is used to declare a variable. For example,

int num;

int num2 = 100;

String str;

2. Expression Statement
An expression with a semicolon at the end is called an expression statement. For
example,

/Increment and decrement expressions

num++;

++num;

num--;

--num;
//Assignment expressions

num = 100;

num *= 10;

//Method invocation expressions

System.out.println("This is a statement");

someMethod(param1, param2);

3. Flow Control Statement


By default, all statements in a Java program are executed in the order they appear in
the program. Sometimes you may want to execute a set of statements repeatedly for a
number of times or as long as a particular condition is true.

All of these are possible in Java using flow control statements. The if statement, while
loop statement and for loop statement are examples of control flow statements.

if(condition) {

System.out.println("Condition is true");

} else {

System.out.println("Condition is false");

}
9. Block Statements in Java
A block statement is a sequence of zero or more statements enclosed in braces.
A block statement is generally used to group together several statements, so
they can be used in a situation that requires you to use a single statement.

1. What is a Block Statement?


Generally, a java program is a combination of single statements that should be
executed sequentially. In some cases, if we want to use more than one statement to
represent a unit of work, we can create a block statement by placing all related
statements inside braces, which would be treated as a single statement. You can
think of a block statement as a compound statement treated as one.

An example of a block statement is given below.

int var = 20;

var++;

2. Scope of Variables inside Blocks?


Please note that all the variables declared in a block statement can only be used
within that block. In other words, you can say that all variables declared in a block
have local scope.

int var = 20;

var++;

}
// A compile-time error. var has been declared inside a block and

// so it cannot be used outside that block

Syetem.out.println(var);
Similarly, you can also nest a block statement inside another block statement. All the
variables declared in the enclosing blocks (outer blocks) are available to the
enclosed blocks (inner blocks). However, the variables declared in the enclosed
inner blocks are not available in the enclosed outer blocks.

3. Blocks during object creation


Another thing that may interest you is that block statements need not be only inside
methods. You can write them to write object initialization logic.

Please note that when block statements are declared in such a way, non-static
blocks will be executed every time an instance of the class is created.
The static blocks will be executed only once when the class is loaded by JVM
class loaders (Much like other static variables present at the class level).

public class MyDemoAction

private Interger variable = 10;

public MyDemoAction(){

System.out.println("MyDemoAction Constructor");

{ //Non-static block statement

static {

//Static block statement


}

private void someMethod() {

System.out.println("HowToDoInJava.com");

}
10. Java System Properties
Java maintains a Set of system properties that can be accessed in the runtime by
executing programs. Each system property is a key-value pair. For example, one
such system property is “java.version”=”1.7.0_09“.

We can retrieve all the system properties via System.getProperties() or we can


also retrieve individual property via System.getProperty(key) method.

Please note that access to system properties can be restricted by the Java security
manager and policy file. By default, Java programs have unrestricted access to all
the system properties.
1. Java System Properties List
The following is a list of important system properties in each category.

1.1. Runtime Environment Properties


JRE home directory, e.g., “C:\Program Files\Java\jdk1.7.0_09\
java.home
jre“.

JRE library search path for search native libraries. It is usually but
java.library.path
not necessarily taken from the environment variable PATH.

java.class.path JRE classpath e.g., '.' (dot – used for current working directory).

JRE extension library path(s), e.g, “C:\Program Files\Java\


java.ext.dirs
jdk1.7.0_09\jre\lib\ext;C:\Windows\Sun\Java\lib\ext “.

java.version JDK version, e.g., 1.7.0_09.

java.runtime.versi
JRE version, e.g. 1.7.0_09-b05.
on

1.2. File System Properties


file.separator symbol for file directory separator such as 'd:\test\test.java'. The
default is '\' for windows or '/' for Unix/Mac.

symbol for separating path entries, e.g., in PATH or CLASSPATH.


path.separator
The default is ';' for windows or ':' for Unix/Mac.

symbol for end-of-line (or new line). The default is "\r\n" for windows
line.separator
or "\n" for Unix/Mac OS X.

1.3. User Properties


user.name the user’s name.

user.home the user’s home directory.

user.dir the user’s current working directory.

1.4. Operation System Properties


os.name the OS’s name, e.g., “Windows 7“.

os.version the OS’s version, e.g., “6.1“.

os.arch the OS’s architecture, e.g., “x86“.

2. Get the Value of a System Property


As discussed earlier, You can get the list of all the system properties
via System.getProperties() or also retrieve individual property
via System.getProperty(key).

2.1. List of all System Properties


Properties pros = System.getProperties();

pros.list(System.out);
2.2. Get a system property value by its key
System.getProperty("java.home");

3. Set a System Property


In Java, you can set a custom system property either from the command line or
from the application code itself.

3.1. Using Command Line


In the given example, the application will be able to access the property with
key custom_key. It’s value will be available as custom_value.

$ java -Dcustom_key="custom_value" application_launcher_class

3.2. Using Java Code


Similar to the above example, after executing this code, the application will be able
to access the property with key custom_key. It’s value will be available
as custom_value.

System.setProperty("custom_key", "custom_value");
Static Import Statements in
Java
In Java, the import statements imports classes from packages, so they can be used in
the current class without the package reference. Similarly, the static import statements
import the static members of the a class and allows to be used without class reference.

1. Types of Static Import Statements


A static import declaration comes in two flavors:

 single-static import: imports one static member (field or method) from a class.
 static-import-on-demand: imports all static members from a class. These are denoted
with an asterisk (*).

1.1. Syntax
The general syntax of static import statements is as follows:

import static <<package name>>.<<type name>>.<<static member name>>;

import static <<package name>>.<<type name>>.*; //On-demand

1.2. Example
For example, we can print the messages in the standard output using
the System.out.println() method. System is a class in java.lang package that has
a static variable named out.

When we use System.out, we are referring to that static variable out of


the System class. We can use a static import statement to import the out static variable
from the System class as follows:

import static java.lang.System.out;


The code can now use the name out to mean System.out in the program. The compiler
will use the static import declaration to resolve the name out to System.out.

public class StaticImportTest {

public static void main(String[] args) {

out.println("Hello World!");

2. Rules for Static Imports


The following are some important rules about static import statements.

2.1. Specifically Imported Member Preceeds Wildcard


Imported Member
If two static members with the same simple name are imported, one using single-static
import declaration and the other using static-import-on-demand declaration, the one
imported using single-static import declaration takes precedence.

Suppose there are two classes, package1.Class1 and package2.Class2. Both classes
have a static method called methodA. The following code will
use package1.Class1.methodA() method because it is imported using the single-static
import declaration:

import static package1.Class1.methodA; // Imports Class1.methodA() method

import static package2.Class2.*; // Imports Class2.methodA() method too

public class Test {

public static void main(String[] args) {

methodA(); // Class1.methodA() will be called

}
}

2.2. Static Member Names should be Unique


Using single-static-import declaration to import two static members with the same
simple name is not allowed. The following static import declarations generate an error
because both of them import the static member with the same simple name
of methodA:

import static package1.Class1.methodA;

import static package1.Class2.methodA; // An error

2.3. Static Member Defined in the Current Class Takes


Precedence
If a static member is imported using a single-static import declaration and there exists
a static member in the same class with the same name, the static member in the class
is used.

package package1;

public class A {

public static void test() {

System.out.println("package1.A.test()");

package package2;
import static package1.A.test;

public class Test {

public static void main(String[] args) {

test(); //package2.Test.test()

public static void test() {

System.out.println("package2.Test.test()");

3. Conclusion
The static imports help us use simple names of static members to make the program
simpler to write and read. These are more of a syntactical sugar rather than providing
any execution benefits in runtime.

Java hashCode() and equals()


Methods
Learn about Java hashCode() and equals() methods, their default implementation, and
how to correctly override them. Also, we will learn to implement these methods using
3rd party classes HashCodeBuilder and EqualsBuilder.
The hashCode() and equals() methods have been defined in Object class which is
parent class for all java classes. For this reason, all java objects inherit a default
implementation of these methods.

1. The hashCode() and equals() Methods


 equals(Object otherObject) – verifies the equality of two objects. It’s default
implementation simply checks the object references of two objects to verify their
equality. By default, two objects are equal if and only if they refer to the same memory
location. Most Java classes override this method to provide their own comparison logic.
 hashcode() – returns a unique integer value for the object in runtime. By
default, Integer value is derived from the memory address of the object in the heap (but
it’s not mandatory). The object’s hash code is used for determining the index location
when this object needs to be stored in some HashTable like data structure.

1.1. Contract between hashCode() and equals()


Overriding the the hashCode() is generally necessary whenever equals() is overridden
to maintain the general contract for the hashCode() method, which states that equal
objects must have equal hash codes.

 Whenever it is invoked on the same object more than once during an execution of a
Java application, the hashCode() must consistently return the same integer,
provided no information used in equals comparisons on the object is modified.
This integer need not remain consistent between the two executions of the same
application or program.
 If two objects are equal according to the equals() method, then calling
the hashCode() on each of the two objects must produce the same integer result.
 It is not required that if two objects are unequal according to the equals(), then
calling the hashCode() on each of the both objects must produce distinct
integer results.
However, the programmer should be aware that producing distinct integer results for
unequal objects may improve the performance of hash tables.

2. Overriding the Default Behavior


Everything works fine until we do not override any of both methods in our classes. But,
sometimes, the application needs to change the default behavior of some objects.

Let us understand why we need to override equals and hashcode methods.


2.1. The Default Behavior
Let’s take an example where your application has Employee object. Let us create a
minimal possible structure of Employee class:

public class Employee

private Integer id;

private String firstname;

private String lastName;

private String department;

//Setters and Getters

}
Above Employee class has some fundamental attributes and their accessor methods.
Now consider a simple situation where you need to compare two Employee objects.
Both employee objects have the same id.

public class EqualsTest {

public static void main(String[] args) {

Employee e1 = new Employee();

Employee e2 = new Employee();

e1.setId(100);

e2.setId(100);
System.out.println(e1.equals(e2)); //false

}
No prize for guessing. The above method will print “false.”

But is it correct after knowing that both objects represent the same employee? In a real-
time application, this should return true.

2.2. Overriding only equals()


To achieve correct application behavior, we need to override equals() method as
below:

public boolean equals(Object o) {

if(o == null)

return false;

if (o == this)

return true;

if (getClass() != o.getClass())

return false;
}

Employee e = (Employee) o;

return (this.getId() == e.getId());

Add this method to the Employee class, and EqualsTest will start returning "true".

So are we done? Not yet. Let’s test the above-modified Employee class again in a
different way.

import java.util.HashSet;

import java.util.Set;

public class EqualsTest

public static void main(String[] args)

Employee e1 = new Employee();

Employee e2 = new Employee();

e1.setId(100);

e2.setId(100);
//Prints 'true'

System.out.println(e1.equals(e2));

Set<Employee> employees = new HashSet<Employee>();

employees.add(e1);

employees.add(e2);

System.out.println(employees); //Prints two objects

}
The above example prints two objects in the second print statement.

If both employee objects have been equal, in a Set which stores unique objects, there
must be only one instance inside HashSet because both objects refer to the same
employee. What is it we are missing??

2.3. Overriding hashCode() is Also Necessary


We are missing the second important method hashCode(). As java docs say, if we
override equals() then we must override hashCode(). So let’s add another method in
our Employee class.

@Override

public int hashCode()

final int PRIME = 31;

int result = 1;

result = PRIME * result + getId();

return result;

}
Once the above method is added in Employee class, the second statement starts
printing only a single object in the second statement and thus validating the true
equality of e1 and e2.

3. EqualsBuilder and HashCodeBuilder


Apache commons provide two excellent utility
classes HashCodeBuilder and EqualsBuilder for generating hash code and equals
methods.

We can use these classes in the following manner.

import org.apache.commons.lang3.builder.EqualsBuilder;

import org.apache.commons.lang3.builder.HashCodeBuilder;

public class Employee

private Integer id;

private String firstname;

private String lastName;

private String department;

//Setters and Getters

@Override

public int hashCode()

final int PRIME = 31;

return new HashCodeBuilder(getId()%2==0?getId()+1:getId(), PRIME).toHashCode();

}
@Override

public boolean equals(Object o) {

if (o == null)

return false;

if (o == this)

return true;

if (o.getClass() != getClass())

return false;

Employee e = (Employee) o;

return new EqualsBuilder().

append(getId(), e.getId()).

isEquals();

4. Generating hashCode() and equals() in Eclipse


IDE
Most editors provide common source code templates. For example, Eclipse IDE has
the option to generate an excellent implementation of hashCode() and equals().

Right click on Java file -> Source -> Generate hashCode() and equals() …
Generate hashCode() and equals() In Eclipse

5. Best Practices to Follow


1. Always use the same fields to generate hashCode() and equals(). As in our case, we
have used employee id.
2. The equals() must be consistent (if the objects are not modified, then it must keep
returning the same value).
3. Whenever a.equals(b), then a.hashCode() must be same as b.hashCode().
4. If we override one method, then we should override the other method as well.

6. Special Attention When Declared in an JPA


Entity
If you’re dealing with an ORM, make sure always to use getters and never use the
field references in hashCode() and equals(). Because in ORM, occasionally fields
are lazy loaded and not available until we call their getter methods.
For example, In our Employee class if we use e1.id == e2.id. It is very much possible
that id field is lazy-loaded. So, in this case, id field inside the methods might be zero
or null, and thus resulting in incorrect behavior.

But if uses e1.getId() == e2.getId(), we can be sure even if the field is lazy-loaded,
calling the field getter will populate the field first.
Immutable Classes in Java
In Java, an immutable object is one whose state can not be changed once created.
Immutable objects are persistent views of their data without a direct option to change it.
To change the state, we must create a new copy of such an object with the intended
changes.

In this post, we will learn immutability in detail, creating an immutable object and its
advantages.

1. What is Immutability?
Immutability is a characteristic of Java objects that makes them immutable to future
changes once they have been initialized. Its internal state cannot be changed in any
way.

Take the example of java.lang.String class which is an immutable class. Once a String
is created, there is no way we can change the content of that String. Every public API
in String class returns a new String with the modified content. The original String always
remains the same.

String string = "test";

String newString = string.toLowerCase(); //Creates a new String

2. Immutability in Collections
Similarly, for Collections, Java provides a certain degree of immutability with three
options:

 Unmodifiable collections
 Immutable collection factory methods (Java 9+)
 Immutable copies (Java 10+)
Collections.unmodifiableList(recordList); //Unmodifiable list

List.of(new Record(1, "test")); //Factory methods in Java 9

List.copyOf(recordList); //Java 10
Note that such collections are only shallowly immutable, meaning that we can not
add or remove any elements, but the collection elements themselves aren’t guaranteed
to be immutable. If we hold the reference of a collection element, then we can change
the element’s state without affecting the collection.

In the following example, we cannot add or remove the list items, but we can change
the state of an existing item in the list.

List<Record> list = List.of(new Record(1, "value"));

System.out.println(list); //[Record(id=1, name=value)]

//list.add(new Record()); //UnsupportedOperationException

list.get(0).setName("modified-value");

System.out.println(list); //[Record(id=1, name=modified-value)]

@Data

@NoArgsConstructor

@AllArgsConstructor

class Record {

long id;

String name;

To ensure complete immutability, we must make sure that we only add immutable
instances in the collections. This way, even if somebody gets a reference to an item
in the collection, it cannot change anything.

3. How to Create an Immutable Class?


Java documentation itself has some guidelines identified to write immutable classes in
this link. We will understand what these guidelines actually mean.

 Do not provide setter methods. Setter methods are meant to change an object’s state,
which we want to prevent here.
 Make all fields final and private. Fields declared private will not be accessible outside
the class, and making them final will ensure that we can not change them even
accidentally.
 Do not allow subclasses to override methods. The easiest way is to declare the class
as final. Final classes in Java can not be extended.
 Special attention to “immutable classes with mutable fields“. Always remember that
member fields will be either mutable or immutable. Values of immutable members
(primitives, wrapper classes, String etc) can be returned safely from the getter methods.
For mutable members (POJO, collections etc), we must copy the content into a
new Object before returning from the getter method.
Let us apply all the above rules to create an immutable custom class. Notice that we
are returning a new copy of ArrayList from the getTokens() method. By doing so,
we are hiding the original tokens list so no one can even get a reference of it and
change it.

final class Record {

private final long id;

private final String name;

private final List<String> tokens;

public Record(long id, String name, List<String> tokens) {

this.id = id;

this.name = name;

this.tokens = tokens;

public long getId() {


return id;

public String getName() {

return name;

public List<String> getTokens() {

return new ArrayList<>(tokens);

@Override

public String toString() {

return "Record{" +

"id=" + id +

", name='" + name + '\'' +

", tokens=" + tokens +

'}';
}

Now it’s time to test our class. We tried to add a new item to the tokens list, but the
original record and its list remain unchanged.

ArrayList<String> tokens = new ArrayList<>();

tokens.add("active");

Record record = new Record(1, "value", tokens);

System.out.println(record); //Record{id=1, name='value', tokens=[active]}

record.getTokens().add("new token");

System.out.println(record); //Record{id=1, name='value', tokens=[active]}

4. Immutability with Java Records


Java records help reduce the boilerplate code by generating the constructors and
getters at compile time. They can also help create immutable classes with very few lines
of code.

For example, we can rewrite the above Record class as follows. Note that records
generate the standard getters, so if we want to return a new copy of a mutable
reference, we must override the corresponding method.

record Record(long id, String name, List<String> tokens){

public List<String> tokens() {

return new ArrayList<>(tokens);

}
}

Now let us test the immutability again.

ArrayList<String> tokens = new ArrayList<>();

tokens.add("active");

Record record = new Record(1, "value", tokens);

System.out.println(record); //Record{id=1, name='value', tokens=[active]}

record.tokens().add("new token");

System.out.println(record); ////Record{id=1, name='value', tokens=[active]}

5. Immutable Classes in JDK


Apart from your written classes, JDK itself has lots of immutable classes. Given is such
a list of immutable classes in Java.

 java.lang.String
 Wrapper classes such as Integer, Long, Double etc
 java.math.BigInteger and java.math.BigDecimal
 Unmodifiable collections such as Collections.singletonMap()
 java.lang.StackTraceElement
 Java enums
 java.util.Locale
 java.util.UUID
 Java 8 Date Time API – LocalDate, LocalTime etc.
 record types

6. Advantages
Immutable objects provide a lot of advantages over mutable objects. Let us discuss
them.
 Predictability: guarantees that objects won’t change due to coding mistakes or by 3rd
party libraries. As long as we reference a data structure, we know it is the same as at the
time of its creation.
 Validity: is not needed to be tested again and again. Once we create the immutable
object and test its validity once, we know that it will be valid indefinitely.
 Thread-safety: is achieved in the program as no thread can change immutable objects.
It helps in writing code in a simple manner without accidentally corrupting the shared
data objects.
 Cacheability: can be applied to immutable objects without worrying about state changes
in the future. Optimization techniques, like memoization, are only possible with
immutable data structures.

7. Conclusion
This tutorial taught us to create an immutable java class with mutable objects and
immutable fields.

In Java, immutable classes are:

 are simple to construct, test, and use


 are automatically thread-safe and have no synchronization issues
 do not need a copy constructor
 do not need an implementation of clone()
 allow hashCode() to use lazy initialization, and to cache its return value
 do not need to be copied defensively when used as a field
 make good Map keys and Set elements (these objects must not change state while in
the collection)
 have their class invariant established once upon construction, and it never needs to be
checked again
 always have “failure atomicity” (a term used by Joshua Bloch) : if an immutable object
throws an exception, it’s never left in an undesirable or indeterminate state
We also saw the benefits which immutable classes bring in an application. As a design
best practice, always aim to make your application Java classes to be immutable. In this
way, you can always worry less about concurrency related defects in your program.
Difference between 32-bit Vs.
64-bit Java
In computer architecture, 64-bit computing is the use of processors that have datapath
widths, integer size, and memory addresses widths of 64 bits (eight octets/bytes). Also,
64-bit CPU and ALU architectures are those that are based on registers, address
buses, or data buses of that size. From the software perspective, 64-bit computing
means the use of code with 64-bit virtual memory addresses. Similarly, 32-bit
computing, CPU or 32-bit programming uses 32 bits (four octets/bytes) for all the above
purposes.

If you go to java download page, it lists various installation packages mentioning 32-bit
packages or 64-bit packages for various platforms such as Linux or windows. Many
times we worry that what package we are eligible to download and install in our systems
so that our java code runs fine. In this post, I will try to put some light on these different
terms and also I will try to answer some obvious questions.

You already read the basic difference between 64-bit and 32-bit
computing/architectures. Now let’s expand our understanding and go deeper into bits
and bytes.

1. Understanding 32-bit Architecture in Detail


As you may be aware of that in any 32-bit operating system, you are limited to 4096
MB (4 GB) of RAM. It is simply because the size of a 32-bit value will not allow any
more references in memory.

232 = 4,294,967,296 i.e. roughly 4.29 GB


So, in a 32-bit system you can theoretically allocate up to 4GB of memory per process.
What breaks this on Windows is how to process address space is handled. Windows
cuts the process address space in half. One-half of it is reserved for the operating
system (which a user process cannot use) and the other half for the user. It doesn’t
matter how much RAM is in the box, a 32-bit process can only use 2GB of RAM. What’s
even worse – this address space needs to be contiguous, so in practice, you are often
left with just 1.5-1.8GB of the heap on Windows machines.

Tech-savvy readers might know that modern chips support PAE, a processor
technology that allows the operating system to use a little bit more memory—up to 64
GB, but it also requires special application support that most applications don’t have or
necessarily need.
The 4 GB limit for Windows, at least, is also a factor of licensing. The home versions of
32-bit Windows, while technically being able to support PAE, have a hard limit of 4 GB
for licensing and driver compatibility reasons. I am pointing out “driver compatibility
reasons” because some specific applications which highly use native files (e.g. anti-
viruses) are built specifically for 32-bit/64-bit machines and native files are not
compatible with other machines.

The other thing to remember is that your BIOS and other device chips in the
motherboard such as video cards, also occupy some memory in same 4 GB space so
the actual memory available for use by your applications reduces further to around 1.5
GB only.

2. How 64-bit architecture is different?


While 32 bits of information can only access 4 GB of RAM, a 64-bit machine can
access 17.2 BILLION GB of system memory, at least theoretically. So it must remove
all the barriers of memory consumption from your system, right? But it does not.

Windows 64-bit Home editions are still limited to 16 GB of RAM [ all because of
licensing reasons], but the Professional and Ultimate versions can use up to 192 GB of
RAM at present due to various compatibility issues.
The per-process limit for RAM is also greatly increased—on 64-bit Windows, instead of
a 2 GB limit, each application can access upto 8 TB of virtual memory without any
special configuration (besides it must be present in your system). It is a huge factor in
choosing your next machine when you consider applications like video editing or virtual
machines that may need to use enormous amounts of RAM.

So now we have a good understanding of 32-bit machines vs. 64-bit machines. Let’s
focus on stuff which is related mostly to java.

3. Which versions to Install on 32-bit/64-bit


Machines?
Strictly speaking, on a 32-bit CPU architecture machine, you should install 32-bit
java/JRE. On the other hand, on a 64-bit CPU architecture machine, you are free to
choose between 32-bit java/JRE and 64-bit java/JRE. Both will work just fine. In fact, on
a 64-bit machine decision of JRE version depends on other factors such as the
maximum memory needed to run your application on high-load scenarios.
3.1. High Availability
Please note that the high availability of memory doesn’t come for free. It does have a
cost on runtime e.g. 30-50% of more heap is required on 64-bit in comparison to 32-bit.
Why? Mainly because of the memory layout in 64-bit architecture.

First of all – object headers are 12 bytes on 64-bit JVM. Secondly, object references
can be either 4 bytes or 8 bytes, depending on JVM flags and the size of the heap. This
definitely adds some overhead compared to the 8 bytes on headers on 32-bit and 4
bytes on references.

3.2. Long GC Pauses


Longer garbage collection pauses. Building up more heap means there is more work to
be done by GC while cleaning up unused objects.

What it means in real life is that you have to be extra cautious when building heaps
larger than 12-16GB. Without fine-tuning and measuring you can easily introduce full
GC pauses spanning several minutes which can result in showstoppers.

4. Can a .class Generated using a 32-bit Compiler


be used on 64-bit Machine?
Absolutely Yes. Java byte code is independent from 32-bit or 64-bit
systems. That’s why it is said that the compiled java code shall be executable on “any”
system. Remember that just the virtual machine is compiled for a special system
architecture because of some native files it has in packaged bundle, and native files are
never platform-independent.

If so, then how 32-bit applications run on 64-bit systems? The answer is that 64-bit
systems include a compatibility layer called WoW64, which actually switches the
processor back and forth between 32-bit and 64-bit modes depending on which
thread needs to execute; making 32-bit software run smoothly even in the 64-bit
environment.

5. What is the Maximum RAM Allocation Possible


on a 32-bit vs. 64-bit Machine?
As we learned already the limits allowed on both versions in the previous discussion in
this post. On 64-bit system, the theoretical limit is very high for any configuration
available today (17.2 BILLION GB memory). Still, there are limitations imposed by
vendors for various purposes, which mainly include licensing and compatibility with
other native applications.

Similarly, on 32-bit machine, the limit is 4 GB, and about only 1.5 GB is actually
available for user applications for the reasons stated above in the post.

There is a trick you can pull on 32-bit windows to reduce the kernel space and grow the
user space. You can use the /3GB parameter in your boot.ini. However, to actually use
this opportunity, the JVM must be compiled/linked using
the /LARGEADDRESSAWARE switch.
This unfortunately is not the case, at least with the Hotspot JVM. Until the latest JDK
releases the JVM is not compiled with this option. You are luckier if you are running on
a jRockit on post-2006 versions. In this case, you can enjoy up to 2.8-2.9 GB of the
heap size.

That’s all for this topic. Please drop a comment if something is not clear, or you simply
disagree with me.

Happy Learning !!

References:

 https://community.oracle.com/thread/2497016?tstart=0
 http://en.wikipedia.org/wiki/32-bit
 http://en.wikipedia.org/wiki/64-bit_computing
Difference between Java.exe
and Javaw.exe
“java.exe” and “javaw.exe” are Java executables on the Windows platform. These
files are nearly identical versions of the Java Application Launcher utility. Both versions
of the launcher take the same arguments and options. The launcher is invoked with
“java” or “javaw” followed by launcher options, the class or Java archive (JAR) file name
and application arguments.

1. javaw.exe
This non-console version of the application launcher is used to launch java
applications usually with graphical user interfaces (GUIs). These applications have
windows with menus, buttons and other interactive elements. Essentially,
use javaw.exe when you don’t want a command prompt window to appear either to take
further input or show output.

The javaw.exe launcher will, however, display a dialog box with error information if a
launch of java application fails for some reason.

2. java.exe
The java.exe is very similar to javaw.exe. The console version of the launcher is
used for applications with text-based interfaces or that output text. Any application
launched with “java” will cause the command line waits for the application response till it
closes.

When launched using javaw, the application launches and the command line exits
immediately and is ready for the next command.

That’s the only noticeable difference between java.exe and javaw.exe. If you know of
any other noticeable differences, please share them with all of us.
Java View Bytecode of a Class
File
Many times, we need to understand what a compiler is doing under the hood. How the
java statements we are writing, will be reordered and executed. Also, we need to see
the byte code for learning purposes also, I do it seldom. In this tutorial, I am giving an
example of how to generate the byte code for a class file in java.

To demonstrate the example, I am using the java file created for my other tutorial
related to automatic resource management in java 7.

1. Compile Java File using the command javac


This is optional because you might have the .class file already.

prompt > javac C://temp/java/test/ResourceManagementInJava7.java

This will generate the .class file ResourceManagementInJava7.class.

2. Execute javap Command and Redirect Output


to .bc File
C:>javap -c C://temp/java/test/ResourceManagementInJava7.class > C://temp/java/test/bytecode.bc

Folder view

Let’s look at the command run on the prompt.


Command window view

A file bytecode.bc file will be generated at a given location. It will be something like this:

public class com.howtodoinjava.java7.tryCatch.ResourceManagementInJava7 {

public com.howtodoinjava.java7.tryCatch.ResourceManagementInJava7();

Code:

0: aload_0

1: invokespecial #1 // Method java/lang/Object."<init>":()V

4: return

public static void main(java.lang.String[]);

Code:

0: new #2 // class java/io/BufferedReader

3: dup

4: new #3 // class java/io/FileReader

7: dup

8: ldc #4 // String C:/temp/test1.txt

10: invokespecial #5 // Method java/io/FileReader."<init>":(Ljava/lang/String;)V

13: invokespecial #6 // Method java/io/BufferedReader."<init>":(Ljava/io/Reader;)V

16: astore_1

17: aconst_null

18: astore_2

19: new #2 // class java/io/BufferedReader

22: dup

23: new #3 // class java/io/FileReader

26: dup
27: ldc #7 // String C:/temp/test2.txt

29: invokespecial #5 // Method java/io/FileReader."<init>":(Ljava/lang/String;)V

32: invokespecial #6 // Method java/io/BufferedReader."<init>":(Ljava/io/Reader;)V

35: astore_3

36: aconst_null

37: astore 4

39: new #2 // class java/io/BufferedReader

42: dup

43: new #3 // class java/io/FileReader

46: dup

47: ldc #8 // String C:/temp/test3.txt

49: invokespecial #5 // Method java/io/FileReader."<init>":(Ljava/lang/String;)V

52: invokespecial #6 // Method java/io/BufferedReader."<init>":(Ljava/io/Reader;)V

55: astore 5

57: aconst_null

58: astore 6

60: aload 5

62: ifnull 138

65: aload 6

67: ifnull 90

70: aload 5

72: invokevirtual #9 // Method java/io/BufferedReader.close:()V

75: goto 138

78: astore 7

80: aload 6

82: aload 7

84: invokevirtual #11 // Method java/lang/Throwable.addSuppressed:(Ljava/lang/Throwable;)V

87: goto 138

90: aload 5

92: invokevirtual #9 // Method java/io/BufferedReader.close:()V

95: goto 138

98: astore 8

100: aload 5

102: ifnull 135

105: aload 6

107: ifnull 130

110: aload 5
112: invokevirtual #9 // Method java/io/BufferedReader.close:()V

115: goto 135

118: astore 9

120: aload 6

122: aload 9

124: invokevirtual #11 // Method java/lang/Throwable.addSuppressed:(Ljava/lang/Throwable;)V

127: goto 135

130: aload 5

132: invokevirtual #9 // Method java/io/BufferedReader.close:()V

135: aload 8

137: athrow

138: aload_3

139: ifnull 219

142: aload 4

144: ifnull 166

147: aload_3

148: invokevirtual #9 // Method java/io/BufferedReader.close:()V

151: goto 219

154: astore 5

156: aload 4

158: aload 5

160: invokevirtual #11 // Method java/lang/Throwable.addSuppressed:(Ljava/lang/Throwable;)V

163: goto 219

166: aload_3

167: invokevirtual #9 // Method java/io/BufferedReader.close:()V

170: goto 219

173: astore 5

175: aload 5

177: astore 4

179: aload 5

181: athrow

182: astore 10

184: aload_3

185: ifnull 216

188: aload 4

190: ifnull 212

193: aload_3
194: invokevirtual #9 // Method java/io/BufferedReader.close:()V

197: goto 216

200: astore 11

202: aload 4

204: aload 11

206: invokevirtual #11 // Method java/lang/Throwable.addSuppressed:(Ljava/lang/Throwable;)V

209: goto 216

212: aload_3

213: invokevirtual #9 // Method java/io/BufferedReader.close:()V

216: aload 10

218: athrow

219: aload_1

220: ifnull 290

223: aload_2

224: ifnull 243

227: aload_1

228: invokevirtual #9 // Method java/io/BufferedReader.close:()V

231: goto 290

234: astore_3

235: aload_2

236: aload_3

237: invokevirtual #11 // Method java/lang/Throwable.addSuppressed:(Ljava/lang/Throwable;)V

240: goto 290

243: aload_1

244: invokevirtual #9 // Method java/io/BufferedReader.close:()V

247: goto 290

250: astore_3

251: aload_3

252: astore_2

253: aload_3

254: athrow

255: astore 12

257: aload_1

258: ifnull 287

261: aload_2

262: ifnull 283

265: aload_1
266: invokevirtual #9 // Method java/io/BufferedReader.close:()V

269: goto 287

272: astore 13

274: aload_2

275: aload 13

277: invokevirtual #11 // Method java/lang/Throwable.addSuppressed:(Ljava/lang/Throwable;)V

280: goto 287

283: aload_1

284: invokevirtual #9 // Method java/io/BufferedReader.close:()V

287: aload 12

289: athrow

290: goto 298

293: astore_1

294: aload_1

295: invokevirtual #13 // Method java/io/IOException.printStackTrace:()V

298: return

Exception table:

from to target type

70 75 78 Class java/lang/Throwable

110 115 118 Class java/lang/Throwable

98 100 98 any

147 151 154 Class java/lang/Throwable

39 138 173 Class java/lang/Throwable

39 138 182 any

193 197 200 Class java/lang/Throwable

173 184 182 any

227 231 234 Class java/lang/Throwable

19 219 250 Class java/lang/Throwable

19 219 255 any

265 269 272 Class java/lang/Throwable

250 257 255 any

0 290 293 Class java/io/IOException

}
Little-Endian and Big-Endian
in Java
We must have heard the terms Little-Endian and Big-Endian many times in your
engineering course. Let’s quickly recap the concept behind these words.

1. Little-Endian vs Big-Endian
These two terms are related to the direction of bytes in a word within CPU
architecture.

Computer memory is referenced by addresses that are positive integers. It is “natural” to


store numbers with the least significant byte coming before the most significant byte in
the computer memory.

Sometimes computer designers prefer to use a reversed-order version of this


representation.

The “natural” order, where the less significant byte comes before the more
significant byte in memory, is called little-endian.

Many vendors like IBM, CRAY, and Sun preferred the reverse order that, of course, is
called big-endian.

2. Example of Ordering
For example, the 32-bit hex value 0x45679812 would be stored in memory as follows:

Address 00 01 02 03

-----------------------------------

Little-endian 12 98 67 45

Big-endian 45 67 98 12
3. Endian-ness in Java
The difference in endian-ness can be a problem when transferring data between two
machines.

Everything in Java binary files is stored in big-endian order. This is sometimes


called network order. This means that if you use only Java, all files are done the same
way on all platforms: Mac, PC, UNIX, etc. You can freely exchange binary data
electronically without any concerns about endian-ness.

The problem comes when you must exchange data files with some program not written
in Java that uses little-endian order, most commonly a program written in C. Some
platforms use big-endian order internally (Mac, IBM 390); some uses little-endian order
(Intel).

4. How to Know the Endian-ness


In Java, we can use the method ByteOrder.nativeOrder() to obtain the byte order used
by the CPU. Below is the output on an Intel CPU.

ByteOrder byteOrder = ByteOrder.nativeOrder();

System.out.println(byteOrder); //LITTLE_ENDIAN

5. Conclusion
Java hides that internal endian-ness from us and gives us consistent results in all the
platforms.

But in programming languages, where code reads the data directly from the memory
areas using pointers, endian-ness could be an issue in cases where data is transferred
from one machine to another machine and both machines have different endian-ness.
Java Pass-by-Value or Pass-
by-Reference
Java is passed by value and not
pass-by-reference. If it had been
pass-by-reference, we should have
been able to C like swapping of
objects.
There has been a lot of debate on whether “java is pass by value or pass by
reference?“. Well, let us conclude last time, Java is passed by value and not pass-
by-reference. If it had been pass-by-reference, we should have been able to C like
swapping of objects, but we can’t do that in java. We know it already, right?

1. Java is Pass-by-value
When you pass an object to a method, its memory address is copied bit by bit to a new
reference variable, thus both pointing to the same instance. But if you change the
reference inside the method, the original reference will not change.

If Java was pass-by-reference, then it would have got changed also.

To prove it, let’s see how memory allocations happen in run time. It should solve the
slightest doubts if any. I am using the following program for demonstration of the
concept.

public class Foo

private String attribute;


public Foo (String a){

this.attribute = a;

public String getAttribute() {

return attribute;

public void setAttribute(String attribute) {

this.attribute = attribute;

public class Main

public static void main(String[] args){

Foo f = new Foo("f");

changeReference(f); // It won't change the reference!

modifyReference(f); // It will change the object that the reference variable "f" refers to!

public static void changeReference(Foo a) {

Foo b = new Foo("b");

a = b;

}
public static void modifyReference(Foo c) {

c.setAttribute("c");

2. Analysis
Let us see what happens on runtime step by step when the above program runs:

Foo f = new Foo("f");

This statement will create an instance of class Foo, with ‘attribute’ initialized to ‘f’. The
reference to this created instance is assigned to variable f;

public static void changeReference(Foo a)

When this executes then a reference of type Foo with a name a is declared and it’s
initially assigned to null.
changeReference(f);

As you call the method changeReference(), the reference a will be assigned to the
object which is passed as an argument.

Foo b = new Foo("b"); //inside first method


This will do exactly the same as in the first step, and will create a new instance of Foo,
and assign it to b;
a = b;

This is an important point. Here, we have three reference variables, and when the
statement executes, a and b will point to the same instance created inside the method.
Note: f is unchanged, and it is continually pointing to instance, it was pointing originally.
NO CHANGE !!

modifyReference(Foo c);

Now when this statement executed a reference, c is created and assigned to the object
with attribute “f”.
c.setAttribute("c");

This will change the attribute of the object that reference c points to it, and the same
object that reference f points to it.

I hope that this explanation was clear enough to make your understanding better if it
was not already.

Happy Learning !!

You might also like