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

THE JAVA EXPERIENCE

The document chronicles a beginner's journey learning Java, highlighting its features such as platform independence, strong typing, and object-oriented principles. It provides an overview of Java's architecture, including the JDK, JRE, and JVM, as well as key concepts like memory management and variable scope. The author expresses gratitude for the learning experience and emphasizes the importance of problem-solving and adaptability in programming.

Uploaded by

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

THE JAVA EXPERIENCE

The document chronicles a beginner's journey learning Java, highlighting its features such as platform independence, strong typing, and object-oriented principles. It provides an overview of Java's architecture, including the JDK, JRE, and JVM, as well as key concepts like memory management and variable scope. The author expresses gratitude for the learning experience and emphasizes the importance of problem-solving and adaptability in programming.

Uploaded by

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

THE JAVA EXPERIENCE: A BEGINNER'S JOURNAL

ADEBAYO OLUWAFIKAYO JAMES

As a beginner, I was both excited and intimidated by the vast world of programming. I enrolled in a
coding bootcamp, and at the time of my enrollment, Java was the only high-level programming language
offered. After completing my initial studies in SQL, I embarked on my journey to learn Java. Although it
was not a deliberate choice, I have found immense value in learning this versatile language. Java's robust
features, platform independence, and extensive community support have made it an excellent
foundation for my programming skills. The language's strong typing and object-oriented principles have
provided me with a solid understanding of software development. Additionally, Java's widespread use in
various industries has opened up numerous opportunities for me to apply my knowledge in real-world
scenarios. Learning Java has not only equipped me with technical skills but also fostered a deeper
appreciation for problem-solving and logical thinking. The challenges I encountered along the way have
strengthened my perseverance and adaptability, qualities that are essential for any aspiring developer.

I am grateful for the path that led me to Java, embarking on the journey to learn Java has been an
exciting experience, filled with moments of discovery, challenge, and growth. This documentation serves
as both a personal learning journal and a comprehensive guide, chronicling my progression from basic
concepts to advanced Java implementations.

EVERYTHING JAVA

Java is a high-level programming language used for building web applications, mobile applications,
enterprise software and backend APIs. Java was developed by James Goslin and released in 1995 by Sun
microsystems which was later purchased by Oracle in 2010.

CHARACTERISTICS OF JAVA

Platform Independence

• Java's "Write Once, Run Anywhere" philosophy is made possible through the Java Virtual
Machine (JVM). Code written in Java can run on any device with a JVM, regardless of the
underlying hardware or operating system

Strong Type System

• Java enforces strict type checking at compile time, this helps catch errors early and ensures code
reliability

Object-Oriented

• Everything in Java is an object (except primitive data types).


• Java supports all major OOP concepts: Inheritance, Encapsulation, Polymorphism, and
Abstraction which promotes reusable, modular, and maintainable code.

Automatic Memory Management

• Java manages memory allocation and deallocation automatically and reduces common
programming errors like memory leaks.
Rich Standard Library

• Comes with a comprehensive set of built-in libraries (Java API) that provides ready-to-use
components for various programming tasks.

Multithreading Support

• Built-in support for concurrent programming, allowing multiple threads to run simultaneously.
This enables efficient utilization of system resources.

Robustness

• Strong exception handling mechanism with strict compile-time checking.

High Performance

• Dynamic/JIT (Just-In-Time) compilation for faster execution.

Development in Java comprises of three components that work together to enable Java’s capabilities,
they are:

❖ JDK (Java Development Kit)-This is a collection of programs (tools and utilities) including the Java
Runtime Environment (JRE), an interpreter/loader, a compiler, an archiver, a documentation
generator and other tools needed in Java development. The Java Development Kit (JDK) is the
most important tool to install for Java development because it provides everything you need to
develop, compile, debug, and run Java applications. There are multiple vendors for the JDK,
examples include Open JDK, Oracle JDK, Adoptium JDK, Azul JDK, Amazon Corretto, RedHat, IBM.
❖ JRE (Java Runtime Environment)- It provides the minimum requirements for executing a java
application. It consists of the Java Virtual Machine (JVM), core classes and supporting files. The
JRE allows the execution of already compiled Java code using only the .class file. The JRE stopped
being supported from Java 9.
❖ JVM (Java Virtual Machine)- The JVM (Java Virtual Machine) is a virtual machine, an abstract
computer that has its own ISA, memory, stack, heap, etc. It runs on the host OS and places its
demands for resources on it. This is a program that reads bytecode of the compiled Java Program
and interprets it into OS specific binary code that is executable by a computer. The JVM is
responsible for the platform independence of Java, memory management, execution engine
(Interpreter, JIT Compiler), security manager (enforces security policies, manages access control,
protects system resources).
Components of JVM (Java Virtual Machine) Architecture:
1. Class Loader- The JVM manages the process of loading, linking and initializing classes and
interfaces in a dynamic manner. During the loading process, the JVM finds the binary
representation of a class and creates it.
During the linking process, the loaded classes are combined into the run-time state of the JVM so
that they can be executed during the initialization phase. The JVM basically uses the symbol table
stored in the run-time constant pool for the linking process. Initialization consists of actually
executing the linked classes.
The following are the types of class loaders:
o BootStrap class loader: This class loader is on the top of the class loader hierarchy. It
loads the standard JDK classes in the JRE's lib directory.
o Extension class loader: This class loader is in the middle of the class loader hierarchy and
is the immediate child of the bootstrap class loader and loads the classes in the JRE's
lib\ext directory.
o Application class loader: This class loader is at the bottom of the class loader hierarchy
and is the immediate child of the extension class loader. It loads the jars and classes
specified by the CLASSPATH ENV variable.

2. Linking and Initialization - The linking process consists of the following three steps:

o Verification − This is done by the Bytecode verifier to ensure that the generated .class
files (the Bytecode) are valid. If not, an error is thrown and the linking process comes to
a halt.
o Preparation − Memory is allocated to all static variables of a class and they are initialized
with the default values.
o Resolution − All symbolic memory references are replaced with the original references.
To accomplish this, the symbol table in the run-time constant memory of the method
area of the class is used.

3. Runtime Data Areas - The JVM spec defines certain run-time data areas that are needed
during the execution of the program. Some of them are created while the JVM starts up. Others
are local to threads and are created only when a thread is created (and destroyed when the
thread is destroyed). These are listed below −

o PC (Program Counter) Register - It is local to each thread and contains the address of the
JVM instruction that the thread is currently executing.
o Stack - It is local to each thread and stores parameters, local variables and return
addresses during method calls. A StackOverflow error can occur if a thread demands
more stack space than is permitted. If the stack is dynamically expandable, it can still
throw OutOfMemoryError.
o Heap - It is shared among all the threads and contains objects, classes' metadata, arrays,
etc., that are created during run-time. It is created when the JVM starts and is destroyed
when the JVM shuts down. You can control the amount of heap your JVM demands from
the OS using certain flags (more on this later). Care has to be taken not to demand too
less or too much of the memory, as it has important performance implications. Further,
the GC manages this space and continually removes dead objects to free up the space.
o Method Area - This run-time area is common to all threads and is created when the JVM
starts up. It stores per-class structures such as the constant pool (more on this later), the
code for constructors and methods, method data, etc. The JLS does not specify if this
area needs to be garbage collected, and hence, implementations of the JVM may choose
to ignore GC. Further, this may or may not expand as per the application's needs. The JLS
does not mandate anything with regard to this.
o Run-Time Constant Pool - The JVM maintains a per-class/per-type data structure that
acts as the symbol table (one of its many roles) while linking the loaded classes.
o Native Method Stacks - When a thread invokes a native method, it enters a new world in
which the structures and security restrictions of the Java virtual machine no longer
hamper its freedom. A native method can likely access the runtime data areas of the
virtual machine (it depends upon the native method interface), but can also do anything
else it wants.

4. Execution Engine - The execution engine is responsible for executing the bytecode, it has
three different components:

o Garbage Collection - The JVM manages the entire lifecycle of objects in Java. Once an
object is created, the developer need not worry about it anymore. In case the object
becomes dead (that is, there is no reference to it anymore), it is ejected from the heap
by the GC using one of the many algorithms – serial GC, CMS, G1, etc. During the GC
process, objects are moved in memory. Hence, those objects are not usable while the
process is going on. The entire application has to be stopped for the duration of the
process. Such pauses are called 'stop-the-world' pauses and are a huge overhead. GC
algorithms aim primarily to reduce this time.
o Interpreter - The interpreter Interprets the bytecode. It interprets the code fast but it's
slow in execution.
o JIT Complier - The JIT stands for Just-In-Time. The JIT compiler is a main part of the Java
runtime environment and it compiles bytecodes to machine code at runtime.

5. Java Native Interface (JNI) - Java Native Interface (JNI) interacts with the native method
libraries which are essential for the execution.

6. Native Method Libraries - Native method libraries are the collection of C and C++ libraries
(native libraries) which are essential for the execution.

The following processes occur for the execution of a java program:

