Java Advanced Topics Study Notes

Table of Contents

Annotations

Annotations in Java are like labels or notes you add to your code. They give extra info to the compiler, tools, or frameworks. They don't change how the code works but help in understanding or processing the code better. Introduced in Java 5, they are widely used in modern applications like web development, frameworks (Spring, Hibernate), and Android.

What Are Annotations?

Simple Example:
class Parent {
    void show() {
        System.out.println("Parent show");
    }
}

class Child extends Parent {
    @Override  // This annotation checks if we're correctly overriding
    void show() {
        System.out.println("Child show");
    }
}

Here, @Override tells the compiler: "I'm changing the parent's method." If you spell show wrong, it warns you.

Built-in Annotations

Detailed Explanation with Code

1. @Override

class Animal {
    void sound() {
        System.out.println("Animal sound");
    }
}

class Dog extends Animal {
    @Override
    void sound() {  // compiler ensures method matches parent
        System.out.println("Dog barks");
    }
}

Why use? Prevents mistakes. Without @Override, if you accidentally write sounds() instead of sound(), it won’t override – just create a new method.

2. @Deprecated

class OldCode {
    @Deprecated
    void oldMethod() {
        System.out.println("Old logic");
    }
}

class Test {
    public static void main(String[] args) {
        OldCode oc = new OldCode();
        oc.oldMethod();  // Compiler shows warning
    }
}

Why use? Tells other developers: "Don’t use this method anymore, there’s a better way." Useful when updating libraries or frameworks.

3. @SuppressWarnings

import java.util.*;

class WarningExample {
    @SuppressWarnings("unchecked")
    void demo() {
        List list = new ArrayList(); // Raw type (usually gives warning)
        list.add("Hello");
        System.out.println(list.get(0));
    }
}

Why use? Sometimes warnings are unnecessary. This annotation hides them, but use carefully — it may hide real issues.

Other Useful Annotations

In easy words: Annotations are helpful tags that make code smarter, cleaner, and less error-prone. They also reduce boilerplate in frameworks like Spring and Hibernate.

RegEx (Regular Expressions)

RegEx is used to find, match, or replace parts of strings using patterns. In Java, it is available in the java.util.regex package (classes: Pattern and Matcher).

Basics

Example: Find numbers in text
import java.util.regex.*;

public class Main {
    public static void main(String[] args) {
        String text = "I have 5 apples and 10 oranges.";
        Pattern p = Pattern.compile("\\d+");  // pattern for numbers
        Matcher m = p.matcher(text);

        while (m.find()) {
            System.out.println(m.group());  // prints 5 then 10
        }
    }
}

Useful Methods

Example: Check Email
String email = "test@example.com";
if (email.matches("^[\\w.-]+@[\\w.-]+\\.[a-z]{2,}$")) {
    System.out.println("Valid email");
}

Common Uses: Form validation (emails, phone numbers), extracting data, search & replace.

In easy words: RegEx is a smart search tool for strings. Start with simple rules like \\d for numbers or \\w for words.

Threads

Threads let your Java program do many tasks at the same time, like multitasking. This is concurrency. Uses java.lang.Thread and java.util.concurrent.

Basics

class MyTask extends Thread {
    public void run() {  // Code here runs in thread
        System.out.println("Task running");
    }
}
MyTask t = new MyTask();
t.start();  // Start it

2. Use Runnable (better):

class MyRun implements Runnable {
    public void run() {
        System.out.println("Run task");
    }
}
Thread t = new Thread(new MyRun());
t.start();

Thread Life

thred lifecycle

Key Methods

Sharing Data Safely (Synchronization)

int count = 0;
synchronized void add() {
    count++;
}
import java.util.concurrent.locks.*;
Lock lock = new ReentrantLock();
lock.lock();
count++;
lock.unlock();

Lambda Expressions

Lambdas were introduced in Java 8. They are a short way to write code (functions) without creating a full class. They work only with Functional Interfaces (an interface with exactly one abstract method).

Basics

Simple Example:
@FunctionalInterface
interface Add {
    int sum(int a, int b);
}

public class Main {
    public static void main(String[] args) {
        Add adder = (a, b) -> a + b;   // Lambda instead of writing a class
        System.out.println(adder.sum(3, 4));  // Output: 7
    }
}

Where to Use Lambdas?

In easy words: Lambdas make code shorter, cleaner, and are used a lot in modern Java (collections, streams, events).

Sorting in Java

Sorting means arranging data in order (like A→Z or small→big). In Java, sorting can be done in two ways:

Basics

1. Comparable (Natural Sorting)

If you want objects to be sorted in their natural order (like names alphabetically), the class should implement Comparable.

class Fruit implements Comparable {
    String name;
    Fruit(String n) { name = n; }

    @Override
    public int compareTo(Fruit other) {
        return this.name.compareTo(other.name); // A-Z order
    }
}

List fruits = new ArrayList<>();
fruits.add(new Fruit("Banana"));
fruits.add(new Fruit("Apple"));
fruits.add(new Fruit("Mango"));

Collections.sort(fruits);  // Sorts by name

Why? Comparable is used when the class itself has a default way to compare objects.

2. Comparator (Custom Sorting)

If you want different ways to sort, use Comparator.

Comparator byLength = 
    (f1, f2) -> Integer.compare(f1.name.length(), f2.name.length());

fruits.sort(byLength);  // Sorts by name length

Why? Comparator is flexible – you can define multiple custom sorting rules without changing the class.

Simple Example

Sorting numbers in descending order:

List nums = Arrays.asList(3, 1, 4);
nums.sort(Comparator.reverseOrder());  // [4, 3, 1]
In easy words: - Use Comparable for natural/default order. - Use Comparator for custom rules (like by length, reverse, etc).

Interview Questions and Tips

Questions (Covering All Topics)

  1. Annotations: What is @Override? Give example. (Explain it checks overriding.)
  2. Annotations: How to make custom annotation with runtime retention?
  3. RegEx: Write pattern for valid phone: (123) 456-7890.
  4. RegEx: Explain difference between greedy and lazy quantifiers.
  5. Threads: Difference between Thread and Runnable?
  6. Threads: What is synchronization? Why needed?
  7. Threads: Explain deadlock with example.
  8. Lambda: Write lambda for sorting list by length.
  9. Lambda: What is functional interface?
  10. Sorting: Difference between Comparable and Comparator?
  11. Sorting: How to sort objects by multiple fields?

Tips