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

java unit 3 part 4

The document discusses various enhancements in Java, including type annotations, repeating annotations, the Java Module System, diamond syntax with inner anonymous classes, and improvements to the switch statement. It highlights the introduction of features such as the yield keyword, which allows switch statements to return values, and text blocks for easier multi-line string representation. These updates aim to improve code readability, modularity, and error handling in Java programming.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views

java unit 3 part 4

The document discusses various enhancements in Java, including type annotations, repeating annotations, the Java Module System, diamond syntax with inner anonymous classes, and improvements to the switch statement. It highlights the introduction of features such as the yield keyword, which allows switch statements to return values, and text blocks for easier multi-line string representation. These updates aim to improve code readability, modularity, and error handling in Java programming.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 12

@NonNull String str;

Following are the examples of type annotations:

@NonNull List<String>
List<@NonNull String> str
Arrays<@NonNegative Integer> sort
@Encrypted File file
@Open Connection connection
void divideInteger(int a, int b) throws @ZeroDivisor ArithmeticException
Note - Java created type annotations to support improved analysis of Java programs. It
supports way of ensuring stronger type checking.

Java Repeating Annotations


In Java 8 release, Java allows you to repeating annotations in your source code. It is helpful
when you want to reuse annotation for the same class. You can repeat an annotation anywhere
that you would use a standard annotation.

For compatibility reasons, repeating annotations are stored in a container annotation that is
automatically generated by the Java compiler. In order for the compiler to do this, two
declarations are required in your code.
1. Declare a repeatable annotation type
2. Declare the containing annotation type

1) Declare a repeatable annotation type


Declaring of repeatable annotation type must be marked with the @Repeatable meta-
annotation. In the following example, we have defined a custom @Game repeatable
annotation type.

@Repeatable(Games.class)
@interfaceGame{
String name();
String day();
}
The value of the @Repeatable meta-annotation, in parentheses, is the type of the container
annotation that the Java compiler generates to store repeating annotations. In the following
example, the containing annotation type is Games. So, repeating @Game annotations is
stored in an @Games annotation.

2) Declare the containing annotation type


Containing annotation type must have a value element with an array type. The component
type of the array type must be the repeatable annotation type. In the following example, we
are declaring Games containing annotation type:

@interfaceGames{
Game[] value();
}
Note - Compiler will throw a compile-time error, if you apply the same annotation to a
declaration without first declaring it as repeatable.

Java Repeating Annotations Example


// Importing required packages for repeating annotation

import java.lang.annotation.Repeatable;

21
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
// Declaring repeatable annotation type
@Repeatable(Games.class)
@interfaceGame{
String name();
String day();
}
// Declaring container for repeatable annotation type
@Retention(RetentionPolicy.RUNTIME)
@interfaceGames{
Game[] value();
}
// Repeating annotation
@Game(name = "Cricket", day = "Sunday")
@Game(name = "Hockey", day = "Friday")
@Game(name = "Football", day = "Saturday")
public class RepeatingAnnotationsExample {
public static void main(String[] args) {
// Getting annotation by type into an array
Game[] game =
RepeatingAnnotationsExample.class.getAnnotationsByType(Game.class);
for (Gamegame2 : game) { // Iterating values
System.out.println(game2.name()+" on "+game2.day());
}
}
}
OUTPUT:

Cricket on Sunday
Hockey on Friday
Football on Saturday

9. Java 9 Module System

Java Module System is a major change in Java 9 version. Java added this feature to collect
Java packages and code into a single unit called module.

In earlier versions of Java, there was no concept of module to create modular Java
applications, that why size of application increased and difficult to move around. Even JDK
itself was too heavy in size, in Java 8, rt.jar file size is around 64MB.

To deal with situation, Java 9 restructured JDK into set of modules so that we can use only
required module for our project.

Apart from JDK, Java also allows us to create our own modules so that we can develop
module based application.
The module system includes various tools and options that are given below.
o Includes various options to the Java tools javac, jlink and java where we can specify
module paths that locates to the location of module.
o Modular JAR file is introduced. This JAR contains module-info.class file in its root
folder.
22
o JMOD format is introduced, which is a packaging format similar to JAR except it can
include native code and configuration files.
o The JDK and JRE both are reconstructed to accommodate modules. It improves
performance, security and maintainability.
o Java defines a new URI scheme for naming modules, classes and resources.

Java 9 Modularized JDK

Module is a collection of Java programs or softwares. To describe a module, a Java


file module-info.java is required. This file also known as module descriptor and defines the
following
o Module name
o What does it export
o What does it require

Module Name

It is a name of module and should follow the reverse-domain-pattern. Like we name packages,
e.g. com.javatpoint.