Business Logic/Source Code- Always written inside


a class that can also have a number of classes with
a main method and save file with .java extension

Compile- The Java compiler reads a text written


in Java programming language and translates it
into bytecode that can be interpreted by the JVM Compilation
stage

Byte code- If the compilation is successful, a new


file with .class extension will be generated
The Class Loader loads and verifies the byte code,
the execution Engine interprets or compiles the
bytecode into native code, the JIT Compiler
optimizes the execution by compiling frequently
executed bytecode into native code. All these
processes occur in the JVM Converting the byte

Interpretation Stage
code to specific OS executable code.

Output

MEMORY MANAGEMENT

Memory management is handled by the JVM. The JVM is responsible for allocating and deallocating
memory for Java programs. Java Programs are executed in a runtime environment that includes several
different memory types. These memory types include:

• Heap Memory: This is the area of memory where objects are located and it is reclaimed by the
JVM garbage collector when it is no longer being used.
• Stack Memory: This is the area of memory where local variables and method calls are stored.
When a method is called, a new stack frame is created on the stack which contains local
variables and parameters. When the method is returned, the stack frame is removed from the
stack.
• Method Area: This is the area of the memory where class definitions and other runtime
constants are stored.
• Native Heap: This is the area where native libraries and codes are stored.

JAVA PROGRAMMING LANGUAGE: SYNTAX AND STRUCTURE

A programming language is like a special set of instructions that we use to communicate with computers,
programming languages help us tell computers what to do. They allow us to write code that the
computer can understand and execute.

In programming, syntax is like the grammar rules we follow when writing code. It tells us how to arrange
symbols, keywords, and operators to create valid and meaningful statements. Just like grammar in a
language helps us form correct sentences, syntax in programming ensures our code is structured
properly and can be understood by the computer.

Java allows two or more expression statements to be grouped into blocks of code, also called code
blocks. This is done by enclosing the statements between opening and closing curly braces({}). Once a
block of code has been created, it becomes a logical unit that can be used any place that a single
statement can. In Java, all code is organized within classes and to start the execution of a Java program,
there is a special method that the Java Virtual Machine (JVM) calls known as the main method. This
method is the entry point for any Java application.

As you progress in Java, there will be more sophisticated aspects of the language that allow you to write
powerful and flexible programs.

Key aspects of java syntax

• Keywords: Reserved words that have special meaning in the language. They are part of the
syntax and cannot be used as identifiers.
• Identifiers: Names given to variables, methods, classes, and other entities. There are different
case styles used in the naming of the identifiers of variables, methods and classes. Classes use a
pascal case approach (All the words begin with a upper case letters including the first word e.g
FirstName), while variables and methods use the camel case approach (The first word starts with
lower case letters while the other words that follow begin with upper case letters e.g firstName).
• Operators: Symbols that perform operations on variables and values.
• Punctuation: Characters that separate statements and elements.
• Comments: Non-executable text that provides explanations or notes within the code.

VARIABLE: A variable is the memory location where we want to store a value/data. A variable is a
container to store value/data. This value/data can be retrieved or manipulated trough out the
execution of a program. The Java programming language is statically-typed, which means Variables
must be declared before they can be used. A variable declaration specifies the variable's datatype
and name(identifier). The process of assigning a value/data to the value is called initialization.
Variables can be initialized at the time of declaration or later in the code.
SCOPE OF VARIABLES

The scope of variable defines where it can be accessed and used within a program. Java, variables
can have different types:

There are three variable scopes in the Java programming language:

▪ Local Variable - Local Variables are declared inside the method body and used only within
that method, while other methods in a class don’t know that the variable exists. They are
implemented at the stack level internally; it is necessary to initialize local variables before
using them in a defined scope. You can’t use access modifiers for local variables in Java. Local
variables have no default value, so they are declared and assigned an initial value before the
first use.

▪ Instance Variable - Instance variables are declared within a class but outside a method. They
are defined without the ‘static’ keyword. As their value is instance-specific and they are not
shared among instances, they are called instance variables. Each instance of a class has its
own copy of the variable, they are created when an object is created using the ‘new’
keyword and destroyed when the object is destroyed. Initialization of instance variables is
not necessary, and their default value is based on the data type. For example, String is null;
int is 0, the float is 0.0f, and the Wrapper class, such as integer, is null. Unlike local variables,
instance variables can use access modifiers. If no access modifier is specified, the default
modifier will be used.
▪ Static/ Class Variable - Static variable are declared the same way as instance variables. But
the difference is static variables are declared within the static keyword in a class but outside
of any method, block, or constructor. Most class variables are declared public as they need
to be available for users of a class. They can be accessed with the class name, if you access a
class variable like an instance variable, the compiler will send a warning message and replace
the object name with the class name automatically without stopping the program. Static
variables are stored in the static memory, they are created at the beginning of program
execution and destroyed automatically once the execution ends. You can have only one copy
of a static variable per class, no matter how many objects you create from it. Static variables
are hardly used other than being declared constants, which can be final, public/private, and
static. Also, constant variables don’t change their initial value.

• Reference Variables - A reference variable is a variable that points to (or references) an


object in memory. The object itself is stored in the heap, while the reference variable holds
the address (or reference) to that object. This allows you to interact with the object
indirectly through its reference. Unlike primitive variables that hold the actual values (like
int, char, etc.), reference variables store the memory address of the objects they refer to.

DATA TYPES IN JAVA

Java provides various data types to store different kinds of data. These are categorized into two main
types: primitive data types and reference data types.

▪ primitive data types: Java provides a set of eight primitive data types that serve as the building
blocks for data manipulation in the language. These data types are not objects and hold their
values directly in memory. A variable's data type determines the values it may contain, plus the
operations that may be performed on it. The primitive datatype comprises of char, boolean,
byte, short, int, long, float, double.
Integer types store whole numbers, positive or negative without decimals. The types are byte,
short, int and long.
Floating point types represents numbers containing one or more decimals. The types are float
and double.
The boolean data type, can only take the values true or false.
The char data type is used to store a single character. The character must be surrounded by
single quotes, like 'A' or 'c'.

Primitive Data Type Size Range Default Value


Char 16 bits '\u0000' to '\uffff' '\u0000'
Boolean 1 bit True or False False
Byte 8 bits -128 to 127 0
Short 16 bits -32,768 to 32,767 0
Int 32 bits -2^31 to 2^31-1 0
long 64 bits -2^63 to 2^63-1 0L
float 32 bits stores 6 to 7 decimal 0.0f
digits
double 64 bits stores 15 to 16 0.00d
decimal digits

It's not always necessary to assign a value when a field is declared. Fields that are declared but not
initialized will be set to a reasonable default by the compiler. Local variables are slightly different; the
compiler never assigns a default value to an uninitialized local variable. If you cannot initialize your local
variable where it is declared, make sure to assign it a value before you attempt to use it. Accessing an
uninitialized local variable will result in a compile-time error.

Type Casting: Type casting is when you assign the value of one primitive data type to another type.
There are two types of casting in Java;

o Widening/automatically/implicit casting: - Converting a smaller type to a larger type. It is done


automatically and safe because there is no chance to lose data.
byte → short → char → int → long → float → double
o Narrowing/manually/explicit casting: - Converting a larger type to a smaller size type. It should
be done manually by the programmer. If we do not perform casting, then the compiler reports a
compile-time error.
double → float → long → int → char → short → byte

▪ reference data types: Non-primitive data types are called reference types because they refer to
objects. Unlike primitive data types, reference data types do not store the actual data values
directly in memory. Instead, they store references (or addresses) to the location where the data
is stored. reference types can be used to call methods to perform certain operations, whereas
primitive types cannot. Primitive types start with a lowercase letter (like int), while reference
types typically start with an uppercase letter (like String). Primitive types always hold a value,
whereas reference types can be null, the null value is a special literal used to indicate that a
reference variable does not point to any object in memory. Examples of reference types are
Strings, Arrays, Classes.

String: A String variable is a sequence of characters. String literals are the most common way to
create a text in java. They are created by enclosing a series of characters within double quotes
(“”).
A String in Java is actually an object that represents a series, creating a String with the “new”
keyword is also possible.

Although, it is always recommended to use literal style of declaration of a String instead of the
“new” operator, this is because the literal style will be stored inside the String pool while the
“new” keyword style stores the string as an object which is stored in the heap memory. The
String pool saves memory and improves performance.

Java provides a wide range of methods to perform certain operations and work with Strings.
These methods include:

o charAt(int index) - Returns the character at the specified index.


