Thread with Lambda expression

2020-03-01 07:47发布

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());
    }

}

3条回答
可以哭但决不认输i
2楼-- · 2020-03-01 08:28

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);
    }
});
查看更多
三岁会撩人
3楼-- · 2020-03-01 08:28

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());
查看更多
三岁会撩人
4楼-- · 2020-03-01 08:45

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);
查看更多
登录 后发表回答