java unit 3 part 4
java unit 3 part 4
@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.
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
@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.
@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.
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
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.
Module Name
It is a name of module and should follow the reverse-domain-pattern. Like we name packages,
e.g. com.javatpoint.
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. }
Output:
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.
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:
// 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.
}
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;
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);
};
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:
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.
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.
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
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";
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.
Syntax
Sealed classes and interfaces are defined using the sealed keyword followed by the permits
clause, which lists the permitted subclasses.
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;
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.
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.
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