o compareTo(String anotherString) - Compares two strings in alphabetical order.
o compareToIgnoreCase(String str) - Compares two strings in alphabetical order, ignoring
case differences.
o concat(String str) - Combines two strings together by adding the second string to the
end of the first.
o contains(CharSequence s) - Checks if the current string contains the specified sequence
of characters.
o endsWith(String suffix) - Checks if the current string ends with the specified suffix.
o equals(Object anObject) - Compares the current string to another specified String.
o equalsIgnoreCase(String anotherString) - Compares the current string to another string,
ignoring case differences.
o format(String format, Object... args) - Returns a formatted string using the specified
format string and arguments.
o indexOf(int ch) - Returns the index of the first occurrence of the specified character.
o indexOf(String str) - Returns the index of the first occurrence of the specified substring.
o isEmpty() - Checks if the string is empty.
o length() - Returns the length of the string.
o replace(char oldChar, char newChar) - Replaces all occurrences of the old character with
the new character.
o replaceAll(String regex, String replacement) - Replaces each substring that matches the
given regular expression with the specified replacement.
o split(String regex) - Splits the string into an array of substrings based on the specified
regular expression.
o startsWith(String prefix) - Checks if the current string starts with the specified prefix.
o substring(int beginIndex) - Returns a new string that is a substring of the current string,
starting from the specified index.
o substring(int beginIndex, int endIndex) - Returns a new string that is a substring of the
current string, starting from the specified begin index and extending to the end index.
o toCharArray() - Converts the string to a new character array.
o toLowerCase() - Converts all characters in the string to lowercase.
o toUpperCase() - Converts all characters in the string to uppercase.
o trim() - Removes leading and trailing whitespace from the string.

OPERATORS IN JAVA

Java operators are special symbols that perform operations (carries out a specific action) on one, two or
three operands (A variables/values that is being manipulated by an operator). In general, operators allow
you to do something with the variables/values.

Java Operators can be categorized:

• Based on the Number of operands


o Unary Operators – involves one operand.
o Binary Operators – involves two operands.
o Ternary Operators – involves three operands.

• Based on the type of Operation (The action they carry out)


o ASSIGNMENT OPERATOR - The assignment operator (=), assigns the value on its right to the
operand on its left with the condition that the value on the left is a variable. Assignment
operator is evaluated from right to left. The right operand must be assignment-compatible with
the data type of the left operand (i.e the value of the literal must be the same value of the
variable declared). If this compatibility is not met, a compile-time error will occur.
o ARITHMETIC OPERATOR – arithmetic operators work with numeric values to produce a new
numeric result. They are used to perform common mathematical operations and operate
exclusively with numeric data types, such as byte, short, char, int, long, float, and double. They
do not support boolean data types or reference types. Arithmetic Operators include:

Arithmetic Operator Name Description


+ Addition Adds together two values
- Subtraction Subtracts one value from another
* Multiplication Multiplies two values
/ Division Divides one value by another
% Modulus Returns the division remainder
++ Increment Increases the value of a variable by 1
-- Decrement Decreases the value of a variable by 1
+ Unary Plus Operator Makes the value of its operand positive
- Unary Minus Operator Arithmetically negates the value of its
operand
Each of the five fundamental arithmetic operators (+, -, *, /, and %) has an associated compound
arithmetic assignment operator. With this compound arithmetic operator, the mathematical
operation is carried out and the resulting value is assigned to the operand on the left.

Compound Arithmetic
Operators
+=
-=
*=
/=
%=

Below is an example use case:

NOTE: The increment/decrement operators can be used in two different ways –

Postfix increment/decrement operators e.g num++


Prefix increment/decrement operators e.g ++num
When the increment/decrement operator is used before the variable name, It is known as
pre increment/decrement, the value of the variable is modified before the rest of the
expression is evaluated.

When the increment/decrement operator is used after the variable name, It is known as
post increment/decrement, the value of the variable is modified after the expression is
evaluated.

o RELATIONAL/COMPARISON OPERATORS – A relational/comparison operator is used to compare


two values/variables(operand). The return value of a comparison is a boolean value which
means it is either true or false. Relational Operators operate on two operands thereby making it
a binary operator. They are extensively used in looping statements as well as conditional if-else
statements.

Relational Operator Description


== Equal To
!= Not Equal To
> Greater Than
>= Greater Than or Equal To
< Less Than
<= Less Than or Equal To

o LOGICAL/CONDITIONAL OPERATORS - Logical operators are used to determine the logic between
variables or values. They Compare two operands and return a boolean result.

Logical Operator Description


! Logical NOT
& Logical AND
| Logical OR
&& Short-Circuit AND
|| Short-Circuit OR

AND: returns true when both conditions are true.


OR: returns true if at least one condition is true.
NOT: returns true when a condition is false and vice-versa

The short-circuit operators exhibit "short-circuiting" behavior, which means the second condition
is not evaluated if the first is false therefore, the second operand is evaluated only if needed.

Java evaluates first the operator which has the highest and lowest precedence. When operators with the
same precedence are used, Java will follow the associativity of the operator.

OPERATOR PRECEDENCE – This is the order in which Java evaluates expressions in an expression.
ASSOCIATIVITY OF OPERATORS – In Java, this refers to the order in which operators of the same
precedence are evaluated in an expression. There are two types of associativity:

Left Associativity: Operators are evaluated from left to right.


Right Associativity: Operators are evaluated from right to left.

Precedence & Associativity Operator


16 & Left-Right .
[]
(args)
++, -- (post)
15 & Right-Left ++, --(pre)
+, - (unary plus and minus)
~
!
14 & Right-Left new
(type)(type casting)
13 & Left-Right *, /, %
12 & Left-Right +, - (addition & subtraction)
+ (String Concatenation)
11 & Left-Right <<
>>
>>>
10 & Left-Right <, <=
>, >=
instanceOf()
9 & Left-Right == (values)
!= (values)
== (objects)
!= (objects)
8 & Left-Right & (integer)
& (Boolean)
7 & Left-Right ^ (integer)
^ (Boolean)
6 & Left-Right | (integer)
| (Boolean)
5 & Left-Right &&
4 & Left-Right ||
3 & Right-Left ?:
2 & Right-Left =
*=, /=, +=, -=, <<=, >>=, >>>=, &=, ^=,|=
1 & Right-Left ->

EXPRESSIONS AND STATEMENTS

EXPRESSION: An Expression is a combination of one or more values, operators and method invocations
that produces a result. The data type of the value returned by an expression depends on the elements
used in the expression. The simplest expressions are called primary expressions and consists of literals
and variables. The Java programming language allows you to construct compound expressions from
various smaller expressions as long as the data type required by one part of the expression matches the
data type of the other. When writing compound expressions, indicate with a parenthesis which operators
should be evaluated first.

STATEMENTS: A statement denotes an operation. In Java, a statement forms a complete unit of


execution. Statements are roughly equivalent to sentences in natural languages. These statements are
constructed using keywords, operators and expressions, it typically represents an action to be carried
out. Statements are terminated with a semicolon (;). Depending on the action performed, Statements in
Java are classified into three categories: -

• Declaration Statement – Introduces a new variable by specifying its data type and identifier
(name).
• Expression Statement – Comprises literals, variables, method invocations. When an expression is
evaluated, it can result in the creation of a variable, the derivation of a value, or no tangible
outcome.
• Control Flow Statement – Control flow statements enable actions based on conditions. They
allow you to execute statements when a specific condition is met or repeat a set of statements
for a specified number of times or as long as a particular condition holds true. These statements
provide flexibility in managing the flow of your Java program based on varying conditions.
The statements inside your source files are generally executed from top to bottom, in the order
that they appear. Control flow statements, however, break up the flow of execution by
employing decision making, looping, and branching, enabling your program to conditionally
execute particular blocks of code.
We have the following Control Flow Statements:
❖ Selection Statement/Conditional Branches, which we use for choosing between two or more
paths. Selection Statement/Conditional Branches decide which statement to execute and when.
Decision-making statements evaluate the Boolean expression and control the program flow
depending upon the result of the condition provided. There are three types in Java: If Statement
(if/else/else if), ternary operator and switch statement.
1. If Statement: In Java, the "if" statement is used to evaluate a condition. The control of
the program is diverted depending upon the specific condition. The condition of the If
statement gives a Boolean value, either true or false. In Java, there are four types of if-
statements given below.
▪ Simple if statement - It evaluates a Boolean expression and enables the program
to enter a block of code if the expression evaluates to true.
▪ if-else statement - The if-else statement is an extension to the if-statement,
which uses another block of code, i.e., else block. The else block is executed if
the condition of the if-block is evaluated as false.
▪ if-else-if ladder - The if-else-if statement contains the if-statement followed by
multiple else-if statements. It is a chain of if-else statements that create a
decision tree where the program may enter in the block of code where the
condition is true. We can also define an else statement at the end of the chain.

▪ Nested if-statement – Here, the if statement can contain a if or if-else statement