How to create Java module


Creating Java module required the following steps.
o Create a directory structure
o Create a module declarator
o Java source code

Create a Directory Structure

To create module, it is recommended to follow given directory structure, it is same as reverse-


domain-pattern, we do to create packages / project-structure in Java.

Note: The name of the directory containing a module's sources should be equal to the name of
the module, e.g. com.javatpoint.

Create a file module-info.java, inside this file, declare a module by using module identifier
and provide module name same as the directory name that contains it. In our case, our directory
name is com.javatpoint.
1. module com.javatpoint{
2.​ 3. }

Leave module body empty, if it does not has any module dependency. Save this file
inside src/com.javatpoint with module-info.java name.
Java Source Code
Now, create a Java file to compile and execute module. In our example, we have
23
a Hello.java file that contains the following code.
1. class Hello{
2. public static void main(String[] args){
3. System.out.println("Hello from the Java module");
4. }
5. }

Save this file inside src/com.javatpoint/com/javatpoint/ with Hello.java name.

Compile Java Module

To compile the module use the following command.

1. javac -d mods --module-source-path src/ --module com.javatpoint


After compiling, it will create a new directory that contains the following structure.

Now, we have a compiled module that can be just run.


Run Module
To run the compiled module, use the following command.
1. java --module-path mods/ --module com.javatpoint/com.javatpoint.Hello

Output:

Hello from the Java module

Well, we have successfully created, compiled and executed Java module.

Look inside compiled Module Descriptor


To see the compiled module descriptor use the following command.
1. javap mods/com.javatpoint/module-info.class

This command will show the following code to the console.


1. Compiled from "module-info.java"
2. module com.javatpoint {
3. requires java.base;
4. }

See, we created an empty module but it contains a java.base module. Why? Because all Java
modules are linked to java.base module and it is default module.

10. Diamond syntax with inner anonymous class

Diamond Operator: Diamond operator was introduced in Java 7 as a new feature.The


main purpose of the diamond operator is to simplify the use of generics when creating an
object. It avoids unchecked warnings in a program and makes the program more readable.

24
The diamond operator could not be used with Anonymous inner classes in JDK 7. In JDK
9, it can be used with the anonymous class as well to simplify code and improves
readability. Before JDK 7, we have to create an object with Generic type on both side of the
expression like:

// Here we mentioned the generic type


// on both side of expression while creating object
List<String> geeks = new ArrayList<String>();
When Diamond operator was introduced in Java 7, we can create the object without mentioning
generic type on right side of expression like:
List<String> geeks = new ArrayList<>();

Problem with Diamond Operator in JDK 7?


With the help of Diamond operator, we can create an object without mentioning the generic
type on the right hand side of the expression. But the problem is it will only work with
normal classes. Suppose you want to use the diamond operator for anonymous inner class
then compiler will throw error message like below:

