-> Operator in Java

The -> operator in Java is used to define lambda expressions
It separates the parameters (on the left) from the body (on the right) of the lambda expression. Lambda expressions provide a concise way to implement functional interfaces.

Example: Lambda Expression

// Using a lambda expression to implement Runnable
Runnable r = () -> System.out.println("Running...");
r.run();


public class RunnableComparison {
  public static void main(String[] args) {

    // ---------------- OLD WAY (Pre-Java 8) ----------------
    Runnable oldWay = new Runnable() {
      @Override
      public void run() {
        System.out.println("Running... (Old Way)");
      }
    };
    oldWay.run();

    // ---------------- NEW WAY (Java 8+ Lambda) ----------------
    Runnable lambdaWay = () -> System.out.println("Running... (Lambda Way)");
    lambdaWay.run();
  }
}


In this example,

() represents no parameters, and the body System.out.println("Running..."); is executed when run() is called.

Syntax

The general syntax of a lambda expression is:
(parameters) -> { body }


  • Parameters: Can be omitted if there’s only one parameter and no type declaration.
  • Body: Can be a single statement or a block of code.

Example: Functional Interface

@FunctionalInterface
interface Calculator {
  int calculate(int a, int b);
}
public class Main {
  public static void main(String[] args) {
    // Lambda implementing Calculator interface
    Calculator add = (a, b) -> a + b;
    System.out.println("Sum: " + add.calculate(5, 3)); // Output: Sum: 8
  }
}

Key Points

  • Lambda expressions are primarily used with functional interfaces (interfaces with a single abstract method).
  • They simplify code by eliminating the need for anonymous inner classes.
  • Commonly used in Java Streams and Collections for operations like filtering, mapping, and reducing.

Limitations

  • Lambdas cannot access non-final local variables.
  • Overuse can make code harder to read if not used judiciously.

💡 Tip: Lambdas work only with functional interfaces (interfaces with exactly one abstract method), such as RunnableCallableComparator, etc.

If you want, I can also show you how to run these in separate threads so you can see them in action concurrently.


Additional example

public class RunnableThreadExample {
  public static void main(String[] args) {

    // -------- OLD WAY (Pre-Java 8) --------
    Thread oldThread = new Thread(new Runnable() {
      @Override
      public void run() {
        System.out.println("Running in a thread... (Old Way)");
      }
    });
    oldThread.start(); // Starts a new thread

    // -------- NEW WAY (Java 8+ Lambda) --------
    Thread lambdaThread = new Thread(() -> 
      System.out.println("Running in a thread... (Lambda Way)")
    );
    lambdaThread.start(); // Starts a new thread

    // Optional: Wait for both threads to finish
    try {
      oldThread.join();
      lambdaThread.join();
    } catch (InterruptedException e) {
      System.err.println("Thread interrupted: " + e.getMessage());
      Thread.currentThread().interrupt(); // Restore interrupt status
    }

    System.out.println("Both threads have finished execution.");
  }
}


How it works:

Old Way

  • Create a Thread by passing an anonymous inner class implementing Runnable.
  • Override run() to define the task.

Lambda Way

  • Pass a lambda expression directly to the Thread constructor.
  • Much shorter and cleaner.

Thread Execution

  • start() launches the thread asynchronously.
  • join() ensures the main thread waits for both threads to finish.


public class RunnableThreadConcurrentExample {
    public static void main(String[] args) {

        // -------- OLD WAY (Pre-Java 8) --------
        Thread oldThread = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 1; i <= 5; i++) {
                    System.out.println("[Old Way] Message " + i);
                    try {
                        Thread.sleep(500); // Sleep for 0.5 seconds
                    } catch (InterruptedException e) {
                        System.err.println("Old thread interrupted.");
                        Thread.currentThread().interrupt();
                        break;
                    }
                }
            }
        });

        // -------- NEW WAY (Java 8+ Lambda) --------
        Thread lambdaThread = new Thread(() -> {
            for (int i = 1; i <= 5; i++) {
                System.out.println("[Lambda Way] Message " + i);
                try {
                    Thread.sleep(500); // Sleep for 0.5 seconds
                } catch (InterruptedException e) {
                    System.err.println("Lambda thread interrupted.");
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        });

        // Start both threads
        oldThread.start();
        lambdaThread.start();

        // Wait for both threads to finish
        try {
            oldThread.join();
            lambdaThread.join();
        } catch (InterruptedException e) {
            System.err.println("Main thread interrupted.");
            Thread.currentThread().interrupt();
        }

        System.out.println("Both threads have finished execution.");
    }
}
  • What you’ll see when running:Both threads will print messages interleaved (order may vary each run).
  • Thread.sleep(500) simulates work and makes the concurrency visible.
  • start() is used (not run()), so both threads run in parallel.

💡 Key takeaway:

  • run() → Executes in the current thread (no concurrency).
  • start() → Launches a new thread and calls run() internally.



← Back to Learning Journey