inside another if or else-if statement.
2. Switch Statement: The switch statement contains multiple blocks of code called cases
and a single case is executed based on the variable which is being switched. While using
switch statements, we must notice that the case expression will be of the same type as
the variable. However, it will also be a constant value. The case variables can be int,
short, byte, char, enum, or String. The Cases cannot be duplicated. We cannot write Java
expressions that will result as a boolean, long, float, or double in a switch case
statement. Break statement terminates the switch block when the condition is satisfied,
although It is optional, if not used, the next case is executed. Default statement is
executed when any of the case doesn't match the value of expression. It is optional.
Switch Expression – Java 14 introduced a less verbose syntax to the switch statement. It uses an
arrow (->) and does not use a break statement resulting in a more concise form. This syntax also
supports multiple constants per case, separated by commas.
3. Ternary Operator: Ternary Operators are often used as a short hand for simple if-else
statements. It is usually used when business logic executes only single statements.
❖ Iteration Statement/ Loops that are used to iterate through multiple values/objects and
repeatedly run specific code blocks. The basic loop types in Java are for, while and do while.
▪ for loop - It enables us to initialize the loop variable, check the condition, and
increment/decrement in a single line of code. We use the for loop only when we
exactly know the number of times, we want to execute the block of code.

▪ while loop - The while loop is also used to iterate over the number of statements
multiple times. However, if we don't know the number of iterations in advance,
it is recommended to use a while loop. Unlike for loop, the initialization and
increment/decrement doesn't take place inside the loop statement in while
loop. It is also known as the entry-controlled loop since the condition is checked
at the start of the loop. If the condition is true, then the loop body will be
executed; otherwise, the statements after the loop will be executed.
▪ do-while loop - When the number of iterations is not known and we have to
execute the loop at least once, we can use do-while loop. The do-while loop
checks the condition at the end of the loop after executing the loop statements.
It is also known as the exit-controlled loop since the condition is not checked in
advance.
▪ for-each loop - Java offers an enhanced for loop that allows you to iterate
through data structures like arrays and collections effortlessly.
❖ Branching Statements, which are used to alter the flow of control in loops. There are two types in
Java: break and continue.
▪ break statement - The break statement is used to interrupt the current flow of the
program and transfer the control to the next statement outside a loop or switch
statement. It breaks only the inner loop in the case of the nested loop. The break
statement cannot be used independently in the Java program, i.e., it can only be
written inside the loop or switch statement.

▪ continue statement - The continue statement skips the specific part of the loop and
jumps to the next iteration of the loop immediately.
OBJECT-ORIENTED PROGRAMMING

In Java, all expressions, statements, and other code elements are encapsulated within classes. This
ensures that Java adheres to its object-oriented principles, which emphasize the use of objects and
classes to structure programs. Classes and objects are basic concepts of Object-Oriented
Programming (OOP). Object-oriented programming is about creating objects that contain both data
and methods. Although object-oriented programs still issue commands to the computer, they first
organize the data with the help of class and objects before executing any commands. Due to this,
object-oriented programming has many advantages like:

o Reusability
o Modularity
o Easy maintenance
o Encapsulation
o Inheritance
o Polymorphism
Difference Between Java Classes and Objects

Class Object
Class is the blueprint of an object. It is used to An object is an instance of the class
create objects.
No memory is allocated when a class is declared Memory is allocated as soon as an object is
created
A class is a group of similar objects An object is a real-world entity such as a book,
car, etc.
Class is a logical entity An object is a physical entity
A class can only be declared once Objects can be created many times as per
requirement
An example of class can be a car Objects of the class car can be BMW, Honda, etc.

There are basic concepts of Object-Oriented Programming (OOP), which we use to model real-life
entities.

Key Concepts of Object-Oriented Programming

• Class
• Object
• Encapsulation
• Inheritance
• Polymorphism
• Abstraction
• Interface

CLASS

A class is a blueprint from which individual objects are created (or, we can say a class is a data type of an
object type). Class defines the attributes and methods that an object will have.

Properties of Java Classes

▪ A class does not take any byte of memory.


▪ A class is just like a real-world entity, but it is not a real-world entity. It's a blueprint where
we specify the functionalities.
▪ A class contains mainly two things: Methods and Data Members.
▪ A class can also be a nested class.
▪ Classes follow all of the rules of OOPs such as inheritance, encapsulation, abstraction, etc.

To create (declare) a class, you need to use access modifiers followed by “class” keyword and class name
(identifier).

Access modifiers - Java access modifiers are keywords used to specify the visibility of variables, classes,
or methods. These help to restrict and secure the access (or, level of access) of the data. There are four
different types of access modifiers in Java:

o Default (No keyword required) - Default access modifier means we do not explicitly declare an
access modifier for a class, field, method, etc. A variable or method declared without any access
control modifier is available to any other class in the same package. This does not apply to the
fields in an interface. Interface fields are implicitly public static final and the methods in an
interface are by default public.
o Private - Private access modifier is the most restrictive access level. Methods, variables, and
constructors that are declared private can only be accessed within the declared class itself.
Variables that are declared private can be accessed outside the class, if public getter methods
are present in the class. Using the private modifier is the main way that an object encapsulates
itself and hides data from the outside world. Class and interfaces cannot be private.
o Protected - Variables, methods, and constructors, which are declared protected in a superclass
can be accessed only by the subclasses in other package or any class within the package of the
protected members' class. The protected access modifier cannot be applied to class and
interfaces. Methods, fields can be declared protected, however methods and fields in a interface
cannot be declared protected.
o Public - A class, method, constructor, interface, etc. declared public can be accessed from any
other class. Classes usually have public modifiers, but we tend to keep our fields private. If the
public class we are trying to access is in a different package, then the public class still needs to be
imported. Because of class inheritance, all public methods and variables of a class are inherited
by its subclasses.

In Java, classes can contain fields(attributes/variables), constructors, and methods.


Data members: Data members are also called fields. We use fields to hold the state, it is actually an
attribute of the class, or you could say that class attributes are variables within a class. Attributes are
variables that hold the data specific to an object. They are defined inside the class but outside any
methods.

Constructors: A constructor is a block of codes similar to the method, however, constructors have no
explicit return type. A constructor is a special method used to initialize objects. It is called when an
object of the class is created i.e. it is used to initialize the object. Constructors have the same name as
the class. Every time an object is created using the “new” keyword, at least one constructor is called.
Typically, you will use a constructor to give initial values to the instance variables defined by the class or
to perform any other start-up procedures required to create a fully formed object. All classes have
constructors, whether you define one or not because Java automatically provides a default constructor
that initializes all member variables to zero. However, once you define your constructor (Parameterized
Constructor), the default constructor is no longer used.

Rules for Creating Java Constructors

• The name of the constructors must be the same as the class name.
• Java constructors do not have a return type.
• There can be multiple constructors in the same class, this concept is known as constructor
overloading.
• The access modifiers can be used with the constructors, use if you want to change the
visibility/accessibility of constructors.
• Java provides a default constructor that is invoked during the time of object creation. If you
create any type of constructor, the default constructor (provided by Java) is not invoked.
• A Java constructor cannot be abstract, static, final, and synchronized.
Method: Methods define the behaviors of the class. A method is a block of code or collection of
statements or a set of code grouped together to perform a certain task or operation. They are also
known as functions.

To create a Java method, there should be an access modifier followed by the return type, method's
name, and parameters list followed by parentheses ().

• modifier − It defines the access type of the method and it is optional to use.
• returnType − Method may return a value. The return types available are primitive return types
(byte, short, int, long, float, double, char, boolean), reference return types (String, Array, Object)
and special return type (void).
• nameOfMethod − This is the method name. The method signature consists of the method name
and the parameter list.
• Parameter List − The list of parameters, it is the type, order, and number of parameters of a
method. These are optional, method may contain zero parameters. Parameters are the variables
that are listed as part of a method's declaration. They act as placeholders for the values that will
be passed into the method when it is called while arguments are the actual values that are
passed to the method when it is invoked. These values are matched with the method’s
parameters in the order they are listed. Parameters are defined within the parentheses following
the method name.
• method body − The method body defines what the method does with the statements.

Methods that are already defined in the Java class libraries is known as predefined methods. It is also
known as the standard library method or built-in method. We can directly use these methods just by
calling them in the program at any point. Some pre-defined methods are length(), equals(), compareTo(),
sqrt(), etc. The method written by the user or programmer is known as a user-defined method. These
methods are modified according to the requirement.

OBJECT

An object is a variable of the type class. A class has the methods and data members (attributes), these
methods and data members are accessed through an object. Objects are created from classes at
runtime, so, an object is the instance (result – a single occurrence of an object at runtime) of a class, and
we create and initialize them with constructors. An object is a real-word entity that has state and
behavior. An object can be a tangible thing that can be touched and felt, like a car or chair, etc. while the
banking system is an example of an intangible object. Every object has a distinct identity, which is usually
implemented by a unique ID that the JVM uses internally for identification. A reference is a variable that
holds the memory address of an object.

Characteristics of an Object:

o State: It represents the data (value) of an object.


o Behavior: It represents the behavior (functionality) of an object such as deposit, withdraw, etc.
o Identity: An object's identity is typically implemented via a unique ID. The ID's value is not visible
to the external user; however, it is used internally by the JVM to identify each object uniquely.

The new keyword is used to create new objects. There are three steps when creating an object from a
class –

o Declaration − A variable declaration with a variable name with an object type.


