Unit2_Java
Unit2_Java
util
• The java.util package has classes that generate pseudorandom
numbers, manage date and time, observe events, manipulate sets of
bits, tokenize strings, and handle formatted data.
• Collections Framework is a sophisticated hierarchy of interfaces and
classes that provide advanced technology for managing groups of
objects.
• The Java Collections Framework standardizes the way in which groups
of objects are handled by your programs.
Advantages
• High-performance
• Inter-operability
• Extending the collection is easy
The Collection Interfaces
• The Collections Framework defines several core interfaces.
1. The Collection interface is the foundation upon which the
Collections Framework is built. Collection is a generic
interface that has this declaration:
interface Collection<E>
Here, E specifies the type of objects that the collection will hold.
Collection extends the Iterable interface. This means that all collections
can be cycled through by use of the for each style for loop.
Example: ArrayList<Integer>
s
Method Description
sp
lie
ta
add() ra
Add objects to collection.
to
sp ov
lit er
clear() er th
or el
ts
in
iterator() th
co
contains() lle
Returns true is a particular value is present
cti
spliterator()
on
retainAll() tai
el
2. The List interface extends Collection and declares the behavior of a collection that stores
a sequence of elements.
Elements can be inserted or accessed by their position in the list, using a zero-based index.
A list may contain duplicate elements. List is a generic interface that has this declaration:
interface List<E>
Here, E specifies the type of objects that the list will hold.
Example: List<String>
Methods
size() - Find the number of elements
add() - Add objects to collection.
get() - To obtain the object stored at a specific location
set() - To assign a value to an element in the list
indexOf() and lastIndexOf()- To find the index of an object
subList() - To obtain a sublist of a list
sort() - To sort a list
listIterator() - To traverse the list
3. The Set interface defines a set. It extends Collection and specifies the
behavior of a collection that does not allow duplicate elements.
Set is a generic interface that has this declaration:
interface Set<E>
Here, E specifies the type of objects that the set will hold.
Example: Set<String>
Set interface includes all the methods of the Collection interface.
5. The Deque interface extends Queue and declares the behavior of a double-ended
queue. Double-ended queues can function as standard, first-in, first-out queues or as
last-in, first out stacks. Deque is a generic interface that has this declaration:
interface Deque<E>
Here, E specifies the type of objects that the deque will hold.
Example: Deque<String>
Methods:
addFirst() - Adds the specified element at the beginning of the deque.
addLast() - Adds the specified element at the end of the deque.
offerFirst() - Adds the specified element at the beginning of the deque.
offerLast() - Adds the specified element at the end of the deque.
getFirst() - Returns the first element of the deque.
getLast() - Returns the last element of the deque.
peekFirst() - Returns the first element of the deque.
peekLast() - Returns the last element of the deque.
removeFirst() - Returns and removes the first element of the deque.
removeLast() - Returns and removes the last element of the deque.
pollFirst() - Returns and removes the first element of the deque.
pollLast() - Returns and removes the last element of the deque.
The Collection Classes
1. The ArrayList class extends AbstractList and implements the List
interface. ArrayList is a generic class that has this declaration:
class ArrayList<E>
Here, E specifies the type of objects that the list will hold.
• ArrayList supports dynamic arrays that can grow as needed. An ArrayList
is a variable-length array of object references. That is, an ArrayList can
dynamically increase or decrease in size.
• Array lists are created with an initial size. When this size is exceeded, the
collection is automatically enlarged. When objects are removed, the
array can be shrunk.
Constructors
ArrayList( ) - creates an empty array list.
ArrayList(Collection<? extends E> c) - creates an array list that is initialized
with the elements of the collection c
ArrayList(int capacity) - creates an array list that has the specified initial
capacity.
Examples:
ArrayList<String> al1 = new ArrayList<>();
ArrayList<String> al2 = new ArrayList<>(al1);
ArrayList<String> al3 = new ArrayList<>(20);
import java.util.*;
class ArrayListDemo {
public static void main(String args[]) {
// Create an array list.
ArrayList<String> al = new ArrayList<String>();
System.out.println("Initial size of al: " + al.size());
// Add elements to the array list.
al.add("C");
al.add("A");
al.add("E");
al.add("B");
al.add("D");
al.add("F");
al.add(1, "A2");
System.out.println("Size of al after additions: " + al.size());
// Display the array list.
System.out.println("Contents of al: " + al);
// Remove elements from the array list.
al.remove("F");
al.remove(2);
System.out.println("Size of al after deletions: " + al.size());
System.out.println("Contents of al: " + al);
}
Initial size of al: 0
} Size of al after additions: 7
Contents of al: [C, A2, A, E, B, D, F]
Size of al after deletions: 5
Contents of al: [C, A2, E, B, D]
2. The LinkedList class extends AbstractSequentialList and implements the
List, Deque, and Queue interfaces. It provides a linked-list data structure.
LinkedList is a generic class that has this declaration:
class LinkedList<E>
Here, E specifies the type of objects that the list will hold.
Constructors:
LinkedList( ) - creates an empty linked list
LinkedList(Collection<? extends E> c) - creates a linked list that contains
the elements of the specified collection.
Examples:
LinkedList<String> list1 = new LinkedList<>();
LinkedList<String> list2 = new LinkedList<>(list1);
import java.util.*;
class LinkedListDemo {
public static void main(String args[]) {
// Create a linked list.
LinkedList<String> ll = new LinkedList<String>();
// Add elements to the linked list.
ll.add("F");
ll.add("B");
ll.add("D");
ll.add("E");
ll.add("C");
ll.addLast("Z");
ll.addFirst("A");
ll.add(1, "A2");
System.out.println("Original contents of ll: " + ll);
// Remove elements from the linked list.
ll.remove("F");
ll.remove(2);
System.out.println("Contents of ll after deletion: " + ll);
// Remove first and last elements.
ll.removeFirst();
ll.removeLast();
System.out.println("ll after deleting first and last: " + ll);
// Get and set a value.
Original contents of ll: [A, A2, F, B, D, E, C, Z]
String val = ll.get(2); Contents of ll after deletion: [A, A2, D, E, C, Z]
ll.set(2, val + " Changed"); ll after deleting first and last: [A2, D, E, C]
ll after change: [A2, D, E Changed, C]
System.out.println("ll after change: " + ll);
3. HashSet class extends AbstractSet and implements the Set interface. It creates a collection
that uses a hash table for storage. HashSet is a generic class that has this declaration:
class HashSet<E>
Here, E specifies the type of objects that the set will hold.
A hash table stores information by using a mechanism called hashing. In hashing, the
informational content of a key is used to determine a unique value, called its hash code. The
hash code is then used as the index at which the data associated with the key is stored.
Constructors
HashSet( ) - creates an empty HashSet
HashSet(Collection<? extends E> c) - creates a HashSet that contains the elements of the
specified collection.
HashSet(int capacity) - creates a HashSet that has the specified initial capacity.
Examples
HashSet<String> hs1 = new HashSet<>();
HashSet<String> hs2 = new HashSet<>(hs1);
HashSet<String> hs3 = new HashSet<>(20);
// Demonstrate HashSet.
import java.util.*;
class HashSetDemo {
public static void main(String args[]) {
// Create a hash set.
HashSet<String> hs = new HashSet<String>();
// Add elements to the hash set.
hs.add("Beta");
hs.add("Alpha");
hs.add("Eta");
hs.add("Gamma");
hs.add("Epsilon");
hs.add("Omega");
System.out.println(hs);
}
}
Output: [Gamma, Eta, Alpha, Epsilon, Omega, Beta]
4. TreeSet extends AbstractSet and implements the NavigableSet
interface. It creates a collection that uses a tree for storage. Objects are
stored in sorted, ascending order. Access and retrieval times are quite
fast, which makes TreeSet an excellent choice when storing large amounts
of sorted information that must be found quickly.
TreeSet is a generic class that has this declaration:
class TreeSet<E>
Here, E specifies the type of objects that the set will hold.
Constructors
TreeSet( ) - Creates an empty tree set that will be sorted in ascending
order
TreeSet(Collection<? extends E> c) - Creates a tree set that contains the
elements of c
TreeSet(Comparator<? super E> comp) - constructs an empty tree set that
will be sorted according to the comparator specified by comp.
Examples:
1. TreeSet<String> ts1 = new TreeSet<String>();
2. TreeSet<String> ts2=new TreeSet<String>(ts1);
3. Comparator<String> reverseComparator = (s1, s2) -> s2.compareTo(s1);
TreeSet<String> ts3 = new TreeSet<>(reverseComparator);
Program
// Demonstrate TreeSet.
import java.util.*;
class TreeSetDemo {
public static void main(String args[]) {
// Create a tree set.
TreeSet<String> ts = new TreeSet<String>();
// Add elements to the tree set.
ts.add("C");
ts.add("A");
ts.add("B");
ts.add("E");
ts.add("F");
ts.add("D");
System.out.println(ts);
}
}
Output: [A, B, C, D, E, F]
Accessing a Collection via an
Iterator
• An Iterator in Java is an interface used to traverse elements in a
Collection sequentially.
• you want to cycle through the elements in a collection. For example,
you might want to display each element. One way to do this is to
employ an iterator, which is an object that implements the Iterator.
• Iterator enables you to cycle through a collection.
• ListIterator extends Iterator to allow bidirectional traversal of a list.
• Iterator and ListIterator are generic interfaces which are declared as
shown here:
interface Iterator<E>
interface ListIterator<E>
Here, E specifies the type of objects being iterated.
To use an iterator to cycle through the contents of a collection, follow these steps:
1. Obtain an iterator to the start of the collection by calling the collection’s
iterator( ) method.
2. Set up a loop that makes a call to hasNext( ). Have the loop iterate as long as
hasNext( ) returns true.
3. Within the loop, obtain each element by calling next( ).
Methods
iterator() Returns an instance of iterator used to iterate over elements of
collections.
listIterator() Returns an iterator for traversing a List in both forward and backward
directions.
hasNext( ) Returns true if there are more elements. Otherwise, returns false.
hasPrevious( ) Returns true if there is a previous element. Otherwise, returns false.
next( ) Returns the next element. A NoSuchElementException is thrown if there is
not a next element.
// Demonstrate iterators.
import java.util.*;
class IteratorDemo {
public static void main(String args[]) { // Create an array list.
ArrayList<String> al = new ArrayList<String>();
// Add elements to the array list.
al.add("C");
al.add("A");
al.add("E");
al.add("B");
al.add("D");
al.add("F");
// Use iterator to display contents of al.
System.out.print("Original contents of al : ");
Iterator<String> itr = al.iterator();
while(itr.hasNext()) {
String element = itr.next();
System.out.print(element + " ");
}
System.out.println();
// Modify objects being iterated.
ListIterator<String> litr = al.listIterator();
while(litr.hasNext()) {
String element = litr.next();
litr.set(element + "+");
}
System.out.print("Modified contents of al: ");
itr = al.iterator();
while(itr.hasNext()) {
String element = itr.next();
System.out.print(element + " "); }
System.out.println();
// Now, display the list backwards.
System.out.print("Modified list backwards: ");
while(litr.hasPrevious()) {
String element = litr.previous();
System.out.print(element + " ");
} Output:
Original contents of al: C A E B D F
System.out.println();
Modified contents of al: C+ A+ E+ B+ D+ F+
}} Modified list backwards: F+ D+ B+ E+ A+ C+
The for-each version of the for loop is often a more convenient alternative to
cycling through a collection than is using an iterator.
import java.util.*;
class ForEachDemo {
public static void main(String args[]) {
// Create an array list for integers.
ArrayList<Integer> vals = new ArrayList<Integer>();
// Add values to the array list.
vals.add(1);
vals.add(2);
vals.add(3);
vals.add(4);
vals.add(5);
// Use for loop to display the values.
System.out.print("Contents of vals: ");
for(int v : vals)
System.out.print(v + " ");
System.out.println();
// Now, sum the values by using a for loop.
int sum = 0;
for(int v : vals)
sum += v;
System.out.println("Sum of values: " + sum); Output:
}} Contents of vals: 1 2 3 4 5
Sum of values: 15
Working with Maps
• The Map interface maps unique keys to values. A key is an object that you use
to retrieve a value at a later date.
• Map is generic and is declared as
interface Map<K, V>
Here, K specifies the type of keys, and V specifies the type of values.
Methods:
put ( ) - To put a value into a map, specifying the key and the value.
get( ) - To obtain a value, passing the key as an argument. The value is returned.
containsKey() - Returns true if the invoking map contains k as a key.
containsValue( ) - Returns true if the map contains v as a value.
isEmpty( ) - Returns true if the invoking map is empty.
replace(k , v ) - It replaces the specified value for a specified key.
put( ) - It is used to insert an entry in the map.
The HashMap class extends AbstractMap and implements the Map interface. HashMap
is a generic class that has this declaration:
class HashMap<K, V>
Here, K specifies the type of keys, and V specifies the type of values.
public class MapExample {
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<>();
map.put(1, "Apple");
map.put(2, "Banana");
map.put(3, "Cherry");
System.out.println(map);
System.out.println(map.get(2));
System.out.println(map.containsKey(1)); {1=Apple, 2=Banana, 3=Cherry}
Banana
map.replace(1, "Apricot"); true
System.out.println(map); {1=Apricot, 2=Banana, 3=Cherry}
} }
StringTokenizer
• The processing of text often consists of parsing a formatted input string.
Parsing is the division of text into a set of discrete parts, or tokens.
• The StringTokenizer class allows an application to break a string into
tokens based on delimiters. It implements the Enumeration interface.
To use StringTokenizer, we need to specify an input string and a set of
delimiters.
• The default set of delimiters consists of the whitespace characters:
space, tab, form feed, newline, and carriage return.
Methods
hasMoreTokens( ) - Returns true if one or more tokens remain in the
string
nextToken( ) - Returns the next token as a String.
// Demonstrate StringTokenizer.
import java.util.StringTokenizer;
class STDemo {
static String in = "title=Java: The Complete Reference;" +
"author=Schildt;" +
"publisher=McGraw-Hill;" +
"copyright=2020";
public static void main(String args[]) {
StringTokenizer st = new StringTokenizer(in, "=;");
while(st.hasMoreTokens()) {
Output:
String key = st.nextToken(); title Java: The Complete Reference
String val = st.nextToken(); author Schildt
publisher McGraw-Hill
System.out.println(key + "\t" + val); copyright 2020
} } }
Date
The Date class encapsulates the current date and time. Date implements the
Comparable interface.
Constructors
Date( ) - initializes the object with the current date and time.
Date(long millisec) - accepts one argument that equals the number of
milliseconds that have elapsed since midnight, January 1, 1970.
import java.util.Date;
class DateDemo {
public static void main(String args[]) {
Date date = new Date(); // Instantiate a Date object
System.out.println(date);
long msec = date.getTime();
System.out.println("Milliseconds sinceWed Jan.Dec1,
251970 GMT
11:08:45 GMT=2024" + msec);
Milliseconds since Jan. 1, 1970 GMT = 1735124925205
}}
Calendar
• The Calendar is an abstract (cannot directly instantiate it) class provides a set
of methods that allows you to convert a time in milliseconds to a number of
useful components such as year, month, day, hour, minute, and second.
Methods
getInstance() - Returns a Calendar object for the default locale and
time zone.
get() - Returns the value of a specific calendar field.
set() - Sets a specific calendar field to a specified value.
add() - Adds or subtracts a specified amount of time to a field.
getTime() - Returns the Date object representing the current date and time of
the Calendar.
getTimeZone() - Returns the time zone for the invoking object.
setTime() - Sets the Calendar to a specific Date.
// Demonstrate Calendar
import java.util.Calendar;
class CalendarDemo {
public static void main(String[] args) {
Calendar calendar = Calendar.getInstance();
// Display current time and date information.
System.out.print("Date: ");
System.out.print(calendar.get(Calendar.MONTH));
System.out.print(" " + calendar.get(Calendar.DATE) + " ");
System.out.println(calendar.get(Calendar.YEAR));
System.out.print("Time: ");
System.out.print(calendar.get(Calendar.HOUR) + ":");
System.out.print(calendar.get(Calendar.MINUTE) + ":");
System.out.println(calendar.get(Calendar.SECOND));
// Set the time and date information and display it.
calendar.set(Calendar.HOUR, 10);
calendar.set(Calendar.MINUTE, 29);
calendar.set(Calendar.SECOND, 22);
System.out.print("Updated time: ");
System.out.print(calendar.get(Calendar.HOUR) + ":");
System.out.print(calendar.get(Calendar.MINUTE) + ":");
Date: Jan 10 2024
System.out.println(calendar.get(Calendar.SECOND)); Time: 11:29:39
}} Updated time: 10:29:22
Locale
• The Locale class is instantiated to produce objects that describe a geographical or
cultural region.
• The ability to write programs that can execute in different international
environments. For example, the formats used to display dates, times, and numbers
are different in various regions.
Constructors
Locale(String language) - Creates Locale from the given language code.
Locale(String language, String country) - Creates Locale from the given language,
country code.
Locale(String language, String country, String variant) - Creates Locale from the given
language, country, variant code (sub-culture).
Examples
Locale loc=new Locale("fr");
Locale locale = new Locale("fr", "CA");
Locale locale = new Locale("en", "US", "Silicon Valley");
import java.util.Locale;
class Main {
public static void main(String[] args) {
Locale current = Locale.getDefault(); // get the default locale
System.out.println("Country code: " + current.getCountry());
System.out.println("Name of the Country: " +
current.getDisplayCountry());
System.out.println("Language Code: " + current.getLanguage());
System.out.println("Language Name: "
+ current.getDisplayLanguage());
Country code: US
System.out.println(); Name of the Country: United States
} Language Code: en
} Language Name: English
Random
• The Random class is a generator of pseudorandom numbers ( uniformly
distributed sequences).
• Random implements the RandomGenerator interface.
Constructors
Random( ) - creates a number generator that uses a reasonably unique
seed.
Random(long seed) - allows you to specify a seed value manually.
Examples
Random r = new Random();
Random r = new Random(12345L); // Set a long seed value
import java.util.Random;
class RandomDemo {
public static void main(String[] args) {
Random r = new Random(); // Generate a random integer
int rInt = r.nextInt();
System.out.println("Random integer: " + randomInt);
// Generate a random integer between 0 (inclusive) and 100 (exclusive)
int rRange = random.nextInt(100);
System.out.println("Random integer between 0 and 100: " + rRange);
boolean rBoolean = random.nextBoolean(); // Generate a random boolean
System.out.println("Random boolean: " + rBoolean);
// Generate a random floating point number between 0.0 andRandom
1.0 integer: -1710722315
Random integer between 0 and 100: 31
double rDouble = random.nextDouble(); Random boolean: true
Random double between 0.0 and 1.0:
System.out.println("Random double between 0.0 and 1.0: " + rDouble);
0.9757959916231587
}
}
Timer and TimerTask
• An interesting and useful feature offered by java.util is the ability to
schedule a task for execution at some future time. The classes that
support this are Timer and TimerTask.
• Timer and TimerTask work together. Timer is the class that you will
use to schedule a task for execution. The task being scheduled must
be an instance of TimerTask.
• TimerTask implements the Runnable interface; thus, it can be used to
create a thread of execution.
Constructor
TimerTask( ) - Creates a timer task object.
Methods
cancel( )-Terminates the task.
void run( ) - Contains the code for the timer task.
• Once a task has been created, it is scheduled for execution by an object of type Timer.
Constructors
Timer( ) - creates a Timer object.
Timer(boolean DThread) - The second uses a daemon thread (low-priority threads that run in the background to
provide services to user threads)
schedule( ) - schedule a task.
// Demonstrate Timer and TimerTask.
import java.util.*;
class MyTimerTask extends TimerTask {
public void run() {
System.out.println("Timer task executed.");
}
}
class TTest {
public static void main(String[] args) {
MyTimerTask myTask = new MyTimerTask();
Timer myTimer = new Timer();
/* Set an initial delay of 1 second,
then repeat every half second. */
myTimer.schedule(myTask, 1000, 500);
try {
Thread.sleep(5000);
} catch (InterruptedException exc) {}
myTimer.cancel();
}}
Output
Timer task executed.
Timer task executed.
Timer task executed.
Timer task executed.
Timer task executed.
Timer task executed.
Timer task executed.
Timer task executed.
Scanner
• Scanner can be used to read input from the console, a file, a string, or any source that
implements the Readable interface.
• you can use Scanner to read a number from the keyboard and assign its value to a
variable.
Constructors
Scanner(String source) - Creates a scanner object to read from a String.
Scanner(File Source) - Creates a scanner object to read input from a file.
Scanner(InputStream source) - create a scanner object to read from a specified
InputStream.
Scanner(Readable source) - Creats a scanner object to read from any Readable object.
Examples
Scanner scanner = new Scanner("Hello World!");
Scanner scanner = new Scanner(new File("file.txt"));
Scanner scanner = new Scanner(System.in);
Scanner scanner = new Scanner(new StringReader("Hello!"));
Methods
next() - Returns the next token of any type.
nextByte() - Returns a next token as a byte value.
nextBoolean() - ‘’
nextDouble() - ‘’
nextFloat() - ‘’
nextInt() - ‘’
nextLong() - ‘’
nextShort() - ‘’
A module in Java defines a module descriptor file called module-info.java.
This file is used to declare the module's name and the packages that it
exports, as well as the dependencies it requires.
Module
• A module is a group of related packages, classes, and other resources that are bundled
together.
• A module is a grouping of packages and resources that can be collectively referred to by
the module’s name.
• A module declaration specifies the name of a module and defines the relationship a
module and its packages have to other modules.
General form - A module declaration begins with the keyword module.
module moduleName {
// module definition
}
The name of the module is specified by moduleName, which must be a valid Java identifier.
Features
Encapsulation: You can control which classes are accessible to other modules.
Dependencies: Modules can declare which other modules they depend on.
Visibility: You can specify which packages are public and available to other modules and
which are private to the module.
Basic Structure of a Module:
• A module in Java defines a module descriptor file called module-info.java.
This file is used to declare the module's name and the packages that it
exports, as well as the dependencies it requires.
module-info.java file: This is the module descriptor file.
Exported packages: These are the packages you want to expose to other
modules.
Requires clauses: Specify the dependencies your module has.
Creating a Simple Java Module
• Module A: A simple module that contains a package and class with a
method.
• Module B: A module that depends on Module A and uses its functionality.
Create Module A
Directory structure: module-info.java for Module A: MyClass.java for Module A:
ModuleA
package com.example.util;
└── src module moduleA {
└── moduleA exports com.example.util; public class MyClass {
} public void displayMessage() {
└── com System.out.println("Hello from
└── example Module A!");
}
└── util }
└── MyClass.java
└── module-info.java
Create Module B
Main.java for Module B:
Directory structure:
module-info.java for
ModuleB Module B: package com.example.main;
└── src module moduleB { import com.example.util.MyClass;
└── moduleB requires moduleA;
} public class Main {
└── com public static void main(String[] args) {
└── example MyClass myClass = new MyClass();
└── main myClass.displayMessage();
}
└── Main.java
}
└── module-info.java
Module A exports the package com.example.util, which contains the class MyClass.
Module B requires Module A (using requires moduleA), meaning it can use the classes
from Module A.
The Main.java in Module B creates an instance of MyClass and calls its displayMessage()
method.
java.base and platform modules
• The modularization of the API is one of the primary benefits realized by
the addition of the modules. Because of their special role, the API
modules are referred to as platform modules, and their names all begin
with the prefix java.
• Here are some examples: java.base, java.desktop, and java.xml.
• java.base is automatically accessible to all modules and all other modules
automatically require java.base. There is no need to include a requires
java.base statement in a module declaration.
Legacy Code and the Unnamed Module
• When you use code that is not part of a named module, it automatically
becomes part of the unnamed module.
• The key feature that supports legacy code is the automatic use of the class
path, rather than the module path. When you compile a program that
does not use modules, the class path mechanism is employed.
Exporting to a Specific Module
• The basic form of the exports statement makes a package accessible to any
and all other modules.
• It can be desirable to make a package accessible to only a specific set of
modules, not all other modules.
• The form of exports that includes to is shown here:
exports packageName to moduleNames;
Here, moduleNames is a comma-separated list of modules to which the
exporting module grants access.
Example:
module appfuncs {
// Exports the package appfuncs.simplefuncs to appstart.
exports appfuncs.simplefuncs to appstart;
}
Use Services
• A service is a program unit whose functionality is defined by an interface or abstract
class. Thus, a service specifies in a general way some form of program activity.
• A concrete implementation of a service is supplied by a service provider. In other
words, a service defines the form of some action, and the service provider supplies that
action.
• Services are often used to support a pluggable architecture.
• For example, a service might be used to support the translation of one language into
another. In this case, the service supports translation in general. The service provider
supplies a specific translation, such as German to English or French to Chinese.
• Service providers are supported by the ServiceLoader class.
• ServiceLoader is a generic class packaged in java.util. It is declared like this:
class ServiceLoader<S>
Here, S specifies the service type. Service providers are loaded by the load( ) method.
When load( ) is called, it returns a ServiceLoader instance for the application
Module Graphs
• During compilation, the compiler resolves the dependence relationships between
modules by creating a module graph that represents the dependences. The process
ensures that all dependences are resolved, including those that occur indirectly.
• Module graphs can be depicted visually in a drawing to illustrate the relationship
between modules. In Java, the arrows point from the dependent module to the
required module. Thus, a drawing of a module graph depicts what modules have
access to what other modules. Assume six modules called A, B, C, D, E, and F.
Further assume that A requires B and C, B requires D and E, and C requires F. The
following visually depicts this relationship.
Three Specialized Module
Features
• There are three additional module-related features that can be quite
useful in certain circumstances. These are the open module, the opens
statement, and the use of requires static.
• Open module - it is useful to enable run-time access to all packages in
the module, whether a package is exported or not.
open module moduleName {
// module definition
}
• Opens statement - It is possible for a module to open a specific
package for run-time access.
opens packageName;
Here, packageName specifies the package to open.
• Requires static - It is possible to specify a module not required at run time.
This is accomplished by use of the static modifier in a requires statement.
requires static mymod;
• specifies that mymod is required for compilation, but not at run time.
Enhancements to switch
• The switch statements are program control statements and provides for a
multiway branch.
• It has been substantially enhanced with the addition of four new features.
• The switch expression - produces a value
• The yield statement - specifies a value
• Support for a list of case constants - more than one case constant
• The case with an arrow - uses an arrow (->) instead of a colon
public class SwitchExample {
public static void main(String[] args) { // Example 1: Switch expression with yield statement
int dayOfWeek = 3; // Example: Let's say it's Wednesday
String dayType = switch (dayOfWeek) {
case 1, 7 -> "Weekend"; // Sunday or Saturday
case 2, 3, 4, 5, 6 -> "Weekday"; // Monday to Friday
default -> {
yield "Invalid day"; // In case of an invalid day number
} };
System.out.println("The day type is: " + dayType);
String fruit = "Apple"; // Example 2: Switch expression with different data types
int price = switch (fruit) {
case "Apple" -> 2;
case "Banana" -> 1;
case "Orange" -> 3;
default -> 0; // Default case for unknown fruits
The day type is: Weekday
};
Price of Apple is: $2
System.out.println("Price of " + fruit + " is: $" + price);
} }
Text Block
• A text block is a new kind of literal that is comprised of a sequence of
characters that can occupy more than one line.
• when creating long string literals, newline characters can be used in a text
block without the need for the \n escape sequence.
• A text block is supported by a new delimiter, which is three double-quote
characters: """. A text block is created by enclosing a string within a set of
these delimiters.
Example
String str = """
Text blocks make
multiple lines easy.
"""; Text blocks make
multiple lines easy.
System.out.println(str);
Records
• A record is a class that is intended to act as a simple data carrier.
• Because it is used to hold group of values, a record is commonly referred to
as an aggregate type.
Syntax
record recordName(component-list) {
// optional body statements
}
The component list defines the data that the record will hold.
A record is instantiated by use of new, just the way you create an instance of a
class.
Examples
record Employee(String name, int idNum) { }
Employee emp = new Employee("Doe, John", 1047);
record Employee(String name, int idNum) { }
class RecordDemo {
public static void main(String[] args) {
// Create an array of Employee records.
Employee[] empList = new Employee[4];
empList[0] = new Employee("Doe, John", 1047);
empList[1] = new Employee("Jones, Robert", 1048);
empList[2] = new Employee("Smith, Rachel", 1049);
empList[3] = new Employee("Martin, Dave", 1050);
for(Employee e: empList)
System.out.println("The employee ID for " + e.name() + " is " + e.idNum());
}} The employee ID for Doe, John is 1047
The employee ID for Jones, Robert is 1048
The employee ID for Smith, Rachel is 1049
The employee ID for Martin, Dave is 1050
Pattern Matching with instanceof
• Pattern matching defines a mechanism that determines if a value fits a general form.
• instanceof pattern matching is used to test the type of a value.
Syntax
objref instanceof type pattern-var
• If the pattern matches, a pattern variable will receive a reference to the object
matched by the pattern.
Traditional
Object obj = "Hello, World!";
if (obj instanceof String) {
String str = (String) obj;
System.out.println(str);
}
you first check if obj is an instance of String, and then you explicit cast it.
you can combine the type check and the cast in a single operation, making
the code shorter and more readable
Code
Object obj = 42; // Integer object
if (obj instanceof Integer i) {
System.out.println("Integer value: " + i);
} else if (obj instanceof String s) {
System.out.println("String value: " + s);
} else {
System.out.println("Unknown type");
}
Sealed Classes
• A sealed class is a class that restricts which other classes or interfaces
can extend or implement it.
• To declare a sealed class, precede the declaration with sealed. Then,
after the class name, include a permits clause that specifies the allowed
subclasses.
Syntax
public sealed class classname permits subclass1, subclass2 {
// ...
}
Example
public sealed class MySealedClass permits Alpha, Beta {
// ...
}
The sealed class is called MySealedClass. It allows only two subclasses: Alpha and
Beta. If any other class attempts to inherit MySealedClass, a compile-time error
will occur. Here are Alpha and Beta, the two subclasses of MySealedClass:
public final class Alpha extends MySealedClass {
// ...
}
public final class Beta extends MySealedClass {
// ...
}
Each subclass is declared final to denote that the inheritance chain ends with
Alpha and Beta.
Sealed Interfaces
• A sealed interface is declared in the same way as a sealed class, by the use of sealed. The permits
clause specify the classes allowed to implement it.
Syntax: public sealed interface interfacename permits subclass1, subclass2 {
// ...
}
Example:
public sealed interface MySealedIF permits Alpha, Beta {
void myMeth();
}
public final class Alpha implements MySealedIF {
public void myMeth() { System.out.println("In Alpha's myMeth()."); }
}
public final class Beta implements MySealedIF {
public void myMeth() { System.out.println("Inside Beta's myMeth()."); }
}