Thread with Lambda expression
Asked Answered
A

3

19

I have an error at line 42 and 43 : Thread t1=new Thread(()->prod.test()); , Thread t2=new Thread(()->cons.test()); Unhandled exception type InterruptedException . If I try to quickfix it will created the try catch with an catch Exception, it will have the same error and will try to fix it in the same way continuing to surround it with try catch.

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

interface Predicate {
    public void test() throws InterruptedException;
}

class MyClass {
    int num = 0;
    Lock lock = new ReentrantLock();

    public void produce() throws InterruptedException {
        lock.lock();
        for (int i = 0; i < 1000; i++) {
            num++;
            Thread.sleep(1);
        }
        lock.unlock();
    }

    public void consume() throws InterruptedException {
        lock.lock();
        for (int i = 0; i < 1000; i++) {
            num--;
            Thread.sleep(1);
        }
        lock.unlock();
    }

    public int getNum() {
        return num;
    }

}

public class Main00 {

    public static void main(String[] args) throws InterruptedException {
        MyClass c = new MyClass();
        Predicate prod = c::produce;
        Predicate cons = c::consume;
        Thread t1 = new Thread(() -> prod.test());
        Thread t2 = new Thread(() -> cons.test());
        long start = System.currentTimeMillis();
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        long end = System.currentTimeMillis();
        System.out.println("time taken " + (end - start) + " num = "
                + c.getNum());
    }

}
Anastaciaanastas answered 14/7, 2015 at 20:35 Comment(0)
M
23

You have created a functional interface Predicate whose method is declared to throw an InterruptedException, which is a checked exception. However, you call test() in the body of a lambda expression as the parameter to the Thread constructor that takes a Runnable, whose run() method is not declared to throw any checked exceptions. Therefore, because the exception is not caught in the body, a compiler error occurs.

Incidentally, it may be confusing to name your own interface Predicate, because of the built-in functional interface java.util.function.Predicate whose functional method returns a boolean.

Because run() can't throw an Exception, you must catch the exception and handle it. You might log the exception and its stack trace. You might wrap the exception in a RuntimeException. Either way, catching the checked exception will allow the code to compile. Example:

Thread t1 = new Thread(() -> {
    try {
        prod.test();
    } catch (InterruptedException e) {
        // handle: log or throw in a wrapped RuntimeException
        throw new RuntimeException("InterruptedException caught in lambda", e);
    }
});
Masbate answered 14/7, 2015 at 21:0 Comment(2)
Exception 'java.lang.InterruptedException' is never thrown in the corresponding try block.Randy
@Randy This particular definition of Predicate declares test to throw InterruptedException, so it can be thrown and it must be caught.Masbate
S
11

If you intend on running a single method only with no arguments you can replace the lambda with a method reference.

For instance:

Thread t = new Thread(() -> {
        foo();
    });

can be more succinctly expressed as

Thread t = new Thread(this::foo);

To start it

t.start();
Sanative answered 12/1, 2019 at 4:36 Comment(1)
I'm assuming you still need to call t.start() (which isn't relevant to the question, but until I get my head around lambdas it's better I ask!).Yeeyegg
C
3

As @rgettman says, the name Predicate is unhappy... Anyways, you could take advantage of default methods in Java:

interface PredicateButPleaseChangeMyName {

    void test() throws InterruptedException;

    default void tryTest() {
       try {
          this.test();
       } catch (InterruptedException e) {
          // handle e (log or wrap in a RuntimeException)
       }
    }
}

Then, in your main method, simply create the threads by calling the default tryTest() method:

Thread t1 = new Thread(() -> prod.tryTest());
Thread t2 = new Thread(() -> cons.tryTest());
Chivy answered 14/7, 2015 at 21:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.