o Instantiation − The 'new' keyword is used to create the object.
o Initialization − The 'new' keyword is followed by a call to a constructor. This call initializes the
new object.

ENCAPSULATION

Encapsulation in Java is a mechanism of wrapping the data (variables) and code acting on the data
(methods) together as a single unit. The purpose of encapsulation is to make sure that "sensitive" data is
hidden from users, in encapsulation, the variables of a class will be hidden from other classes, and can
be accessed only through the methods of their current class. Therefore, it is also known as data hiding.
Another way to think about encapsulation is, that it is a protective shield that prevents the data from
being accessed by the code outside this shield.

In Java, encapsulation is implemented by declaring instance variables as private, restricting direct access.
Public getter methods retrieve variable values, while setter methods modify them, enabling controlled
access. This approach allows the class to enforce data validation and maintain a consistent internal state,
enhancing security and flexibility.

Advantages of Encapsulation

o Better control of class attributes and methods


o Class attributes can be made read-only (if you only use the get method), or write-only (if you
only use the set method)
o Flexible: the programmer can change one part of the code without affecting other parts
o Increased security of data

Disadvantages of Encapsulation

o Can lead to increased complexity, especially if not used properly.


o Can make it more difficult to understand how the system works.
o This may limit the flexibility of the implementation.

INHERITANCE

Inheritance is a process where one class acquires the properties (methods and attributes) of another.
Inheritance is an important of concept of Java OOPs. The primary purpose of inheritance is to enable
code reuse and establish a natural hierarchy between classes.

The class which inherits the properties of other is known as subclass (derived class, child class) and the
class whose properties are inherited is known as superclass (base class, parent class).

What a subclass inherits from its superclass

o Subclass doesn’t automatically acquire all aspects of its superclass. Instead, it selectively inherits
non-private members from the superclass i.e. public, default, and protected members get
passed to the subclass while private members remain confined within the superclass and aren’t
accessible to the subclass.
o Constructors and initializers, both static and instance are not members within a class. Hence,
they do not undergo the inheritance process in java.
o Static members are inherited by subclass.
o When a class member is marked private, its accessibility is restricted solely to the class in which
it is declared. This means that private class members are not passed down to subclasses and
remain exclusive.
o If a class member is declared public, it is accessible from any part of the program, given that the
class itself is accessible. In the context of inheritance, a subclass inherits all public members of
its superclass.
o A class member with the package level/default is inherited exclusively when both the superclass
and subclass reside within the same package. In cases where the superclass and subclass belong
to different packages, the subclass does not inherit package-level members from its superclass.
o When a class member is marked as protected, it is consistently accessible within the body of a
subclass, regardless of whether the subclass is in the same package as the superclass or in a
different package.

The “extends” keyword is used for inheritance in Java. Using the extends keyword indicates you are
inheriting from an existing class.
“super” keyword - The super keyword is primarily used in the context of inheritance to access members
(fields and methods) of the parent class and to call the parent class constructor.

“this” and “super” keyword

“this” and “super” are two keywords used to refer to the current object and its superclass.

this Super
Often used to access instance variables and Refers to the superclass of the current object
methods of the current object
“this” can be used without the concept of “super” needs inheritance i.e. there is superclass
inheritance and there is subclass

Types of Inheritance in Java


o Single Inheritance - In single inheritance, a sub-class is derived from only one super class. It
inherits the properties and behavior of a single-parent class. Sometimes, it is also known as
simple inheritance.

o Multilevel Inheritance - Multilevel Inheritance involves a subclass that extends from a superclass
and subsequently serves as a subclass for another class.

o Hierarchical Inheritance - In Hierarchical Inheritance, one class serves as a superclass (base class)
for more than one subclass.
o Multiple Inheritance - In Multiple inheritances, one class can have more than one superclass and
inherit features from all parent classes. Java does not support multiple inheritances with classes,
but we can achieve multiple inheritances only through Interfaces.

o Hybrid Inheritance - Hybrid Inheritance is a combination of two or more of the previously


discussed types of inheritance. Hybrid inheritance involving multiple inheritance is also not
possible with classes. We can achieve hybrid inheritance only through Interfaces. However, it is
important to note that Hybrid inheritance does not necessarily require the use of Multiple
Inheritance exclusively. It can be achieved through a combination of Multilevel Inheritance and
Hierarchical Inheritance with classes, Hierarchical and Single Inheritance with classes.
POLYMORPHISM

In practice, inheritance, and polymorphism are used together in Java to achieve fast performance and
readability of code. Poly means many and morphos means forms, together they form polymorphism.
Polymorphism allows us to perform a single action in different ways. With polymorphism, the same
entity (method or object) can perform different operations in different scenarios.

Types of Polymorphism

Based on the type of binding (the decision-making process that establishes the connection between the
code and the specific method or field i.e. static binding and dynamic binding), there are two types if
polymorphism in Java:

• Static/Compile-Time Polymorphism (Method Overloading) - This type of polymorphism is


achieved by method overloading. When there are multiple methods with the same name but
different parameters then these methods are said to be overloaded. Methods can be overloaded
by changes in the number of arguments or/and a change in the type of arguments.
• Dynamic/Runtime Polymorphism (Method Override) - This type of polymorphism occurs when a
derived class has a definition for one of the member functions of the base class. That base
function is said to be overridden. When intending to override a method within a derived class
from the base class, it is advisable to use the @Override annotation (Annotations are used to
convey information to the compiler, runtime or other tools that process the program.
Annotations in java are a form of metadata that provides information about a programs code.
Annotations are defined using the @ Symbol followed by an annotation type).

ABSTRACTION

Abstraction is a concept that focuses on hiding the complex implementation details and showing only
the essential features of an object to the user. In other words, the user will have the information on what
the object does instead of how it does it. In Java programming, abstraction is achieved using Abstract
classes and interfaces.
Java Abstract Classes

The “abstract” keyword is used in the declaration of abstract classes and methods.

Rules and guidelines around an abstract class.

• Java abstract classes may or may not contain abstract methods, i.e., methods without body
(public void get(); )
• If a class has at least one abstract method, then the class must be declared abstract.
• If a class is declared abstract, it cannot be instantiated i.e. cannot create an object of an abstract
class.
• To use an abstract class, you have to inherit it from another class, provide implementations to
the abstract methods in it.
• If you inherit an abstract class, you have to provide implementations to all the abstract methods
in it.
• You cannot define an abstract method as private.
• You cannot define abstract method as a static method.
• You cannot mark abstract class as “final”.
• Do not create private constructors inside abstract class.
INTERFACE
Another way to achieve abstraction in Java, is with interfaces. An interface in Java is a blueprint
of a behavior. An Interface defines a contract that a class must following order to implement a
certain set of behaviors. An Interface is defined as an abstract type used to specify the behavior
of a class. An interface is a reference type and is similar to the class. An interface is a collection
of abstract methods, along with abstract methods, an interface may also contain constants,
default methods, static methods, and nested types. Method bodies exist only for default
methods and static methods.
To create an interface, we use the “interface” keyword followed by the interface name.

Interfaces cannot be instantiated; they can only be implemented by classes (i.e. class
implements interface) or extended by other interfaces (i.e. interface extends interface).

Rules and guidelines around Interfaces


• An Interface declaration is considered abstract by default, regardless of whether it is
explicitly marked with the “abstract” keyword.
• Classes and interfaces differ significantly. Classes can contain instance fields while
interfaces cannot, furthermore, while you can create an object by instantiating a class,
you cannot do so with an interface.
• The body of an interface may consist of abstract, default, private and static methods.
• The signature of the interface method and the same return type or subtype should be
maintained when overriding the methods.
• An implementation class itself can be abstract and if so, interface methods need not be
implemented.
• A class can implement more than one interface at a time.
• A class can extend only one class, but implement many interfaces.
• An interface can extend another interface, in a similar way as a class can extend another
class.

PACKAGES

A package is a collection of related classes, interfaces, annotations and enums grouped together in a
single unit. A package provides access protection and name space management.

Use of Packages
• Packages Prevent naming conflicts by allowing classes with the same name to exist in different
packages, like college.staff.cse.Employee and college.staff.ee.Employee.
• They make it easier to organize, locate, and use classes, interfaces, and other components.
• Packages also provide controlled access for Protected members that are accessible within the
same package and by subclasses.
• Packages are also used for default members (no access specifier) that are accessible only within
the same package.

Types of Java Packages

• Built-in Packages - These packages consist of a large number of prewritten free to use classes
which are a part of the Java API. Some of the commonly used built-in packages are:
o java.lang: Contains language support classes(e.g. classes which defines primitive data types,
math operations). This package is automatically imported.
o java.io: Contains classes for supporting input / output operations.
o java.util: Contains utility classes which implement data structures like Linked List, Dictionary and
support ; for Date / Time operations.
o java.applet: Contains classes for creating Applets.
o java.awt: Contain classes for implementing the components for graphical user interfaces (like
button, menus etc.).
o java.net: Contain classes for supporting networking operations.

The complete list can be found at Oracles website: https://docs.oracle.com/javase/8/docs/api/.

