Generics

What are Generics?

Generics allow you to define classes, interfaces, and methods with a placeholder for types. They enable you to write more flexible and type-safe code.

Basic Syntax

  • Generic Class:

      public class Box<T> {
        private T value;
    
        public void set(T value) {
            this.value = value;
        }
    
        public T get() {
            return value;
        }
    }
      
  • Generic Method:

      public <T> void printArray(T[] array) {
        for (T element : array) {
            System.out.println(element);
        }
    }
      

Annotations

What are Annotations?

Annotations provide metadata about your code, which can be used by the compiler or at runtime for various purposes such as configuration or code analysis.

Common Annotations

  • @Override: Indicates that a method is intended to override a method in a superclass.
  • @Deprecated: Marks a method or class as deprecated, meaning it should no longer be used.
  • @SuppressWarnings: Suppresses specified compiler warnings.

Custom Annotations

  • Define an Annotation:
  @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyCustomAnnotation {
    String value() default "";
}
  
  • Use an Annotation:
  @MyCustomAnnotation("Example")
public void myMethod() {
    // Method implementation
}
  

Lambda Expressions

What are Lambda Expressions?

Lambda expressions provide a clear and concise way to represent one method interface using an expression. They are commonly used to implement functional interfaces.

Syntax

  • Basic Lambda Expression:
  (parameters) -> expression
  
  • Example:
  // Functional interface
@FunctionalInterface
interface MathOperation {
    int operate(int a, int b);
}

// Lambda expression
MathOperation add = (a, b) -> a + b;
System.out.println(add.operate(5, 3)); // Output: 8
  

Stream API

What is the Stream API?

The Stream API provides a way to process sequences of elements (e.g., collections) in a functional style. It supports operations such as filtering, mapping, and reducing.

Basic Operations

  • Create a Stream:
  List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream = list.stream();
  
  • Intermediate Operations:
  Stream<String> filteredStream = stream.filter(s -> s.startsWith("a"));
  
  • Terminal Operations:
  filteredStream.forEach(System.out::println); // Output: a
  

Java Modules (Java 9+)

What are Java Modules?

Java Modules allow you to modularize your code, improving maintainability and encapsulation. They provide a way to group related packages and control their visibility.

Basic Syntax

  • Module Declaration:
  module com.example.myapp {
    requires java.sql;
    exports com.example.myapp.services;
}
  
  • Module Info File:

    • The module-info.java file should be placed in the root directory of your module.

Reflection API

What is the Reflection API?

The Reflection API allows you to inspect and manipulate classes, methods, and fields at runtime. It provides the ability to discover information about classes and objects dynamically.

Basic Operations

  • Get Class Information:
  Class<?> clazz = Class.forName("java.lang.String");
System.out.println(clazz.getName()); // Output: java.lang.String
  
  • Invoke Methods:
  Method method = clazz.getMethod("length");
int length = (int) method.invoke("Hello");
System.out.println(length); // Output: 5
  
  • Access Fields:
  Field field = clazz.getField("CASE_INSENSITIVE_ORDER");
Object fieldValue = field.get(null);
System.out.println(fieldValue);
  

Summary

  • Generics: Provide type safety and flexibility.
  • Annotations: Add metadata to your code.
  • Lambda Expressions: Simplify the implementation of functional interfaces.
  • Stream API: Process data sequences in a functional style.
  • Java Modules: Modularize and encapsulate code (Java 9+).
  • Reflection API: Inspect and manipulate classes at runtime.