Java
Java
and C++
Nowadays Java and C++ programming languages are
vastly used in competitive coding. Due to some
awesome features, these two programming languages
are widely used in industries as well as comepetitive
programming. C++ is a widely popular language
among coders for its efficiency, high speed, and
dynamic memory utilization. Java is widely used in the
IT industry's , It is incomparable to any other
programming language in terms of software
development. Let us go through the various points to
compare these popular coding languages:
Similarities between Java and C++
1. Execution: At compile-time, Java source code
or .java file is converted into bytecode or .class file. At
runtime, JVM (Java Virtual Machine) will load
the .class file and will convert it to machine code with
the help of an interpreter. After compilation of method
calls (using the Just-In-Time (JIT) compiler), JVM will
execute the optimized code. So Java is both compiled
as well as an interpreted language. On the other hand,
C++ executes the code by using only a compiler. The
C++ compiler compiles and converts the source code
into the machine code. That's why C++ is faster than
Java but not platform-independent.
Below is the illustration of how Java and C++ codes are
executed:
The execution of a Java code is as follows:
Execution of a C++ Code
2. Features: C++ and Java both have several Object
Oriented programming features which provide many
useful programming functionalities. Some features are
supported by one and some by the other. Even though
both languages use the concept of OOPs, neither can
be termed 100% object-oriented languages. Java uses
primitive data types and thus cannot be termed as
100% Object-Oriented Language. C++ uses some data
types similar to primitive ones and can implement
methods without using any data type. And thus, it is
also deprived of the 100% Object-Oriented title.
Below is the table which shows the features supported
and not supported by both the programming
languages:
C+ Jav
Features + a
Pointers Yes No
C+ Jav
Features + a
Interference and
No Yes
Packages
API No Yes
Syntax Difference:
Syntax of c++:
1
#include <iostream>
2
using namespace std;
3
4
int main() {
5
6
cout << "GFG!";
7
return 0;
8
}
syntax of java
1
/*package whatever //do not write package name here
*/
2
3
import java.io.*;
4
5
class GFG {
6
public static void main (String[] args) {
7
System.out.println("GFG!");
8
}
9
}
Applications: Both C++ and Java have vast areas of
application. Below are the applications of both
languages:
Applications of C++ Programming language:
Sl.
No Parameter
. s Java C++
C++ was
developed by
Java was
Bjarne
developed by
Stroustrup at
1. Founder James Gosling
Bell Labs in 1979
at Sun
as an extension
Microsystems.
of the C
language.
Sl.
No Parameter
. s Java C++
Official
4. oracle.com/java isocpp.org
Website
C++ was
Java was Influenced by
Influenced by Influenced by
Influenced
5. Ada 83, Pascal, Ada, ALGOL 68,
By:
C++, C#, etc. C, ML, Simula,
languages. Smalltalk, etc.
languages.
languages. languages.
Platform- Platform
independent, dependent,
Platform
Java bytecode should be
7. Dependenc
works on any compiled for
y
operating different
system. platforms.
C++ is platform-
It can run on
dependent.
8. Portability any OS hence it
Hence it is not
is portable.
portable.
Java is both
C++ is a
Compiled and
9. Compilation Compiled
Interpreted
Language.
Language.
Memory
Memory Memory
1 Management is
Managemen Management in
0. System
t C++ is Manual.
Controlled.
Keyword. keywords.
It supports only
single
inheritance. It supports both
1 Multiple Multiple single and
2. Inheritance inheritances are multiple
achieved Inheritance.
partially using
interfaces.
It supports only
method It supports both
1 overloading and method and
Overloading
3. doesn't allow operator
operator overloading.
overloading.
It supports It doesn’t
Documentat documentation support
1
ion comments (e.g., documentation
7.
Comment /**.. */) for comments for
source code. source code.
C++ doesn’t
have built-in
Java provides support for
1 Thread built-in support threads,
8. Support for depends on
multithreading. third-party
threading
libraries.
an object-
programming oriented
language. programming
language.
Java doesn't
2 goto C++ supports
support goto
1. Keyword goto keyword.
Keyword
Java doesn't
C++ supports
2 Structures support
Structures and
2. and Unions Structures and
Unions.
Unions.
All classes in
Java are
subclasses of A fresh
2 Inheritance the Object inheritance tree
4. Tree class, hence is always
Java only ever created in C++.
follows a single
inheritance tree.
It supports both
2 Global It supports no global scope and
5. Scope global scope. namespace
scope.
Automatic It supports
Object object manual object
2
Managemen management management
6.
t with garbage using new and
collection. delete.
interactive with
8. hardware.
hardware.
Game engines,
Machine
Internet and
learning,
Android games,
Operating
Mobile
systems, Google
applications,
Search Engine,
Healthcare and
Web browsers,
2 Language research
Virtual Reality
9. Used for computation,
(VR), Game
Cloud
development,
applications,
Medical
Internet of
technology,
Things (IoT)
Telecommunicati
devices, etc.
ons, Databases,
etc.
Mozilla Firefox,
Wikipedia,
Amazon, Apple
LinkedIn,
3 Application OS, Spotify,
Android OS,
0. built Adobe
Uber, and
Photoshop, and
Minecraft,
YouTube.
Differences Between JDK, JRE and JVM
Understanding the difference between JDK, JRE, and
JVM plays a very important role in understanding
how Java works and how each component contributes to the
development and execution of Java applications. The main
difference between JDK, JRE, and JVM is:
JDK: Java Development Kit is a software development
environment used for developing Java applications and
applets.
JRE: JRE stands for Java Runtime Environment, and it
provides an environment to run only the Java program
onto the system.
JVM: JVM stands for Java Virtual Machine and is
responsible for executing the Java program.
JDK vs JRE vs JVM
JVM is OS-
Platform- Platform- specific, but
Platform dependent dependent bytecode is
Dependenc (OS specific) (OS specific) platform-
y independent
debugger,
(e.g., rt.jar) Collector
etc.)
Running a Convert
Writing and
Java bytecode into
compiling Java
application on native
code
Use Case a system machine code
Working of JDK
The JDK enables the development and execution of Java
programs. Consider the following process:
Java Source File (e.g., Example.java): You write the
Java program in a source file.
Compilation: The source file is compiled by the Java
Compiler (part of JDK) into bytecode, which is stored in
a .class file (e.g., Example.class).
Execution: The bytecode is executed by the JVM (Java
Virtual Machine), which interprets the bytecode and runs
the Java program.
Note: From above, media operation computing during the
compile time can be interpreted.
What is a Framework?
A framework is a set of classes and interfaces which provide a
ready-made architecture. In order to implement a new feature
or a class, there is no need to define a framework itself.
However, an optimal object-oriented design often includes a
framework with a collection of classes such that all the classes
perform the same kind of task.
Need for a Separate Collection Framework
Before Collection Framework (or before JDK 1.2) was
introduced, the standard methods for grouping Java objects (or
collections) were Arrays or Vectors, or Hashtables. All of
these collections had no common interface. Therefore, though
the main aim of all the collections is the same, the
implementation of all these collections was defined
independently and had no correlation among them. And also, it
is very difficult for the users to remember all the
different methods, syntax, and constructors present in every
collection class.
Are you confused between Collection, Collection
Interface, Collections Class, Collection Framework?
Collection: A group of individual objects that represent a
single entity is known as a collection. It is the common
word that you used in your daily life. But if we are
discussing Java programming language then it will become
Java Collection Framework.
Collection Framework: To represent a group of objects
as a single entity in the Java programming language we
need classes and interfaces defined by the Collection
Framework. If are from C++ background that you can
compare Collection with Containers and Collection
Framework with STL(Standard Template Library).
Collection Interface: Interfaces specify what a class
must do and not how. It is the blueprint of the class. It is
the root interface of the Collection Framework that defines
the most common methods that can be used for any
collection objects. Or you can say it represents the
individual object as a single entity.
Collections Class: It is present in java.util package and
is a member of Collection Framework. This class provides
many utility methods for the collection object.
Now you must be wondering why to include such a concept or
what difficulties were faced before java version 1.2 that lead
birth to the concept of Collection. In order to figure it out, the
three main advantages are mentioned below:
1. Reduces the programming effort as the programmer does
not have to worry about designing the Collection class and
on the same hand java being object-oriented language
advances in achieving abstraction by not writing the
Collection class.
2. Increases program speed and quality as the programmer
now is not worried about thinking best implementation for
a specific data structure as of now for a programmer
scope widens up and at the same time is now only worried
about the best implementation that can drastically boost
the performance of program irrespective of data structure
constraints encountered earlier.
3. The API that implements these interfaces are now having
common sets of methods be it of any interfaces such as
Collection, Set, List, and Map.
Note: All these collections can be imported using:
import java.util.*;
However, single classes can also be imported by replacing *
with the class name as shown
import java.util.ArrayList;
import java.util.LinkedList;
The following figure illustrates the hierarchy of the collection
framework.
Deque Interface
Deque or double-ended queue is a data structure where we can
add and remove the elements from both ends of the queue.
This interface extends the queue interface. The class which
implements this interface namely are LinkedList and
ArrayDeque, and Collection class. Here in the Collection class, it
has implementation of basic algorithms like binary search,
sort(), max(), min(), reverse(), fill(), etc. These algorithms are
implemented on the above-mentioned collection frameworks.
ArrayDeque class in Java provides a way to apply resizable-
array in addition to the implementation of the Deque interface.
It is also known as Array Double Ended Queue(Array Deck). This
is a special kind of array that grows and allows users to add or
remove an element from both sides of the queue.
BlockingDeque interface gets its name because it blocks
illegal operations such as insertion into a full queue or deletion
from an empty queue, all of these properties are inbuilt into the
structure of this interface. Since it is a deque (double-ended
queue) that is the insertion, deletion, and traversal operations
can be performed from both ends. The BlockingDeque is an
interface, so we cannot declare any objects with it.
ConcurrentLinkedDeque class implements the Collection
interface and the AbstractCollection class. It belongs
to java.util.concurrent package. It is used to implement Deque
with the help of LinkedList concurrently. It does not permit null
elements and iterators and spliterators are weakly consistent.
Now basic knowledge about the collection to write some basic
programs invoking the interfaces with the help of object in the
collection is over. It's time a move a bit deeper down so here a
new concept is popularly known as Generics comes into play to
jump into. Writing codes with little knowledge is dangerous.
The idea is to allow type (Integer, String, … etc, and user-
defined types) to be a parameter to methods, classes, and
interfaces. For example, classes like HashSet, Array List,
HashMap, etc use generics very well. The generic classes can
only be used for non-primitive types and wrapper classes. Here
are the major advantages of Generics in Java:
1. Write once for any primitive data type as in any generic
function code can be written down for computation over
non-primitive and later on during compilation these data
types are passed in a generic function.
2. It can be class like Array List, LinkedList, Stack, Vector, etc.
It can be an interface like Set, Map, etc as discussed
above, or it can include functions like sort(), max(), min(),
etc. Hence, they are extensively used in Collection.
3. They are type-safe as they commit errors at compile time.
Unlike arrays, different instantiations of a generic type is not
compatible with each other, not even explicitly. This
incompatibility may be softened by the wildcard if? is used as
an actual type parameter.
The question mark (?) is known as the wildcard in generic
programming. It represents an unknown type. The wildcard can
be used in a variety of situations such as the type of parameter,
field, or local variable; sometimes as a return type.
User cases
Example 1: A simple java program to demonstrate the
compile-time errors without the involvement of generics
into play. Here 'ClassCastException' is thrown by the
program
// Class 1
// Object class
class GenericClass {
// Class 2
// Main class
class GFG {
// Min driver method
public static void main(String[] args)
{
// Creating a generic class object
// Here 'go' is name of object
GenericClass go = new GenericClass();
// Compiles fine because
// p being an object accepts integer
go.x = 007;
T x;
S y;
}
// Class 2
// Main class
class GFG {
Iterator ();
Now, dwelling onto different methods present in Collection such
as add(), removes (), remove All(), contains(), contains All(),
stream() and many more. In order to use so, one has to
get a clear understanding of the same. Let's peek out for
various functions causing bulk operations namely
1. contains All () Method
2. add All () Method
3. remove All () Method
4. retain All () Method
// Method 1 - containsAll()
// Java Program to illustrate
// containsAll() method
// Class
class GfG {
// Method 2 - addAll()
// Java program to illustrate
// boolean addAll(Collection c)
// Class
class GFG {
// Method 3 - reomoveAll()
// Java program to demonstrate
// removeAll() method
import java.util.*;
// Class
public class GFG {
// Class
public class GFG {
Now lets us discuss all the methods been proposed for iteration
are as follows:
1. Iterators Method
2. For-each loop Method
3. forEach() Method
4. Streams Method
There are various ways of traversing through a collection
namely:
Method 1: Iterators Method
The Iterable interface provides an iterator() method which
implements the Iterator interface. The iterator interface
provides 3 functions(hasNext(), next(), remove()) which are
used to iterate through the collection and also remove
elements from the collection. 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.
Therefore, this interface contains only one abstract method
which is the iterator.
// Method 1
// Traversing a collection
// using for-each loop
import java.util.*;
// Main class
class GFG {
// Method 2
// Traverssing a collection
// using forEach() method
// Class
class GFG {
// Main driver method
public static void main(String[] args)
{
// Traversing a collection
// using forEach() method
l.forEach(x -> System.out.println(x));
}
}
// Method 3
// Traversing a collection
// using stream() method
// Class
class GFG {
// Main driver method
public static void main(String[] args)
{
// Traversing a collection
// using stream method
// to print elements with a space
l.stream().forEach(x -> System.out.print(x + " "));
// New line
System.out.println();
// initializing array
int[] arr = { 1, 2, 3, 4, 5 };
// size of array
int n = arr.length;
// traversing array
for (int i = 0; i < n; i++)
System.out.print(arr[i] + " ");
}
}
Basics of Arrays in Java
There are some basic operations we can start with as
mentioned below:
1. Array Declaration
To declare an array in Java, use the following syntax:
type[] arrayName;
type: The data type of the array elements
(e.g., int, String).
arrayName: The name of the array.
Note: The array is not yet initialized.
2. Create an Array
To create an array, you need to allocate memory for it using
the new keyword:
// Creating an array of 5 integers
int[] numbers = new int[5];
This statement initializes the numbers array to hold 5 integers.
The default value for each element is 0.
3. Access an Element of an Array
We can access array elements using their index, which starts
from 0:
// Setting the first element of the array
numbers[0] = 10;
// Accessing the first element
int firstElement = numbers[0];
The first line sets the value of the first element to 10. The
second line retrieves the value of the first element.
4. Change an Array Element
To change an element, assign a new value to a specific index:
// Changing the first element to 20
numbers[0] = 20;
5. Array Length
We can get the length of an array using the length property:
// Getting the length of the array
int length = numbers.length;
Now, we have completed with basic operations so let us go
through the in-depth concepts of Java Arrays, through the
diagrams, examples, and explanations.
In-Depth Concepts of Java Array
Following are some important points about Java arrays.
Array Properties
In Java, all arrays are dynamically allocated.
Arrays may be stored in contiguous
memory [consecutive memory locations].
Since arrays are objects in Java, we can find their length
using the object property length. This is different from
C/C++, where we find length using size of.
A Java array variable can also be declared like other
variables with [] after the data type.
The variables in the array are ordered, and each has an
index beginning with 0.
Java array can also be used as a static field, a local
variable, or a method parameter.
An array can contain primitives (int, char, etc.) and object (or
non-primitive) references of a class, depending on the definition
of the array. In the case of primitive data types, the actual
values might be stored in contiguous memory locations (JVM
does not guarantee this behavior). In the case of class
objects, the actual objects are stored in a heap segment.
Note: This storage of arrays helps us randomly access the
elements of an array [Support Random Access].
Creating, Initializing, and Accessing an Arrays in Java
For understanding the array we need to understand how it
actually works. To understand this follow the flow mentioned
below:
Declare
Initialize
Access
1. Declaring an Array
The general form of array declaration is
Method 1:
type var-name[];
Method 2:
type[] var-name;
The element type determines the data type of each element
that comprises the array. Like an array of integers, we can also
create an array of other primitive data types like char, float,
double, etc., or user-defined data types (objects of a class).
Note: It is just how we can create is an array variable, no
actual array exists. It merely tells the compiler that this
variable (int Array) will hold an array of the integer type.
Now, let us provide memory storage to this created array.
2. Initialization an Array in Java
When an array is declared, only a reference of an array is
created. The general form of new as it applies to one-
dimensional arrays appears as follows:
var-name = new type [size];
Here, type specifies the type of data being
allocated, size determines the number of elements in the array,
and var-name is the name of the array variable that is linked to
the array. To use new to allocate an array, you must specify
the type and number of elements to allocate.
Example:
// declaring array
int intArray[];
// allocating memory to array
intArray = new int[20];
// combining both statements in one
int[] intArray = new int[20];
Note: The elements in the array allocated by new will
automatically be initialized to zero (for numeric
types), false (for boolean), or null (for reference types). Do
refer to default array values in Java.
Obtaining an array is a two-step process. First, you must
declare a variable of the desired array type. Second, you must
allocate the memory to hold the array, using new, and assign it
to the array variable. Thus, in Java, all arrays are
dynamically allocated.
Class GFG {
public static void main (String[] args)
{
// declares an Array of integers.
int[] arr;
2. Multi-Dimensional Arrays
Arrays with more than one dimension, such as two-dimensional
arrays (matrices).
// A 2D array (matrix)
int[][] multiDimArray = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9} };
You can also access java arrays using for each loops.
class Student {
public int roll_no;
public String name;
class Student{
public String name;
Student(String name){
this.name = name;
}
@Override
public String toString(){
return name;
}
}
System.out.println(
"Trying to access element outside the size of array");
System.out.println(arr[5]);
}
}
Output:-
Trying to access element outside the size of array
Exception in thread "main"
java.lang.ArrayIndexOutOfBoundsException: Index 5 out of
bounds for length 4
at GFG.main(GFG.java:13)
class GFG {
public static void main(String[] args){
// Number of Columns
System.out.println("Columns : " + arr[0].length);
}
}
Output:-
Rows:3
Columns:3
// Driver Class
public class multiDimensional {
// main function
public static void main(String args[])
{
// declaring and initializing 2D array
int arr[][] = { { 2, 7, 9 }, { 3, 6, 1 }, { 7, 4, 2 } };
// printing 2D array
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++)
System.out.print(arr[i][j] + " ");
System.out.println();
}
}
}
Output:-
279
361
742
Passing Arrays to Methods: -
Like variables, we can also pass arrays to methods. For
example, the below program passes the array to
method sum to calculate the sum of the array's values.
Output
sum of array values: 15
class Test {
// Driver method
public static void main(String args[])
{
int arr[] = m1();
class Test {
public static void main(String args[])
{
int intArray[] = { 1, 2, 3 };
class Test {
public static void main(String args[])
{
int intArray[][] = { { 1, 2, 3 }, { 4, 5 } };
int cloneArray[][] = intArray.clone();
Common Operations
The below table demonstrates the common array operations
Operati
on Example
Sort Arrays.sort(arr);
Arrays.binarySearch(arr,
Search key);
Arrays.copyOf(arr, len);
Best Practices
The best practices when working with arrays in Java are listed
below:
Use For-Each Loop When Possible (Avoids Index
Errors): The for-each loop is a best way to iterate over
arrays elements without worrying about index-out-of-
bounds errors. It reduces the risk of accessing invalid
indices.
Check Array Length Before Accessing
Elements: Always check the length of the array
using array.length before attempting to access an
element. This helps prevent
ArrayIndexOutOfBoundsException.
Use Arrays.copyOf() Instead of Manual Copying: If
you need to copy an array, use Arrays.copyOf() rather
than manually copying each element with a loop.
Prefer ArrayList if Dynamic Resizing is Needed: If
you require a collection that can dynamically resize (add
or remove elements), consider using ArrayList instead of
an array.
// Driver Class
class Geeks {
// Constructor
Geeks()
{
super();
System.out.println("Constructor Called");
}
// main function
public static void main(String[] args)
{
Geeks geek = new Geeks();
}
}
Output
Constructor Called
Constructors
Methods can
must have the
have any
same name as
valid name
Name the class name
Methods
have the
Constructors return type
do not return or void if
any type does not
return any
Return Type value.
Constructors
are called Methods are
automatically called
with new explicitly
Invocation keyword
class Geek
{
......
// A Constructor
Geek() {
}
.......
}
// We can create an object of the above class
// using the below statement. This statement
// calls above constructor.
Geek obj = new Geek();
or instance creation.
Default Constructor
Parameterized Constructor
Copy Constructor
// Driver class
class Geeks{
// Default Constructor
Geeks() {
System.out.println("Default constructor");
// Driver function
public static void main(String[] args)
{
Geeks hello = new Geeks();
}
}
Output: - Default constructor
(Note: Default constructor provides the default values
to the object like 0, null, false etc. depending on the
type.)
class Geeks {
class GFG
{
public static void main(String[] args)
{
// This would invoke the parameterized constructor
Geeks geek1 = new Geeks("Sweta", 68);
System.out.println("GeekName: " + geek1.name
+ " and GeekId: " + geek1.id);
}
}
Output
GeekName: Sweta and GeekId: 68
class Geeks {
// Parameterized Constructor
Geeks(String name, int id)
{
this.name = name;
this.id = id;
}
// Copy Constructor
Geeks(Geeks obj2)
{
this.name = obj2.name;
this.id = obj2.id;
}
}
class GFG {
public static void main(String[] args)
{
// This would invoke the parameterized constructor
System.out.println("First Object");
Geeks geek1 = new Geeks("Sweta", 68);
System.out.println("GeekName: " + geek1.name
+ " and GeekId: " + geek1.id);
System.out.println();
Constructor Overloading
This is a key concept in OOPs related to constructors
is constructor overloading. This allows us to create
multiple constructors in the same class with different
parameter lists.
Example: This example, demonstrates constructor
overloading, where multiple constructors perform the
same task (initializing an object) with different types or
numbers of arguments.
// Java Program to illustrate constructor overloading
// using same task (addition operation) for different
// types of arguments
import java.io.*;
class Geeks {
System.out.println(
"Constructor with two arguments: "
+ " String and Integer: " + name + " " + age);
}
class GFG {
public static void main(String[] args)
{
// Creating the objects of the class named 'Geek'
// by passing different arguments
class GFG {
final GFG() {}
public static void main(String[] args)
{
System.out.println("GFG!");
}
}
Output: -
(./GFG.java:2: error: modifier final not allowed here
final GFG() {})
1 error
This snippet of code results in a compile-time error.
4. A constructor can invoke another constructor of
the same class
By using this() as the first statement in a constructor we
can call another constructor of the same class. If we want to
invoke a parameterized constructor, we can pass a
parameter list as an argument: this(parameter list). super()
is used to invoke the constructor of the superclass. JVM
implicitly declares the first statement as super() for the no-
argument constructor, and this() for the default constructor.
Saves time as too many operations are carried over at the same
time causing work to get finished as if threads are not used the only
one process will be handled by the processor.
So, we have touched all main concepts of multithreading but the question
striving in the head is left. why do we need it, where to use it and how?
Now, we will discuss all three scenarios why multithreading is needed and
where it is implemented via the help of programs in which we will be
further learning more about threads and their methods. We need
multithreading in four scenarios as listed.
Thread Class
Mobile applications
o Asynchronous thread
Web applications
Game Development
Note: By default, we only have one main thread which is responsible for
main thread exception as you have encountered even without having any
prior knowledge of multithreading
setDaemon
It set the current thread as Daemon thread
()
// Case 1
// Java Program to illustrate Creation and execution of
// thread via start() and run() method in Single inheritance
// Class 1
System.out.println("Thread1 is running");
// Class 2
// started
System.out.println("Thread2 is running");
// Class 3
// Main Class
class GFG {
// Main method
// it
obj1.start();
// execute it
obj2.start();
// Case 2
// Java Program to illustrate Difference between Runnable
// & Non-runnable Threads And Single Inheritance
// Class 1
// started
System.out.println("Thread 1 is running");
// Class 2
// Method
System.out.println("Thread 2");
// Class 3
// Main Class
class GFG {
// Main method
// it
obj1.start();
// This thread will now look for run() method which is absent
obj2.start();
// Class 1
// started
System.out.println("Thread 1 is running");
// Class 2
// Method
System.out.println("Thread 2");
// Class 3
// Main Class
class GFG {
// Main method
// it
obj1.start();
obj2.show();
Output:
Case 1:
Thread1 is running
Thread2 is running
Here we have created our two thread classes for each thread. In the main
method , we are simply creating objects of these thread classes where
objects are now threads. So in main , we call thread using start() method
over both the threads. Now start() method starts the thread and lookup for
their run() method to run. Here both of our thread classes were having
run() methods, so both threads are put to run state from runnable by the
scheduler, and output on the console is justified.
Case 2:
Thread 1 is running
Here we have created our two thread classes for each thread. In the main
method, we are simply creating objects of these thread classes where
objects are now threads. So in main, we call thread using start() method
over both the threads. Now start() method starts the thread and lookup
their run() method to run. Here only class 1 is having the run() method to
make the thread transcend from runnable to run state to execute whereas
thread 2 is only created but not put to run state by the scheduler as its
corresponding run() method was missing. Hence, only thread 1 is called
rest thread 2 is created only and is in the runnable state later blocked by
scheduler because the corresponding run() method was missing.
Case 3:
Thread 2
Thread 1 is running
import java.io.*;
import java.util.*;
// Class 1
System.out.println("Thread1");
try {
Thread.sleep(1000);
catch (Exception e) {
}
// Class 2
System.out.println("Thread2");
try {
// time
Thread.sleep(1000);
// Class 3
// Main class
// Thread class
t1.start();
t2.start();
}
Output
Thread2
Thread1
Thread2
Thread1
Thread2
Thread1
Thread2
Thread1
Thread2
Thread1
Points to remember: Whenever you wanted to create
threads, there are only two ways:
1. Extending the class
2. Implementing the interface which is runnable
Make sure to create an object of threads in which you have to
pass the object of runnable.
// Example 1
// Java Program to illustrate Output Without sleep() Method
// Class 1
// Helper Class 1
class Shot extends Thread {
// Method 1
public void show() {
}
}
}
// Class 2
// Helper Class 2
class Miss extends Thread {
// Method 2
public void show() {
}
}
}
// Class 3
// Main class
public class GFG {
// Method 3
// Main method
public static void main(String[] args) {
}
}
[Output:
Case 1:
Shot
Shot
Shot
Shot
Shot
Miss
Miss
Miss
Miss
Miss]
// Example 2
// Java Program to illustrate Output Using sleep() Method
// in Serial Execution
// Class 1
// Helper Class 1
class Shot extends Thread {
// Method 1
// public void show() {
public void show()
{
// Print statement
System.out.println("Shot");
// Class 2
// Helper Class 2 Hello
class Miss extends Thread {
// Method 2
// public void show() {
public void show()
{
// Print statement
System.out.println("Miss");
// Class 3
// Main class
public class GFG {
// Method 3
// Main method
public static void main(String[] args)
{
// Example 3
// Java Program to illustrate Output Using sleep() Method
// in Parallel Execution
// Class 1
// Helper Class 1
class Shot extends Thread {
// Method 1
// public void show() {
public void run()
{
// Print statement
System.out.println("Shot");
// Class 2
// Helper Class 2 Hello
class Miss extends Thread {
// Method 2
// public void show() {
public void run()
{
// Print statement
System.out.println("Miss");
// Class 3
// Main class
public class GFG {
// Method 3
// Main method
public static void main(String[] args)
{
[Case 3: output
Shot
Miss
Shot
Miss
Shot
Miss
Shot
Miss
Shot
Miss]
Daemon thread :-
Basically a service provider thread that provides services to the
user thread. The scope for this thread start() or be it
terminate() is completely dependent on the user's thread as it
supports in the backend for user threads being getting run. As
soon as the user thread is terminated daemon thread is also
terminated at the same time as being the service provider
thread.
Hence, the characteristics of the Daemon thread are as follows:
It is only the service provider thread not responsible for
interpretation in user threads.
So, it is a low-priority thread.
It is a dependent thread as it has no existence on its own.
JVM terminates the thread as soon as user threads are
terminated and come back into play as the user's thread
starts.
Yes, you guess the most popular example is garbage
collector in java. Some other examples do include
'finalizer'.
Exceptions: IllegalArgumentException as return type while
setting a Daemon thread is boolean so do apply carefully.
Note: To get rid of the exception users thread should only start
after setting it to daemon thread. The other way of starting
prior setting it to daemon will not work as it will pop-out
IllegalArgumentException
As discussed above in the Thread class two most widely used
method is as follows:
Daemon Thread
Methods Action Performed
import java.io.*;
// Importing Thread class from java.util package
import java.util.*;
// Class 1
// Helper Class extending Thread class
class CheckingMyDaemonThread extends Thread {
// Method
// run() method which is invoked as soon as
// thread start via start()
public void run()
{
else {
// Class 2
// Main Class
class GFG {
import java.io.*;
// Basically we are importing Thread class
// from java.util package
import java.util.*;
// Class 1
// Helper Class extending Thread class
class CheckingMyDaemonThread extends Thread {
// Method
// run() method which is invoked as soon as
// thread start via start()
public void run()
{
else {
// Class 2
// Main Class
class GFG {
// Method
// Main driver method
public static void main(String[] args)
{
Note:
While implementing ThreadGroup do note that ThreadGroup is
a part of ' java.lang.ThreadGroup' class not a part of Thread
class in java so do peek out constructors and methods of
ThreadGroup class before moving ahead keeping a check over
deprecated methods in his class so as not to face any
ambiguity further.
Here main() method in itself is a thread because of which you
do see Exception in main() while running the program because
of which system.main thread exception is thrown
sometimes while execution of the program.
Synchronization
It is the mechanism that bounds the access of multiple threads
to share a common resource hence is suggested to be useful
where only one thread at a time is granted the access to run
over.
It is implemented in the program by using ' synchronized '
keyword.
Now let's finally discuss some advantages and disadvantages of
synchronization before implementing the same. For more depth
in synchronization, one can also learn object level
lock and class level lock and do notice the differences between
two to get a fair understanding of the same before
implementing the same.
Why Synchronization is Required?
1. Data inconsistency issues are the primary issue where
multiple threads are accessing the common memory
which sometimes results in faults in order to avoid that a
thread is overlooked by another thread if it fails out.
2. Data integrity
3. To work with a common shared resource which is very
essential in the real world such as in banking systems.
Note: Do not go for synchronized keyword unless it is most
needed, remember this as there is no priority setup for threads,
so if the main thread runs before or after other thread the
output of the program would be different.
The biggest advantage of synchronization is the increase in
idiotic resistance as one cannot choose arbitrarily an object to
lock on as a result string literal cannot be locked or be the
content. Hence, these bad practices are not possible to perform
on synchronized method block.
As we have seen humongous advantages and get to know how
important it is but there comes disadvantage with it.
Disadvantage: Performance issues will arise as during the
execution of one thread all the other threads are put to a
blocking state and do note they are not in waiting state . This
causes a performance drop if the time taken for one thread is
too long.
multi-tasking
As perceived from the image in which we are getting that count
variable being shared resource is updating randomly. It is
because of multithreading for which this concept becomes a
necessity.
Case 1: If ' main thread' executes first then count will be
incremented followed by a ' thread T' in synchronization
Case 2: If ' thread T ' executes first then count will not
increment followed by ' main thread ' in synchronization
// Class 1
// Helper Class extending Thread class
class MyThread extends Thread {
// Method 1
// To increment the count above by unity
void increment() { count++; }
// Method 2
// run method for thread invoked after
// created thread has started
public void run()
{
// Class 2
public class GFG {
Here the count is incremented to 1 meaning ' main thread ' has
executed prior to ' created thread '. We have run it many times
and compiled and run once again wherein all cases here main
thread is executing faster than created thread but do
remember output may vary. Our created thread can execute
prior to ' main thread ' leading to 'Count : 0' as an output on
the console.
Now another topic that arises in dealing with synchronization in
threads is Thread safety in java synchronization is the new
concept that arises out in synchronization so let us discuss it
considering
A real-life scenario followed by
Pictorial representation as an illustration followed by
Technically description and implementation
Real-life Scenario
Suppose a person is withdrawing some amount of money from
the bank and at the same time the ATM card registered with
the same account number is carrying on withdrawal operation
by some other user. Now suppose if withdrawing some amount
of money from net banking makes funds in account lesser than
the amount which needed to be withdrawal or the other way.
This makes the bank unsafe as more funds are debited from
the account than was actually present in the account making
the bank very unsafe and is not seen in daily life. So what
banks do is that they only let one transaction at a time. Once it
is over then another is permitted.
Illustration:
Example 1
// Java Program to illustrate Incomplete Thread Iterations
// Returning Counter Value to Zero
// irrespective of iteration bound
// Class 1
// Helper Class
class TickTock {
// Member variable of this class
int count;
// Class 2
// Synchronization demo class
// Main Class
class GFG {
// Expression
for (int i = 0; i < 10000; i++) {
// Example 2
// Java Program to Illustrate Complete Thread Iterations
// illustrating join() Method
// Class 1
// Helper Class
class TickTock {
// Class 2
// Synchronization demo class
// Main Class
class GFG {
// Expression
for (int i = 0; i < 1000; i++) {
// Calling object of above class
// in main() method
tt.increment();
}
}
});
// Class 1
// Helper Class
class TickTock {
// Class 2
// Synchronization demo class
// Main Class
class GFG {
// Expression
for (int i = 0; i < 100000; i++) {
// Expression
for (int i = 0; i < 100000; i++) {
Output: -
Case 3
Count: 151138
// Example 4
// Java Program to Illustrate Thread Safe And
// Synchronized Programs as of Complete Iterations
// using 'synchronized' Keyword
// Class 1
// helper Class
class TickTock {
// Member variable of this class
int count;
// Class 2
// Synchronization demo class
// Main Class
class GFG {
// Expression
for (int i = 0; i < 100000; i++) {
// Thread 2
Thread t2 = new Thread(new Runnable() {
// Method
// To begin the execution of thread
public void run()
{
// Expression
for (int i = 0; i < 100000; i++) {
Synchronization in Java:-
In multithreading, synchronization is important to make sure
multiple threads safely work on shared resources. Without
synchronization, data can become inconsistent or corrupted if
multiple threads access and modify shared variables at the
same time. In Java, it is a mechanism that ensures that only
one thread can access a resource at any given time. This
process helps prevent issues such as data inconsistency
and race conditions when multiple threads interact with shared
resources.
Example: Below is a Java Program to demonstrate
synchronization.
// Java Program to demonstrate synchronization in Java
class Counter {
private int c = 0; // Shared variable
Output
Counter: 2000
[Explanation: Two threads, t1 and t2, increment the shared
counter variable concurrently. The inc() and get() methods are
synchronized, meaning only one thread can execute these
methods at a time, preventing race conditions. The program
ensures that the final value of the counter is consistent and
correctly updated by both threads.]
[Need of Synchronization:
When multiple threads share resources, synchronization make
sure that only one thread accesses the resource at a time. This
prevents problem like data getting mixed up or broken because
of multiple threads changing it together.]
class Counter {
private int c = 0; // Shared variable
Output
Counter: 2000
Types of Synchronization
There are two types of synchronizations in Java which are listed
below:
Process Synchronization
Thread Synchronization
1. Process Synchronization in Java
Process Synchronization is a technique used to coordinate the
execution of multiple processes. It ensures that the shared
resources are safe and in order.
// Main class
public class Geeks {
public static void main(String[] args)
{
BankAccount account
= new BankAccount(); // Shared resource
Output
Withdrawn: 100, Balance: 900
Deposited: 200, Balance: 1100
Deposited: 200, Balance: 1300
Withdrawn: 100, Balance: 1200
Deposited: 200, Balance: 1400
Withdrawn: 100, Balance: 1300
Final Balance: 1300
Mutual Exclusion:-
Mutual Exclusion helps keep threads from interfering with one
another while sharing data. There are three types of Mutual
Exclusive mentioned below:
Synchronized method.
Synchronized block.
Static synchronization.
Example: Below is the implementation of the Java
Synchronization.
// A Java program to demonstrate working of synchronized.
import java.io.*;
// A Class used to send a message
class Sender {
public void send(String msg)
{
System.out.println("Sending " + msg); // Changed to print
without new line
try {
Thread.sleep(100);
}
catch (Exception e) {
System.out.println("Thread interrupted.");
}
System.out.println(msg + "Sent"); // Improved output
format
}
}
// Driver class
class Geeks {
public static void main(String args[])
{
Sender send = new Sender();
ThreadedSend S1 = new ThreadedSend("Hi ", send);
ThreadedSend S2 = new ThreadedSend("Bye ", send);
class Test {
synchronized void test_func(int n)
{
// synchronized method
for (int i = 1; i <= 3; i++) {
System.out.println(n + i);
try {
Thread.sleep(100);
}
catch (Exception e) {
System.out.println(e);
}
}
}
}
// Driver Class
public class Geeks {
// Main function
public static void main(String args[])
{
// only one object
final Test O = new Test();
a.start();
b.start();
}
}
Output
16
17
18
31
32
33
[Explanation: Here the Test class has a synchronized method
test_func() that prints a sequence of numbers with a slight
delay, ensuring thread safety when accessed by multiple
threads. Two threads are created using anonymous classes,
each calling the test_func() method with different values. The
synchronized keyword ensures that only one thread can
execute the method at a time.]
class Geeks
{
public static void main(String[] args)
{
// File name specified
File obj = new File("myfile.txt");
System.out.println("File Created!");
}
}
Output:
File Created!
Streams in Java
In Java, a sequence of data is known as a stream. This concept
is used to perform I/O operations on a file. Below are the types
of Streams:
1. Input Stream
The Java InputStream class is the superclass of all input
streams. The input stream is used to read data from numerous
input devices like the keyboard, network, etc. InputStream is an
abstract class, and because of this, it is not useful by itself.
However, its subclasses are used to read data.
There are several subclasses of the InputStream class, which
are as follows:
1. AudioInputStream
2. ByteArrayInputStream
3. FileInputStream
4. FilterInputStream
5. StringBufferInputStream
6. ObjectInputStream
Creating an InputStream:
// Creating an InputStream
InputStream obj = new FileInputStream();
Here, an input stream is created using FileInputStream.
Note: We can create an input stream from other subclasses as
well as InputStream.
Common Methods of InputStream:
Method Description
2. Output Stream
The output stream is used to write data to numerous output
devices like the monitor, file, etc. Output Stream is an abstract
superclass that represents an output stream. Output Stream is
an abstract class and because of this, it is not useful by itself.
However, its subclasses are used to write data.
There are several subclasses of the Output Stream class which
are as follows:
1. ByteArrayOutputStream
2. FileOutputStream
3. StringBufferOutputStream
4. ObjectOutputStream
5. DataOutputStream
6. PrintStream
Creating an OutputStream:
// Creating an OutputStream
OutputStream obj = new FileOutputStream();
Here, an output stream is created using FileOutputStream.
Note: We can create an output stream from other subclasses
as well as Output Stream.
Common Methods of Output Stream:
Method Description
1. Byte Stream
This stream is used to read or write byte data. The byte stream
is again subdivided into two types which are as follows:
Byte Input Stream: Used to read byte data from
different devices.
Byte Output Stream: Used to write byte data to
different devices.
2. Character Stream
This stream is used to read or write character data. Character
stream is again subdivided into 2 types which are as follows:
Character Input Stream: Used to read character data
from different devices.
Character Output Stream: Used to write character data
to different devices.
Owing to the fact that you know what a stream is, let's polish
up File Handling in Java by further understanding the various
methods that are useful for performing operations on the files
like creating, reading, and writing files.
Java File Class Methods
The following table depicts several File Class methods:
Return
Method Name Description Type
createNewFile
It creates an empty file. Boolean
()
File Operations
The following are the several operations that can be performed
on a file in Java:
Create a File
Read from a File
Write to a File
Delete a File
1. Create a File
In order to create a file in Java, you can use the
createNewFile() method.
If the file is successfully created, it will return a Boolean
value true and false if the file already exists.
// Creating File using Java Program
// Import the File class
import java.io.File;
import java.io.IOException;
// Creating File
if (Obj.createNewFile()) {
System.out.println("File created: " + Obj.getName());
}
else {
System.out.println("File already exists.");
}
}
// Exception Thrown
catch (IOException e) {
System.out.println("An error has occurred.");
e.printStackTrace();
}
}
}
Output:
2. Write to a File
We use the FileWriter class along with its write() method in
order to write some text to the file.
Example:
// Writing Files using Java Program
// Writing File
Writer.write("Files in Java are seriously good!!");
Writer.close();
System.out.println("Successfully written.");
}
// Exception Thrown
catch (IOException e) {
System.out.println("An error has occurred.");
e.printStackTrace();
}
}
}
Output
Reader.close();
}
// Exception Cases
catch (FileNotFoundException e) {
System.out.println("An error has occurred.");
e.printStackTrace();
}
}
}
Output
4. Delete a File
We use the delete() method in order to delete a file.
Example:
// Deleting File using Java Program
import java.io.File;
// Deleting File
if (Obj.delete()) {
System.out.println("The deleted file is : " +
Obj.getName());
}
else {
System.out.println(
"Failed in deleting the file.");
}
}
}
Output
Example:
// Using Method Reference
import java.util.Arrays;
public class Geeks
{
// Method
public static void print(String s) {
System.out.println(s);
}
Aspect Syntax
Refer to a method in an
Object :: methodName
object
list.forEach(s ->
Print all elements in a list
System.out.println(s));
class Person
{
private String name;
private Integer age;
// Constructor
public Person(String name, int age)
{
// This keyword refers to current instance itself
this.name = name;
this.age = age;
}
// Getter-setters
public Integer getAge() { return age; }
public String getName() { return name; }
}
// Driver class
public class Geeks
{
// Static method to compare with name
public static int compareByName(Person a, Person b) {
return a.getName().compareTo(b.getName());
}
Sort by Age :
Sachin
Vicky
Poonam
Explanation: This example shows how to use static method
references to sort items. We have a person class with attributes
like name and age and there are two methods to compare
people by name and by age. In the main method we created a
list of people and sorting them by name and then sort them by
age and then printing the name again.
2. Reference to an Instance Method of a Particular
Object
This type of method means using a method from a certain
object which we already have. We do not need to write another
function to call that particular method we can just simply refer
to it directly.
Syntax:
// Lambda expression
(args) -> obj.instanceMethod(args);
// Method reference
obj::instanceMethod;
class Person {
// Attributes of a person
private String name;
private Integer age;
// Constructor
public Person(String name, int age)
{
// This keyword refers to current object itself
this.name = name;
this.age = age;
}
// Getter-setter methods
public Integer getAge() { return age; }
public String getName() { return name; }
}
// Helper class
// Comparator class
class ComparisonProvider
{
// To compare with name
public int compareByName(Person a, Person b) {
return a.getName().compareTo(b.getName());
}
// Main class
public class Geeks
{
public static void main(String[] args)
{
// Creating an empty ArrayList of user-defined type
// List of person
List<Person> personList = new ArrayList<>();
// Using streams
personList.stream()
.map(x -> x.getName())
.forEach(System.out::println);
System.out.println();
personList.stream()
.map(x -> x.getName())
.forEach(System.out::println);
}
}
Output
Sort by Name :
Poonam
Sachin
Vicky
Sort by Age :
Sachin
Vicky
Poonam
Explanation: This example show how to use an instance
method reference to sort a list of people. We have created a
Person class with name and age and we also created a
ComparisonProvider class, it has methods to compare people
by name or age. In the main method we created a list of people
and we are using the ComparisonProvider instance to sort and
print the names first by name, then by age.
3. Reference to an Instance Method of an Arbitrary
Object of a Particular Type
It means calling a method on any object that belongs to a
certain group or class, not just one specific object. It helps us
write less code when we want to do the same thing for many
objects.
Syntax:
// Lambda expression
(obj, args) -> obj.instanceMethod(args);
// Method reference
ObjectType::instanceMethod;
Example: - Reference to an Instance Method of an
Arbitrary Object of a Particular Type
// Reference to an Instance Method of an
// Arbitrary Object of a Particular Type
import java.io.*;
import java.util.*;
Output
Poonam
Sachin
Vicky
Explanation: This example show how to use a method
reference to sort a list of names. We created a list of names and
then sorting them ignoring uppercase or lowercase with the
help of compareToIgnoreCase method of the String class and
then we are printing the sorted names
4. Constructor Method Reference
It lets us quickly create a new object without writing extra code.
It is a shortcut to call the class new method.
Syntax:
// Lambda expression
(args) -> new ClassName(args);
// Method reference
ClassName::new;
Example: - Constructor Method Reference
// Constructor
public Person()
{
Random ran = new Random();
Output
ilvxzcv
vdixqbs
lmcfzpj
dxnyqej
zeqejcn
Explanation: This example show how to use a constructor
method reference to create objects. We have created a Person
class and it gives each person a random name. The
getObjectList method creates a list of objects by using a
supplier, which means it uses the Person constructor to make
new Person objects. In the main method we created a list of
people and then we are printing their random names.
Common Use Cases
There are some common cases where we use Method
References in Java as mentioned below:
Iterating over collections: Simplifying operations like
printing or processing elements.
Stream API operations: Enhancing readability in
filtering, mapping, and reducing operations.
Custom utilities: Using predefined methods for
frequently used tasks like sorting and comparisons.