• User-defined Packages - These are the packages that are defined by the user.

In Java, you can import classes from a package either by:

• Importing a specific class

• Importing all classes from a package

INTERMEDIATE TO ADVANCED JAVA: MASTERING ADVANCED CONCEPTS AND PATTERNS

ARRAYS IN JAVA

An array is a container object that store multiple values in a single variable (a single, contiguous block of
memory). Instead of declaring separate variables for each value, an array store element of the same data
type as a collection. The elements can be of any data type including primitive types (such as float, int,
double, boolean, char) or objects. The length of an array is established when the array is created. After
creation, its length is fixed i.e., we can store only a fixed set of elements in a Java array. Array in Java is
index-based, the first element of the array is stored at the 0th index, 2nd element is stored on 1st index
and so on.
In a situation where the size of the array and variables of the array are already known, array literals can
be used. To create an array literal, declare the array by defining the variable type with square brackets
and assign the values in a comma-separated list, inside curly braces:

An array can also be created by using the “new” keyword. This method creates the array with an
allocated memory which determines the number of elements in the array. For example:

This statement initializes the numbers array to hold 5 integers.

To find out how many elements an array has, use the length() method. The array elements are accessed
through the index. Array indices are 0-based; that is, they start from 0 to arrayRefVar.length() - 1.

You can access and change an array element by referring to the index number.

When processing array elements, we use either for loop or foreach loop to access the elements because
all of the elements in an array are of the same type and the size of the array is known.
Iterating an array with for loop

Iterating an array with for each loop


The Arrays class in the java.util package contains various static methods for sorting and searching arrays,
comparing arrays, and filling array elements. These methods are overloaded for all primitive types.

The complete list can be found at Oracles website:


https://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html

Types of Arrays in Java

• Single-Dimensional Arrays - A single-dimensional array is a linear collection of elements of the


same data type.

• Multi-Dimensional Arrays - A multidimensional array is an array of arrays where each element


can be an array itself. It is useful in matrices or for storing data in row and column format.

• Jagged Arrays - a jagged array is an array of arrays where each row of the array can have a
different number of columns. This contrasts with a regular two-dimensional array, where each
row has the same number of columns.
Advantages of an Array

• It makes the code optimized, allowing retrieval or sorting of data to be more efficient.
• We can get any data located at an index position.

Disadvantage of an Array

• Arrays have a fixed size and do not grow dynamically at runtime.

EXCEPTION HANDLING

What Is an Exception in Java?

An exception is a problem that arises during the execution of a program. When an Exception occurs the
normal flow of the program is disrupted and the program/Application terminates abnormally, therefore,
these exceptions are to be handled.

An exception can occur for many different reasons, such as:

o A user has entered an invalid data.


o A file that needs to be opened cannot be found.
o A network connection has been lost in the middle of communications or the JVM has run out of
memory.

Some of these exceptions are caused by user error, others by programmer error, and others by physical
resources that have failed in some manner.

Without handling this exception, an otherwise healthy program may stop running altogether and
generate an error message. The technical term for this is: Java will throw an exception (throw an error).

Exception hierarchy
All exception classes are subtypes of the java.lang.Exception class. The exception class is a subclass of the
Throwable class. Other than the exception class there is another subclass called Error which is derived
from the Throwable class. Based on these, we have the following categories of Exceptions:

• Checked/Compile-time exceptions - A checked exception is an exception that is checked


(notified) by the compiler at compilation-time. Checked exceptions are exceptions that the Java
compiler requires us to handle by having to either declaratively throw the exception up the call
stack, or handling it ourselves. Checked exceptions are either caught or declared in the method
signature using the “throws” keyword.
• Unchecked/Runtime exceptions - An unchecked exception is an exception that occurs at the time
of execution (Runtime). These include programming bugs, such as logic errors or improper use
of an API. Runtime exceptions are ignored at the time of compilation. Unchecked exceptions are
not required to be caught or declared in the method signature.
• Errors – Errors are not exceptions at all and even though they don’t extend RuntimeException,
they are also unchecked. Errors represent serious and usually irrecoverable conditions like a
library incompatibility, infinite recursion, or memory leaks. Errors problems that arise beyond
the control of the user or the programmer. Errors are typically ignored in your code because you
can rarely do anything about an error.

The following is a list of some Java Unchecked and Checked Exception

S/No Exception & Description


1 ArithmeticException:
Arithmetic error, such as divide-by-zero.
2 ArrayIndexOutOfBoundsException:
Array index is out-of-bounds.
3 ArrayStoreException:
Assignment to an array element of an incompatible
type.
4 ClassCastException:
Invalid cast.
5 IllegalArgumentException
Illegal argument used to invoke a method.
6 IllegalMonitorStateException
Illegal monitor operation, such as waiting on an
unlocked thread.
7 IllegalStateException
Environment or application is in incorrect state.
8 IllegalThreadStateException
Requested operation not compatible with the current
thread state.
9 IndexOutOfBoundsException
Some type of index is out-of-bounds.
10 NegativeArraySizeException
Array created with a negative size.
11 NullPointerException
Invalid use of a null reference.
12 NumberFormatException
Invalid conversion of a string to a numeric format.
13 SecurityException
Attempt to violate security.
14 StringIndexOutOfBounds
Attempt to index outside the bounds of a string.
15 UnsupportedOperationException
An unsupported operation was encountered.
16 ClassNotFoundException
Class not found.
17 CloneNotSupportedException
Attempt to clone an object that does not implement
the Cloneable interface.
18 IllegalAccessException
Access to a class is denied
19 InstantiationException
Attempt to create an object of an abstract class or
interface.
20 InterruptedException
One thread has been interrupted by another thread.
21 NoSuchFieldException
A requested field does not exist.
22 NoSuchMethodException
A requested method does not exist.

The Throwable class has some important methods, they are:

S/No Method & Description


1 public String getMessage()
Returns a detailed message about the
exception that has occurred. This message is
initialized in the Throwable constructor.
2 public Throwable getCause()
Returns the cause of the exception as
represented by a Throwable object
3 public String toString()
Returns the name of the class concatenated
with the result of getMessage().
4 public void printStackTrace()
Prints the result of toString() along with the
stack trace to System.err, the error output
stream.
5 public StackTraceElement [] getStackTrace()
Returns an array containing each element on
the stack trace. The element at index 0
represents the top of the call stack, and the
last element in the array represents the
method at the bottom of the call stack
6 public Throwable fillInStackTrace()
Fills the stack trace of this Throwable object
with the current stack trace, adding to any
previous information in the stack trace.

Handling Exceptions in Java (Catching Exceptions)

• Try/Catch Block

A method catches an exception using a combination of the try and catch keywords, the code within a
try/catch block is referred to as protected code. The code which is prone to exceptions is placed in the
try block. Every try block should be immediately followed either by a catch block or finally block. When
an exception occurs, that exception occurred is handled by catch block associated with it. A catch
statement involves declaring the type of exception you are trying to catch. If an exception occurs in
protected code, the catch block (or blocks) that follows the try is checked. If the type of exception that
occurred is listed in a catch block, the exception is passed to the catch block much as an argument is
passed into a method parameter. The syntax for using try/catch looks like the following:

A try block can be followed by multiple catch blocks. The syntax for multiple catch blocks looks like the
following

Instead of using multiple catch blocks, you can also handle more than one exception using a single catch
block, this feature simplifies the code. The syntax is as thus:
• The Finally Block

The finally block follows a try block or a catch block. A finally block of code always executes, irrespective
of occurrence of an Exception. A finally block appears at the end of the catch blocks and has the
following syntax:

Rules of the try-catch-finally block

o A catch clause cannot exist without a try statement.


o It is not compulsory to have finally clauses whenever a try/catch block is present.
o The try block cannot be present without either catch clause or finally clause.
o Any code cannot be present in between the try, catch, finally blocks.

• try-with-resources

Try-with-resources allows the declaration of resources to be used in a try block with the assurance that
the resources will be closed after the execution of that block. To use this statement, you simply need to
declare the required resources within the parenthesis, and the created resource will be closed
automatically at the end of the block.
• The Throws/Throw Keywords

The throws keyword in Java is used in method declarations to specify that a method can throw one or
more exceptions. It indicates to the caller of the method that they must handle these exceptions, either
by catching them or by declaring them in their own throws clause.

The throw keyword in Java is used to explicitly throw an exception. It is typically used within a method or
a block of code to indicate that an exceptional condition has occurred, and the execution of the code
should stop at that point. The throw keyword can be used with both built-in exceptions and custom
exceptions.
Differences between throw and throws:

Throw Throws
Used to throw an exception for a method Used to indicate what exception type may
be thrown by a method
Cannot throw multiple exceptions Can declare multiple exceptions

• Custom Exceptions

You can create your own custom exceptions by extending the subclasses of Throwable (Exception or
RuntimeException). If you want to write a checked exception that is automatically enforced by the
Handle or Declare Rule, you need to extend the Exception class. If you want to write a runtime
exception, you need to extend the RuntimeException class.
WRAPPER CLASSES

