Angle Bracket <> in Java with Examples Different types of Recursions in Java Java Lambda Filter Example Java Program for Shopping Bill Pythagorean Triplet with Given Sum Using Single Loop in Java TemporalAdjusters lastInMonth() method in Java with Examples ZIP API in Java Atomic reference in Java Digit Extraction in Java DRY (Don't Repeat Yourself) Principles in Java with Examples Empty array in Java Is main method compulsory in Java? Java I/O Operation - Wrapper Class vs Primitive Class Variables Java Program to Find the Perimeter of a Rectangle Java Thread Priority Java Type Erasure Need of Concurrent Collections in Java Nested ArrayList in Java Print Odd and Even Numbers by Two Threads in Java Square pattern in Java TemporalAdjusters next() method in Java with Examples What does start() function do in multithreading in Java Convert Number to Words Problem in Java Detect And Remove Cycle in a Single Linked List in Java Evolution of Interfaces in Java How to pad a String in Java Implementing Patricia Trie in Java Java Program to Find the Most Repeated Word in a Text File java.util.UUID class in Java ReadWriteLock Interface in Java Reference Data Types in Java Sort An Array According to The Count of Set Bits in Java Alternate Vowel and Consonant string in Java Built-in Exceptions in Java with Examples Capture the Pawns Problem in Java Collections.shuffle() Method in Java with Examples JDBC MySQL Localhost 3306 Alternate Vowel and Consonant string in Java Built-in Exceptions in Java with Examples Capture the Pawns Problem in Java Collections.shuffle() Method in Java with Examples Convert Number to Words Problem in Java Detect And Remove Cycle in a Single Linked List in Java Evolution of Interfaces in Java How to pad a String in Java Implementing Patricia Trie in Java Java Program to Find the Most Repeated Word in a Text File java.util.UUID class in Java ReadWriteLock Interface in Java Reference Data Types in Java Sort An Array According to The Count of Set Bits in Java JDBC MySQL Localhost 3306 Adding a Character as Thousands Separator to Given Number in Java Circular Primes in Java Equilibrium Index Problem in Java Java String regionMatches() Method with Examples LFU Cache Problem in Java Longest Repeating and Non-Overlapping Substring in Java Prefix Suffix Search in Java Product Array Puzzle Problem in Java Russian Doll Envelopes Problem in Java Second Most Repeated Word in a Sequence in Java Special Two-Digit Numbers in a Binary Search Tree in Java Swap Corner Words and Reverse Middle Characters in Java Toggle K bits Problem in Java Upside Down Binary Tree in Java Verbal Arithmetic Puzzle Problem in Java Insert a String into another String in Java Print Shortest Path to Print a String on Screen in Java Search Insert Position in Java BST Sequences in Java Burrows - Wheeler Data Transform Algorithm in Java Convert BST to Min Heap in Java Fibonacci Sum in Java Get name of current method being executed in Java Keith number in Java Longest Even Length Substring in Java Saint-Exupery Numbers in Java Standard practice for protecting sensitive data in Java application Strobogrammatic number in Java Types of Methods in Java Programming Valid Number Problem in Java Boggle Search Problem in Java Convert Java Object to JSON String using Jackson API Generate Random String in Java Java Program to Determine the Unicode Code Point at Given Index in Strin Java 18 snippet tags Jumping Numbers in Java Junction Numbers in Java Find Four Elements that Sums to a given value in Java How to print string vertically in Java How to remove in string in Java Three-Way Partition Problem in Java Apocalyptic Number in Java Check if the given two matrices are mirror images of one another in Java Duplicate Characters Problem in Java Duplicate Parenthesis Problem in Java Sum of Minimum and Maximum Elements of all Subarrays of Size K in Java Triple Shift Operator in Java Valid Pairing of Numbers in Java Valid Sudoku problem in Java Java Cipher Class Kth Missing Positive Number in Java Largest Square Matrix Problem in Java Length of the longest substring without repeating characters in Java Minimum Cost to Make String Valid Problem in Java Ordered pair in Java Range Addition Problem in Java

Angle Bracket &lt;> in Java with Examples

In Java, angle brackets (<>) are used as part of the syntax for generics. Generics were introduced in Java 5 to provide a way to create classes, interfaces, and methods that operate on a specified type without compromising type safety. The angle brackets are used to declare and define generic types, allowing classes and methods to work with different types in a type-safe manner.

Various uses of Angle Bracket <>

1. Generic Classes

Generic classes allow you to declare a class with one or more type parameters. These type parameters act as placeholders for actual data types that will be specified when creating an instance of the class. This enables the creation of classes that can work with various types without sacrificing type safety.

Filename: Box<T>.java

public class Box<T> {

    private T value;

    public Box(T value) {

        this.value = value;

    }

    public T getValue() {

        return value;

    }

    public void setValue(T value) {

        this.value = value;

    }

    public static void main(String[] args) {

        // Creating a Box for Integer

        Box<Integer> integerBox = new Box<>(42);

        System.out.println("Integer Value: " + integerBox.getValue());

        // Creating a Box for String

        Box<String> stringBox = new Box<>("Hello, Generics!");

        System.out.println("String Value: " + stringBox.getValue());

    }

}

Output:

Integer Value: 42

String Value: Hello, Generics!

Explanation

The Box class is declared with a type parameter T. The value field is of type T, allowing it to hold values of any type. The constructor accepts an initial value of type T. Getter and setter methods (getValue and setValue) operate on the generic type T. In the main method, we create instances of the Box class with specific types (Integer and String).

2. Generic Methods

In Java, generic methods allow you to create methods that work with different types while maintaining type safety. Like generic classes, generic methods use type parameters to specify and enforce the types they work with. This enables you to write methods that can operate on a variety of data types without sacrificing compile-time type checking.

Filename: GenericMethodExample.java

public class GenericMethodExample {

    public static <T extends Comparable<T>> T findMax(T[] array) {

        if (array == null || array.length == 0) {

            return null; // Return null for an empty array

        }

        T max = array[0];

        for (T element : array) {

            if (element.compareTo(max) > 0) {

                max = element;

            }

        }

        return max;

    }

    public static void main(String[] args) {

        // Example with integers

        Integer[] intArray = {3, 1, 4, 1, 5, 9, 2, 6, 5};

        Integer maxInt = findMax(intArray);

        System.out.println("Max Integer: " + maxInt);

        // Example with strings

        String[] stringArray = {"apple", "orange", "banana", "kiwi"};

        String maxString = findMax(stringArray);

        System.out.println("Max String: " + maxString);

    }

}

Output:

Max Integer: 9

Max String: orange

Explanation

The findMax method is declared as a generic method using the <T> syntax before the return type. The type parameter T is constrained to implement the Comparable<T> interface, ensuring that the elements in the array can be compared.

The method uses the type parameter T for the array type and the comparison of elements. In the main method, we demonstrate using the generic method with both an array of integers and an array of strings.

3. Bounded Wildcards

In Java, bounded wildcards are a feature of generics that allow you to specify restrictions on the types that can be used as arguments in generic classes or methods. Bounded wildcards are denoted by the use of the wildcard character (?) along with the extends or super keywords. These wildcards are useful when you want to accept a range of types without losing type safety.

Filename: WildcardExample.java

import java.util.ArrayList;

import java.util.List;

public class WildcardExample {

    // Upper Bounded Wildcard: accepts a list of any type that is a subtype of Number

    public static double sumOfList(List<? extends Number> numbers) {

        double sum = 0.0;

        for (Number number : numbers) {

            sum += number.doubleValue();

        }

        return sum;

    }

    // Lower Bounded Wildcard: adds integers to a list or its supertypes

    public static void addIntegers(List<? super Integer> numbers) {

        numbers.add(1);

        numbers.add(2);

        numbers.add(3);

    }

    public static void main(String[] args) {

        // Upper Bounded Wildcard Example

        List<Integer> integers = new ArrayList<>(List.of(1, 2, 3, 4, 5));

        List<Double> doubles = new ArrayList<>(List.of(1.1, 2.2, 3.3, 4.4, 5.5));

        double sumOfIntegers = sumOfList(integers);

        System.out.println("Sum of Integers: " + sumOfIntegers);

        double sumOfDoubles = sumOfList(doubles);

        System.out.println("Sum of Doubles: " + sumOfDoubles);

        // Lower Bounded Wildcard Example

        List<Number> numberList = new ArrayList<>(List.of(10, 20, 30));

        addIntegers(numberList);

        System.out.println("List after adding integers: " + numberList);

    }

}

Output:

Sum of Integers: 15.0

Sum of Doubles: 16.5

List after adding integers: [10, 20, 30, 1, 2, 3]

Explanation

sumOfList method takes a list of any type that extends Number (List<? extends Number>) and calculates the sum of its elements. It uses an upper-bounded wildcard to ensure that the list can contain elements of type Number or its subtypes.

addIntegers method takes a list of any type that is a supertype of Integer (List<? super Integer>) and adds integer values to it. It uses a lower-bounded wildcard to allow the list to be of type Integer or any of its supertypes.

4. Creating Parameterized Types

Creating parameterized types allows you to write code that can work with a variety of data types without sacrificing type safety. This is achieved by introducing a type parameter, which acts as a placeholder for the actual type that will be specified when using the class or method. Parameterized types are particularly useful when working with collections or algorithms that should be independent of the specific data types they operate on.

Filename: Box<T>.java

public class Box<T> {

    private T value;

    public Box(T value) {

        this.value = value;

    }

    public T getValue() {

        return value;

    }

    public static <E> void printArray(E[] array) {

        for (E element : array) {

            System.out.print(element + " ");

        }

        System.out.println();

    }

    public static void main(String[] args) {

        // Parameterized Class Example

        Box<Integer> integerBox = new Box<>(42);

        System.out.println("Integer Value: " + integerBox.getValue());

        // Parameterized Method Example

        String[] stringArray = {"Java", "Generics", "Example"};

        printArray(stringArray);

    }

}

Output:

Integer Value: 42

Java Generics Example

Explanation

The Box class is parameterized with a type parameter T. It has a constructor that takes a value of type T and a method getValue that returns the stored value. The printArray method is a parameterized method that can print an array of any type (E). It uses a type parameter to achieve this flexibility.

In the main method, Box<Integer> is instantiated, creating a Box that holds an integer value. The printArray method is called with a String array.

5. Recursive Generics

Recursive generics enable the creation of data structures or classes where the type parameter is used recursively within the class definition. This is common in scenarios where a class or data structure needs to reference instances of the same class with the same type parameter.

Filename: BinaryTree<T>.java

public class BinaryTree<T> {

    private T data;

    private BinaryTree<T> left;

    private BinaryTree<T> right;

    public BinaryTree(T data) {

        this.data = data;

        this.left = null;

        this.right = null;

    }

    public BinaryTree(T data, BinaryTree<T> left, BinaryTree<T> right) {

        this.data = data;

        this.left = left;

        this.right = right;

    }

    public T getData() {

        return data;

    }

    public BinaryTree<T> getLeft() {

        return left;

    }

    public BinaryTree<T> getRight() {

        return right;

    }

    public static void main(String[] args) {

        // Creating a binary tree

        BinaryTree<String> tree = new BinaryTree<>("A",

                new BinaryTree<>("B",

                        new BinaryTree<>("D"),

                        new BinaryTree<>("E")),

                new BinaryTree<>("C",

                        new BinaryTree<>("F"),

                        new BinaryTree<>("G")));

        // Example usage

        System.out.println("Root: " + tree.getData());

        System.out.println("Left Child: " + tree.getLeft().getData());

        System.out.println("Right Child: " + tree.getRight().getData());

    }

}

Output:

Root: A

Left Child: B

Right Child: C

Explanation

The BinaryTree class is defined with a generic type parameter T. The class has three fields: data of type T representing the data of the node, and left and right of type BinaryTree<T> representing the left and right subtrees. Two constructors are provided—one for creating a leaf node and another for creating a node with left and right subtrees.

Getter methods (getData, getLeft, and getRight) allow access to the data and subtrees. In the main method, a binary tree is created with String data. The example usage prints information about the root and its left and right children.

Conclusion

In conclusion, the use of angle brackets in Java generics is fundamental to creating flexible, type-safe, and reusable code. Generics enhance the expressiveness of Java programs and contribute to the development of robust and maintainable software. The combination of generics, wildcards, and other features introduced by angle brackets reflects Java's commitment to providing a strong, statically-typed language that allows developers to write more generic and adaptable code.