// Program to illustrate the problem// while linking diamond operator// with an anonymous inner class
abstract class Geeksforgeeks<T> {
abstract T add(T num1, T num2);
}
public class Geeks {
public static void main(String[] args)
{
Geeksforgeeks<Integer> obj = new Geeksforgeeks<>() { Integer
add(Integer n1, Integer n2)
{
return (n1 + n2);
}
};
Integer result = obj.add(10, 20); System.out.println("Addition of
two numbers: " + result);
}
}
Output:
prog.java:9: error: cannot infer type arguments for Geeksforgeeks
Geeksforgeeks obj = new Geeksforgeeks () {
^
reason: cannot use '' with anonymous inner classes
where T is a type-variable:
T extends Object declared in class Geeksforgeeks
1 error
Java developer extended the feature of the diamond operator in JDK 9 by allowing the
diamond operator to be used with anonymous inner classes too. If we run the above code
with JDK 9, then code will run fine and we will generate the below output.
Addition of two numbers: 30
Output:
25
11. Enhancements for Switch Statement in Java

Java 12 improved the traditional switch statement and made it more useful. Java 13 further
introduced new features. Before going into the details of new features, let’s have a look at
the drawbacks faced by the traditional Switch statement.

Problems in Traditional Switch

1. Default fall through due to missing break:


The default fall-through behavior is error-prone. Let’s understand it with an example.
switch (itemCode)
{ case 001 :
System.out.println("It's a laptop!");
break;
case 002 :
System.out.println("It's a desktop!");
break;
case 003 :
System.out.println("It's a mobile phone!");
break;
default :
System.out.println("Unknown device!");
}
The above code works by matching the corresponding case and executing the particular code
block. As long as you provide the necessary break statements, it works fine.
But what happens if we forget any of the required break statements:
switch (itemCode)
{ case 001 :
System.out.println("It's a laptop!");
// missed out break here
case 002 :
System.out.println("It's a desktop!");

}
Here, if we pass 001, the first case matches, and the code block executes. But due to missing
break, execution falls through and continues for case 002. We get the following wrong output:
It's a laptop!
It's a desktop!
Clearly, this is not the intended output. It is a result of accidentally missing out break
statements.
2. Multiple values per case not supported:
There may be situations where similar processing is required for multiple case values. But
the traditional switch makes to follow the fall through behaviors.
case 001:
case 002:
case 003:
System.out.println("It's an electronic gadget!");

26
12. Upgraded Switch in Java 13

Enhancements to switch statements were introduced by Java 12 and then further modified by
Java 13. Let’s dive into the important features of this improved version of the Switch
statement.
1. Supports multiple values per case:
With multiple values being specified per case, it simplifies the code structure and eliminates
the need for using fall through.
The values need to be separated by commas and break should follow the case block.
switch (itemCode)
{ case 001, 002, 003 :
System.out.println("It's an electronic gadget!");
break;

case 004, 005:


System.out.println("It's a mechanical device!");
}
2. yield is used to return a value:
A new keyword yield has been introduced. It returns values from a switch branch only.
We don’t need a break after yield as it automatically terminates the switch expression.
int val = switch (code)
{ case "x", "y" :
yield 1;
case "z", "w" :
yield 2;
};
3. Switch can be used as an expression:
The switch can now be used as an expression. This means the switch can now return
values based on our input. There is a slight change in switch syntax to accommodate this
change. A switch block needs to be delimited by a semicolon. The yield keyword is used to
return values. No break required with the yield statement.
Let’s have a look at a code snippet to understand these changes better.
String text = switch (itemCode)
{ case 001 :
yield "It's a laptop!";
case 002 :
yield "It's a desktop!";
case 003 :
yield "It's a mobile phone!";
default :
throw new IllegalArgumentException(itemCode + "is an unknown device!");
}; // switch block ended by semicolon

27
13. Yield Keyword

In Java, the yield keyword was introduced as part of the enhancement of the switch
expression in Java 12 (as a preview feature) and then fully integrated in Java 14. It allows for
a value to be returned from a switch expression, making the switch statement more flexible
and expressive.
Understanding yield in Switch Expressions

Prior to Java 12, switch statements were primarily used for control flow, but they couldn't
directly return values. With the introduction of switch expressions, you can now use switch
statements to produce values.
Example with yield
Here's an example that demonstrates the use of yield in a switch expression:
public class YieldExample {
public static void main(String[] args)
{ int day = 3;
String dayType = switch (day)
{ case 1, 2, 3, 4, 5 -> "Weekday";
case 6, 7 -> "Weekend";
default -> throw new IllegalArgumentException("Invalid day: " + day);
};

System.out.println("Day type: " + dayType);


}
}

In the example above, the switch expression assigns a value to the variable dayType. It uses
the arrow (->) syntax for cases and does not require the yield keyword because it returns a
simple value.

However, when you have more complex logic within a case, you can use yield to return a
value from that case:

public class YieldExample {


public static void main(String[] args)
{ int day = 3;
String dayType = switch (day)
{ case 1, 2, 3, 4, 5 -> {
System.out.println("It's a weekday");
yield "Weekday";
}
case 6, 7 -> {
System.out.println("It's the weekend");
yield "Weekend";
}
default -> throw new IllegalArgumentException("Invalid day: " + day);
};

System.out.println("Day type: " + dayType);


}
}

Explanation

28
1. Switch Expression: The switch statement in this example is used as an expression
that returns a value.
2. Arrow Syntax : The -> arrow syntax simplifies returning a single value.
3. Yield Statement : When more complex logic is required inside a case, the yield
statement is used to return a value from the block. This is particularly useful when the
case block contains multiple statements.

Benefits of yield in Switch Expressions

 Clarity and Conciseness: The code is clearer and more concise compared to
traditional switch statements.
 Expressions Over Statements: Allows switch to be used as an expression, making it
more powerful and flexible.
 Less Error-Prone: Reduces common errors associated with traditional switch
statements, such as fall-through.

14. Text Blocks in Java 15


In this
 article, we are going to discuss the Java 15 text blocks feature to declare multi-line
strings most efficiently. We all know that how we can
declare multi-line strings and that too quite easily with the help of concatenation, string’s join
method, StringBuilder append method, etc. Now the question will arise in our mind that if
everything is this simple then what is the need for a new feature i.e. text blocks to declare
multi-line strings. So let’s first try to understand the problem and then we will understand the
need for a text block.
In earlier releases of the JDK, embedding multi-line code snippets required a tangled mess of
explicit line terminators, string concatenations, and delimiters. Text blocks eliminate most of
these obstructions, allowing you to embed code snippets and text sequences more or less as-
is.
A text block is an alternative form of Java string representation that can be used anywhere a
traditional double-quoted string literal can be used. Text blocks begin with a “”” (3 double-
quote marks) observed through non-obligatory whitespaces and a newline. For example:
 Java

// Using a literal string


String text1 = "Geeks For Geeks";

// Using a text block


String text2 = """
Geeks For Geeks""";

Note: Since Java 15, text blocks are available as a standard feature. With Java 13 and 14, we
needed to enable it as a preview feature.
The object created from text blocks is java.lang.String with the same properties as a regular
string enclosed in double quotes. This includes the presentation of objects and the interning.
Continue with text1 and text2 from the previous examples,
 Java

29
// Both text1 and text2 are strings of equal value
text1.equals(text2) // true

// Both text1 and text2 intern to the same string


text1 == text2 // true

Text blocks may be utilized in the region of a string literal to enhance the clarity and
readability of the code. This typically takes place whilst a string literal is used to symbolize a
multi-line string. In this example there’s a substantial muddle from citation marks, newline
escapes, and concatenation operators:
 Java

// ORIGINAL
String message = "A-143, 9th Floor, Sovereign Corporate Tower,\n" +
"Sector-136, Noida,\n" +
"Uttar Pradesh - 201305";

// BETTER : Using text blocks


// gets rid of lots of the clutter
String message = """
A-143, 9th Floor, Sovereign Corporate Tower,
Sector-136, Noida,
Uttar Pradesh - 201305""";

15. Sealed Classes

Sealed classes and interfaces were introduced in Java 15 as a preview feature and became a
standard feature in Java 17. Sealed classes and interfaces allow you to restrict which other
classes or interfaces can extend or implement them. This helps to model your domain more
precisely and enhances maintainability and security by controlling the inheritance hierarchy.

Key Features of Sealed Classes

1. Restricting Inheritance: Sealed classes enable you to define a fixed set of


subclasses, ensuring that no other classes can extend your sealed class without your
explicit permission.
2. Exhaustiveness in Switch Expressions: When used with pattern matching and
switch expressions, sealed classes help the compiler ensure all possible cases are
covered.

Syntax

Sealed classes and interfaces are defined using the sealed keyword followed by the permits
clause, which lists the permitted subclasses.

Example of Sealed Class

Here's an example demonstrating how to define and use a sealed class:

30
public sealed class Shape permits Circle, Rectangle, Square {
// common methods and fields for shapes
}
public final class Circle extends Shape
{ private final double radius;
public Circle(double radius)
{ this.radius = radius;
}
public double getRadius()
{ return radius;
}
// other methods specific to Circle
}
public final class Rectangle extends Shape
{ private final double width;
private final double height;
public Rectangle(double width, double height)
{ this.width = width;
this.height = height;
}
public double getWidth()
{ return width;
}
public double getHeight()
{ return height;
}
// other methods specific to Rectangle
}
public final class Square extends Shape
{ private final double side;

public Square(double side)


{ this.side = side;
}
public double getSide()
{ return side;
}
// other methods specific to Square
}

Explanation
1. Sealed Class: The Shape class is declared as sealed and specifies the subclasses
Circle, Rectangle , and Square using the permits clause.
2. Final Subclasses : The permitted subclasses are declared as final, meaning they
cannot be extended further. Alternatively, subclasses can be non-sealed, allowing
further subclassing, or sealed themselves.

Permitted Subclass Modifiers

 final : The subclass cannot be extended further.


 sealed: The subclass can be sealed, allowing specific further subclasses.
 non-sealed : The subclass removes the sealing restriction, allowing any class to extend
it.

31
Benefits of Sealed Classes

1. Control Over Inheritance: Ensures that the class hierarchy remains controlled and
predictable.
2. Exhaustiveness Checking: Helps the compiler perform exhaustive checking, which
is useful for pattern matching and switch expressions.
3. Enhanced Design: Provides a clear and well-defined class hierarchy, improving the
design and maintenance of APIs and libraries.

Use Cases for Sealed Classes

 Defining Fixed Sets of Related Classes: When you have a fixed set of related classes
and want to ensure no other classes can extend your base class.
 Enum-Like Structures: When you need more complex behaviour than enums but
still want to restrict the set of possible types.
 Exhaustive Pattern Matching: In combination with pattern matching and switch
expressions, sealed classes allow for exhaustive checks at compile time.

32

You might also like