Wrapper classes provide a way to use primitive data types as objects. When working with numbers, most
of the time you use the primitive types in your code. There are, however, reasons to use objects in place
of primitives, and the Java platform provides wrapper classes for each of the primitive data types. These
classes "wrap" the primitive in an object. Often, the wrapping is done by the compiler—if you use a
primitive where an object is expected, the compiler boxes the primitive in its wrapper class for you.
Similarly, if you use a number object when a primitive is expected, the compiler unboxes the object for
you.

o Boxing: Converting a primitive type into a corresponding wrapper class object.


o Unboxing: Converting a wrapper class object back into a corresponding primitive type.
o Autoboxing: Automatic conversion of primitive types to corresponding wrapper class objects
by the compiler.
o Autounboxing: Automatic conversion of wrapper class objects to corresponding primitive
types by the compiler.

Each primitive type has a corresponding wrapper class:

o byte -> Byte


o short -> Short
o int -> Integer
o long -> Long
o float -> Float
o double -> Double
o char -> Character
o boolean -> Boolean

Each Wrapper class contains other methods that are useful for converting numbers to and from strings
and for converting between number systems. The following table lists these methods in the Integer class.
Methods for the other Wrapper classes are similar:

Method Description
static Integer decode(String s) Decodes a string into an integer. Can accept string
representations of decimal, octal, or hexadecimal numbers
as input.
static int parseInt(String s) Returns an integer (decimal only).
static int parseInt(String s, int radix) Returns an integer, given a string representation of
decimal, binary, octal, or hexadecimal (radix equals 10, 2,
8, or 16 respectively) numbers as input.
String toString() Returns a String object representing the value of this
Integer.
static String toString(int i) Returns a String object representing the specified integer.
static Integer valueOf(int i) Returns an Integer object holding the value of the
specified primitive.
static Integer valueOf(String s) Returns an Integer object holding the value of the
specified string representation.
static Integer valueOf(String s, int radix) Returns an Integer object holding the integer value of the
specified string representation, parsed with the value of
radix. For example, if s = "333" and radix = 8, the method
returns the base-ten integer equivalent of the octal
number 333.

There are three reasons that you might use a Number object rather than a primitive:

o As an argument of a method that expects an object (often used when manipulating collections
of numbers such as ArrayList, Maps, Vector etc.).
o To use constants defined by the class, such as MIN_VALUE and MAX_VALUE, that provide the
upper and lower bounds of the data type.
o To use class methods for converting values to and from other primitive types, for converting to
and from strings, and for converting between number systems (decimal, octal, hexadecimal,
binary).

Wrapper classes are essential in Java for converting primitive types to objects, enabling their use in
collections, and providing utility methods for type conversion and parsing.

GENERICS IN JAVA

generics enable types (objects, classes and interfaces) to be parameters when defining classes, interfaces
and methods. Generics let you create one blueprint that can work with different types of data. Instead of
writing separate code for handling numbers, text, or custom data types, you can write it once and specify
which type you want to use when you actually use it. It's like having a single container design that can be
used to store any type of item, but you decide what type of item it will store when you create the
container.

Types of Java Generics

• Generic Classes: A generic class is implemented exactly like a non-generic class. The only
difference is that it contains a type parameter section. There can be more than one type of
parameter, separated by a comma. The classes, which accept one or more parameters, ?are
known as parameterized classes or parameterized types. we use <> to specify parameter types in
generic class creation, we can also pass multiple Type parameters in Generic classes. In
Parameter type we cannot use primitives like ‘int’, ’char’ or ‘double’.
• Generic Method: Generic Java method takes a parameter and returns some value after
performing a task. It is exactly like a normal method, however, a generic method has type
parameters that are cited by actual type. This allows the generic method to be used in a more
general way. The compiler takes care of the type of safety which enables programmers to code
easily since they do not have to perform long, individual type castings.
When we declare an instance of a generic type, the type argument passed to the type parameter must
be a reference type. We cannot use primitive data types like int, char. In these scenarios, we use wrapper
classes like Integer and Character instead.

To create objects of a generic class, we use the following syntax.

Type Parameters in Java Generics: The type parameters naming conventions are important to learn
generics thoroughly. The common type parameters are as follows:

o T – Type
o E – Element
o K – Key
o N – Number
o V – Value
Advantages of Generics

o Code Reusability: You can write a method, class, or interface once and use it with any type.
o Type Safety: Generics ensure that errors are detected at compile time rather than runtime,
promoting safer code.
o No Need for Type Casting: The compiler automatically handles casting, removing the need
for explicit type casting when retrieving data.
o Code Readability and Maintenance: By specifying types, code becomes easier to read and
maintain.
o Generic Algorithms: Generics allow for the implementation of algorithms that work across
various types, promoting efficient coding practices.

Disadvantages of Generics

o Complexity: For beginners, understanding concepts like wildcards (? extends, ? super) can be
difficult.
o Performance Overhead: Type erasure causes some overhead as generic types are converted to
Object during runtime.
o No Support for Primitive Types: Generics only work with reference types, requiring the use of
wrapper classes like Integer or Double for primitives.
o Limited Reflection: Type erasure limits how much you can use reflection with generics since type
information is not available at runtime.

JAVA COLLECTIONS FRAMEWORKS

Collections in Java are data structures that group multiple objects into a single unit. They enable you to
store, retrieve, manipulate, and aggregate data efficiently.

A framework is a set of classes and interfaces which provide a ready-made architecture. A framework is
an ecosystem of libraries, classes or interfaces which will help in solving problems.

A collections framework is a unified architecture for representing and manipulating collections.

The primary advantages of a collections framework are that it:

o Reduces programming effort by providing data structures and algorithms so you don't have to
write them yourself.
o Increases performance by providing high-performance implementations of data structures and
algorithms. Because the various implementations of each interface are interchangeable,
programs can be tuned by switching implementations.
o Provides interoperability between unrelated APIs by establishing a common language to pass
collections back and forth.
o Reduces the effort required to learn APIs by requiring you to learn multiple ad hoc collection
APIs.
o Reduces the effort required to design and implement APIs by not requiring you to produce ad
hoc collections APIs.
o Fosters software reuse by providing a standard interface for collections and algorithms with
which to manipulate them.
The collection interfaces are divided into two groups:

The most basic interface, java.util.Collection, has the following descendants:

o java.util.Set
o java.util.SortedSet
o java.util.NavigableSet
o java.util.Queue
o java.util.concurrent.BlockingQueue
o java.util.concurrent.TransferQueue
o java.util.Deque
o java.util.concurrent.BlockingDeque

The other collection interfaces are based on java.util.Map and are not true collections. However, these
interfaces contain collection-view operations, which enable them to be manipulated as collections:

o java.util.SortedMap
o java.util.NavigableMap
o java.util.concurrent.ConcurrentMap
o java.util.concurrent.ConcurrentNavigableMap

Iterable - This is the root interface for the entire collection framework. The collection interface extends
the iterable interface. Therefore, inherently, all the interfaces and classes implement this interface. The
main functionality of this interface is to provide an iterator for the collections.
Collection - This interface extends the iterable interface and is implemented by all the classes in the
collection framework. This interface contains all the basic methods which every collection has All these
methods are implemented in this interface because these methods are implemented by all the classes
irrespective of their style of implementation. And also, having these methods in this interface ensures
that the names of the methods are universal for all the collections. Therefore, in short, we can say that
this interface builds a foundation on which the collection classes are implemented.

Methods of the Collection Interface are:

Methods Description
add(Object) This method is used to add an object to the collection.
addAll(Collection c) This method adds all the elements in the given
collection to this collection.
clear() This method removes all of the elements from this
collection.
contains(Object o) This method returns true if the collection contains the
specified element.
containsAll(Collection c) This method returns true if the collection contains all of
the elements in the given collection.
equals(Object o) This method compares the specified object with this
collection for equality.
hashCode() This method is used to return the hash code value for
this collection.
isEmpty() This method returns true if this collection contains no
elements.
iterator() This method returns an iterator over the elements in
this collection.
max() This method is used to return the maximum value
present in the collection.
parallelStream() This method returns a parallel Stream with this
collection as its source.
remove(Object o) This method is used to remove the given object from
the collection. If there are duplicate values, then this
method removes the first occurrence of the object.
removeAll(Collection c) This method is used to remove all the objects
mentioned in the given collection from the collection.
removeIf(Predicate filter) This method is used to remove all the elements of this
collection that satisfy the given predicate.
retainAll(Collection c) This method is used to retain only the elements in this
collection that are contained in the specified collection.
size() This method is used to return the number of elements
in the collection.
spliterator() This method is used to create a Spliterator over the
elements in this collection.
stream() This method is used to return a sequential Stream with
this collection as its source.
toArray() This method is used to return an array containing all of
the elements in this collection.

