web-dev-qa-db-fra.com

Fil avec expression Lambda

J'ai une erreur aux lignes 42 et 43: Thread t1=new Thread(()->prod.test());, Thread t2=new Thread(()->cons.test()); Type d'exception non gérée InterruptedException . Si j'essaie de procéder à la correction rapide, il créera la tentative try avec un catch Exception , le même message d'erreur s'affichera et il tentera de la réparer de la même manière en continuant de l'entourer avec 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());
    }

}
12
T4l0n

Vous avez créé une interface fonctionnelle Predicate dont la méthode est déclarée pour lancer une InterruptedException, qui est une exception vérifiée. Cependant, vous appelez test() dans le corps d'une expression lambda en tant que paramètre de le constructeur Thread qui prend un Runnable , dont la méthode run() n'est pas déclarée pour lancer les exceptions vérifiées . Par conséquent, étant donné que l'exception n'est pas interceptée dans le corps, une erreur du compilateur se produit.

Incidemment, il peut être déroutant de nommer votre propre interface Predicate, en raison de l'interface fonctionnelle intégrée Java.util.function.Predicate / dont la méthode fonctionnelle retourne une boolean.

Comme run() ne peut pas lancer Exception, vous devez catch l'exception et la gérer. Vous pouvez enregistrer l'exception et sa trace de pile. Vous pouvez envelopper l'exception dans une RuntimeException. Dans les deux cas, attraper l'exception vérifiée permettra au code de se compiler. Exemple:

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);
    }
});
13
rgettman

Comme @rgettman le dit, le nom Predicate est malheureux ... Quoi qu'il en soit, vous pouvez tirer parti des méthodes default en Java:

interface PredicateButPleaseChangeMyName {

    void test() throws InterruptedException;

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

Ensuite, dans votre méthode principale, créez simplement les threads en appelant la méthode par défaut tryTest():

Thread t1 = new Thread(() -> prod.tryTest());
Thread t2 = new Thread(() -> cons.tryTest());

Si vous envisagez d'exécuter une seule méthode sans aucun argument, vous pouvez remplacer le lambda par une référence de méthode.

Par exemple:

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

peut être plus succinctement exprimé comme 

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