Advanced Java Concepts

Welcome to the final part of the Learn Java series! In this section, we will explore some advanced Java concepts that are crucial for mastering the language. We will cover topics such as concurrency, generics, lambda expressions, and streams. These concepts will help you write more efficient, scalable, and modern Java applications.

Concurrency

Concurrency allows multiple tasks to run simultaneously, improving the efficiency and performance of your applications. Java provides several ways to handle concurrency:

Threads

In Java, you can create and manage threads using the Thread class or implementing the Runnable interface. Here’s an example of creating and running a thread:

class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("Thread is running.");
    }
}

public class Main {
    public static void main(String[] args) {
        Thread thread = new Thread(new MyRunnable());
        thread.start();
    }
}

This code defines a class MyRunnable that implements Runnable and overrides the run() method. In the Main class, a Thread object is created with an instance of MyRunnable and started.

Executors

Executors provide a higher-level API for managing and controlling thread execution. Here’s an example using the ExecutorService:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Main {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(2);

        executor.submit(() -> {
            System.out.println("Task 1 is running.");
        });

        executor.submit(() -> {
            System.out.println("Task 2 is running.");
        });

        executor.shutdown();
    }
}

In this example, an ExecutorService is created with a fixed thread pool of 2 threads. Two tasks are submitted to the executor, and then the executor is shut down.

Generics

Generics allow you to define classes, interfaces, and methods with type parameters. This enables type safety and code reusability. Here’s an example of a generic class:

public class Box {
    private T item;

    public void setItem(T item) {
        this.item = item;
    }

    public T getItem() {
        return item;
    }
}

public class Main {
    public static void main(String[] args) {
        Box stringBox = new Box<>();
        stringBox.setItem("Hello Generics");

        System.out.println(stringBox.getItem());  // Output: Hello Generics
    }
}

The Box class is a generic class that can hold an item of any type T. In the Main class, a Box object is created with the type parameter String.

Lambda Expressions

Lambda expressions provide a concise way to write anonymous methods, primarily used with functional interfaces. Here’s an example of using a lambda expression:

@FunctionalInterface
interface MathOperation {
    int operate(int a, int b);
}

public class Main {
    public static void main(String[] args) {
        MathOperation addition = (a, b) -> a + b;
        System.out.println("Result: " + addition.operate(5, 3));  // Output: Result: 8
    }
}

In this example, MathOperation is a functional interface with a single method operate. A lambda expression is used to provide an implementation for the operate method.

Streams

Streams provide a modern way to process sequences of elements (e.g., collections) using functional-style operations. Here’s an example of using streams to filter and process a list of numbers:

import java.util.Arrays;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

        numbers.stream()
               .filter(n -> n % 2 == 0)
               .map(n -> n * n)
               .forEach(System.out::println);
    }
}

In this example, a list of numbers is converted into a stream. The stream filters out odd numbers, squares the remaining even numbers, and prints each result.

Conclusion

In this lesson, we explored several advanced Java concepts, including concurrency, generics, lambda expressions, and streams. Mastering these topics will enable you to write more efficient, scalable, and modern Java applications. Continue practicing and experimenting with these concepts to deepen your understanding and enhance your Java programming skills.