List - This is a child interface of the collection interface. This interface is dedicated to the data of the list
type in which we can store all the ordered collections of the objects. This also allows duplicate data to be
present in it. Since all the subclasses implement the list, we can instantiate a list object with any of these
classes.

The classes which implement the List interface are as follows:

o ArrayList - ArrayList provides us with dynamic arrays in Java. The size of an ArrayList is increased
automatically if the collection grows or shrinks if the objects are removed from the collection.
Java ArrayList allows us to randomly access the list. ArrayList cannot be used for primitive types,
like int, char, etc. We will need a wrapper class for such cases. Do not use ArrayList in scenarios
of addition and removal operations of elements, for this, always use a LinkedList.
If the operation is doing a lot of Random Access operations to read an element or replace an
element then use ArrayList.
o LinkedList - The LinkedList is a linear data structure where the elements are not stored in
contiguous locations and every element is a separate object with a data part and address part.
The elements are linked using pointers and addresses. Each element is known as a node.
LinkedList can also contain duplicate elements and maintains insertion order. LinkedList is very
useful in scenarios where you need to perform frequent insertions and deletions of elements in
a list as it does not require the same amount of memory allocation or reallocation as an array-
based list.

Set - A set is an unordered collection of objects in which duplicate values cannot be stored. This
collection is used when we wish to avoid the duplication of the objects and wish to store only the unique
objects meaning no element can be repeated within the set. Set is typically used when you want to store
a collection of items but you only need to keep track of unique items and you don’t care about the order
in which they were added. Since all the subclasses implement the set, we can instantiate a set object
with any of these classes.
The following are the classes that implement the Set interface:

o HashSet - The HashSet class is an inherent implementation of the hash table data structure. The
objects that we insert into the HashSet do not guarantee to be inserted in the same order. The
objects are inserted based on their hashcode. This class also allows the insertion of NULL
elements.

o LinkedHashSet - LinkedHashSet combines the features of a hashset and a Linked list. A


LinkedHashSet is very similar to a HashSet. The difference is that this uses a doubly linked list to
store the data and retains the ordering of the elements. LinkeHashSet maintains the order of
elements based on their insertion. When you iterate over the entries of a LinkedHashSet, they
are returned in the order in which they were added.

o TreeSet – TreeSet implements the Sorted Set interface and is based on the Tree Map
implementation using a red-black tree data structure to maintain the Sorted order of elements.
The treeset is used to handle the data which needs to be sorted i.e. TreeSet stores elements in a
sorted and ascending order.
Map – A map is part of the Collections frameworks but it does not extend the collection interface. A map
is an abstract data type that provides a way to store, retrieve and manipulate data based on keys. The
map interface is implemented by several but HashMap, LinkedHashMap, TreeMap are the most
commonly used map implementations. Map is a parameterized type with two type variables i.e. Map<K,
V> where type variable K represents the type of keys and type variable V represents the type of values
the keys are mapped to. Since all the subclasses implement the map, we can instantiate a map object
with any of these classes.

Methods of Java Map

Methods Description
Put(Object key, Object Value) This method inserts an entry in the map
putAll(Map map) This method inserts the specified map in this map
remove(Object key) It is used to delete an entry for the specified keys
KeySet() It returns the set view containing all the keys
entrySet() It returns the Set view containing all the keys and values
clear() It is used to reset the map
putIfAbsent(K key, V value) It inserts the specified value with the specified key in the map
only if it is not already specified
get(Object key) It returns the value for the specified key
containKey(Object key) It is used to search the specified key from this map

The following are the classes that implement the Map interface:

o HashMap - HashMap provides the basic implementation of the Map interface of Java. It stores
the data in (Key, Value) pairs, to access a value in a HashMap, we must know its key. HashMap
uses a technique called Hashing. Hashing is a technique of converting a large String to a small
String that represents the same String so that the indexing and search operations are faster. It
implements all of the Map operations and allows null values and one null key. Also, this class
does not maintain any order among its elements.

o LinkedHashMap - As the name indicates this implementation of the Java Map interface uses a
hash table and a linked list as the underlying data structures. Thus, the order of a
LinkedHashMap is with insertion-order.
o TreeMap – TreeMap is a red-black tree-based implementation and stores the key-value pairs in a
sorted order based on the keys. This means that when we insert key-value pairs to a TreeMap,
they are automatically sorted by their keys and not their values.
FUNCTIONAL PROGRAMMING IN JAVA

Java introduced functional programming features with the release of Java 8. Functional programming is a
programming paradigm that focuses on using functions to transform data. It emphasizes writing small,
reusable, and pure functions that avoid changing state or mutating data, resulting in more predictable
and maintainable code. In Java, functional programming is supported by features like lambda
expressions, the Stream API, and functional interfaces, these features enable a more declarative and
concise style of coding. Lambda expression facilitates functional programming and simplifies
development a lot. A lambda expression works on the principle of functional interface.

• Functional interface - A Functional interface is an interface with only one abstract method to
implement. They can have multiple default or static methods. A lambda expression provides an
implementation of the functional interface method. Functional interfaces can be represented
using lambda expressions, method references, or constructor references.
• Lambda expression - A lambda expression is a short block of code which takes in parameters and
returns a value. Lambda expressions is an anonymous method that has mutability at very
minimum and it has only a parameter list and a body. A lambda expression can infer the type of
parameter used and can return a value without a return keyword. In the case of the simple one-
statement method, even curly braces can be eliminated. A lambda expression is characterized by
the following syntax:
Java provides several built-in functional interfaces in the java.util.function package, such as
Predicate, Consumer, Function, Supplier, and BiFunction.

Functional programming features was introduced with the Stream API. The Stream API, introduced in
Java 8, is a powerful feature designed to process sequences of elements in a declarative and
functional programming style. By utilizing the Stream API, you can work with data in a more readable
and maintainable way, leveraging parallel processing capabilities to enhance performance.

What Are Streams?

Streams can be defined as a sequence of elements from a source which support data processing
operations. Streams can be regarded as operations performed on data. Streams doesn’t store the
data. You can’t add or remove elements from streams. Hence, they are not the data structures. They
are the just operations on data. A stream takes in a source, executes operations on it, and generates
a result. The source could be a collection, an array, or an I/O resource.

Pipeline of Operations in Streams

When we work with streams, we set up a pipeline of operations in different stages as mentioned
below:
• Create a Stream using. We can create streams from collections(stream() method), we can
also create a stream of single element of type T and create a stream of values(Stream.of()
method).
• One or more intermediate operations for transforming the initial stream into others or
filtering.
• Applying a terminal operation to produce a result.
o intermediate operations - operations which return stream themselves
o terminal operations - operations which return other than stream. These operations are
always mandatory to derive an output and we can only invoke a single terminal output.

java.util.stream.Stream interface is the center of Java 8 Streams API. This interface contains all the
stream operations. Below table shows frequently used Stream methods with description.
THREADS AND MULTI-THREADING IN JAVA

A thread is the smallest unit of execution within a process. A thread is a lightweight process, each thread
has its own stack, program counter, and local variables but shares the memory space and resources of
the process.

Multithreading is the ability to run multiple threads concurrently. Multithreading enables concurrent
execution of two or more parts of a program for maximum resource utilization and performance. It helps
in performing multiple tasks simultaneously, making programs faster and more efficient. Multi-threading
extends the idea of multitasking into applications where you can subdivide specific operations within a
single application into individual threads. Each of the threads can run in parallel. The OS divides
processing time not only among different applications, but also among each thread within an
application.

To achieve the multithreading (or, write multithreaded code), you need java.lang.Thread class. Threads
can be created by using two mechanisms :

o Extending the Thread class - We create a class that extends the java.lang.Thread class. This class
overrides the run() method available in the Thread class. A thread begins its life inside run()
method. We create an object of our new class and call start() method to start the execution of a
thread. Start() invokes the run() method on the Thread object.
o Implementing the Runnable Interface - We create a new class which implements
java.lang.Runnable interface and override run() method. Then we instantiate a Thread object
and call start() method on this object.

Thread Class vs Runnable Interface

o If we extend the Thread class, our class cannot extend any other class because Java doesn’t
support multiple inheritance. But, if we implement the Runnable interface, our class can still
extend other base classes.
o We can achieve basic functionality of a thread by extending Thread class because it provides
some inbuilt methods like yield(), interrupt() etc. that are not available in Runnable interface.
o Using runnable will give you an object that can be shared amongst multiple threads.

Embarking on the journey to master Java has been a transformative experience, blending technical
learning with personal growth. As I reflect on my journey with Java, I am filled with gratitude for the
challenges and triumphs that have shaped my understanding of programming. From its foundational
principles to its advanced concepts, Java has proven to be a powerful tool for crafting innovative
solutions and understanding the art of programming. This document represents not just a compilation of
knowledge but a milestone in my evolution as a developer. While this marks the end of this document,
the learning never truly ends, it is merely the beginning of a lifelong pursuit of learning, innovation, and
mastery in the ever-evolving world of technology. Java have equipped me with the confidence to tackle
new challenges and continue exploring the endless possibilities of technology.

You might also like