// Interface fonctionnelle = une seule méthode abstraite
@FunctionalInterface // pas obligé mais informe le compilo
interface MonInterface {
  // Méthode abstraite
  public boolean f();

  // Méthode statique, n'est pas abstraite
  public static void uneMethodeStatique() {
    
  }

  // Factory
  public static MonInterface create() {
    return new MonInterface() {
      public boolean f() {
        return true;
      }
    };
  }

  // Implémentation par défaut
  default public boolean g() {
    return !f();
  }
}

interface A {
  default public String f() {
    return "A";
  }
}

interface B {
  default public String f() {
    return "B";
  }
}

class K implements A, B {
  // il faut redéfinir f pcq ya ambiguité entre le f de A et celui de B
  public String f() {
    return "";
  }

  public String toString() {
    return A.super.f() + B.super.f();
  }
}

class MyClass implements Runnable {
  @Override
  public void run() {
    System.out.println("hello");
  }
}

public class Main {
  public static void main(String[] args) {
    Runnable r = new MyClass();
    Thread t = new Thread(r);

    t.start();
  }
}

Objet foncteur

f : \begin{aligned} &\N^{2} \ra \N \\\\ &x, y \mapsto x+y \end{aligned}

Interface fonctionnelle

NE définit qu’une et une seule méthode abstraite.

Possibilité de faire des :

Lambda expression = fonction anonyme.

import java.util.Comparator;

interface Operator {
  public int calcul(int i, int j);
}

class Adder implements Operator {
  @Override
  public int calcul(int i, int j) {
    return i + j;
  }
}

interface I {
  public int f(int i);
}

interface HIHI {
  public Object create();
}

public class Main {
 public static void util(Operator o, int a, int b) {
    System.out.println(o.calcul(a, b));
  }
    
  public static void main(String[] args) {
    // Utilisation de la classe
    Operator add = new Adder();
    util(add, 4, 5);

    // On override la classe pour faire notre calcul
    Operator add2 = new Operator() {
      @Override
      public int calcul(int i, int j) {
        return i+j;
      }
    };
    util(add2, 4, 5);

    // On utilises une lambda expr pour faire notre calcul
    util((a, b) -> a+b, 4, 5); /* Ne va fonctionner que si `Operator`
                                * est une interface fonctionnelle. */

    // Même logique, on associe ça à f() parce que f() est la seule méthode de l'interface
    // Càd on est dans ue interface fonctionnelle.
    Operator mult = (int x, int y) -> x*y; // Ici il n'y a pas d'instanciation d'objet !

    // Types non obligatoire évidemment, l'inférence de type fonctionne
    Operator mult2 = (x, y) -> x*y; // Ici il n'y a pas d'instanciation d'objet !

    Operator add3 = (x, y) -> Integer.sum(x, y); // J'appelle la méthode de façon idiote
    Operator add4 = Integer::sum; /* Alors je peux directement appeller la méthode comme ça
                                   * = référence de méthode statique */
  
    Comparator<Integer> c = (i1, i2) -> i1.compareTo(i2); // J'appelle encore de façon bête
    Comparator<Integer> c2 = Integer::compareTo; /* très smart ce compilo... mmmhh...
                                                  * = référence de méthode d'instance */
    // Toujours la même logique
    Integer deux = 2;
    I ii = (x) -> deux.compareTo(x);
    I ii2 = deux::compareTo; /* référence de méthode d'instance désignée
                              * = "je veux la méthode sur cet objet là !" */

    // S'il n'y a qu'UN paramètre, pas besoin de parenthèses
    I i = (x) -> x + 1;

    // On peut aussi mettre un bloc d'instruction, dans ce cas là il faut un return
    I i2 = x -> { int tmp = x; return tmp + 1; };
  
    HIHI h = () -> new Object();
    HIHI h2 = Object::new; // Appel au constructeur de "Object"
    /* Fonctionne aussi si on a un constructeur avec plusieurs arguments !
     * Donc c'est tout bon même avec les surcharges de constructeurs */
  }
}

Trois choses dans le Java :

Les plus importants Dans java.util.function :

Consumer<T>

import java.util.List;
import java.util.function.Consumer;

public class Main {
  // Cette classe itère dans une collection (d'Integer) et donne à manger à sysout::println
  public static void util(List<Integer> l) {
    for (var i : l) {
      System.out.println(i);
    }
  }

  // Abstraction de util
  public static void utilabs(List<Integer> l, Consumer<Integer> c) {
    for (var i : l) {
      c.accept(i);
    }
  }

  // Donc on peut écrire util comme ça :
  public static void util2(List<Integer> l) {
    utilabs(l, x -> System.out.println(x));
    // que l'on peut aussi écrire :
    utilabs(l, System.out::println);
  }

  public static void main(String[] args) {
    Consumer<Integer> toScreen = System.out::println;
    Consumer<Integer> toNetwork = x -> System.out.println(">" + x + "<");

    Consumer<Integer> toScreenAndNetwork = x -> { toScreen.accept(x); toNetwork.accept(x); };
    // que l'on peut aussi écrire...
    Consumer<Integer> toScreenAndNetwork2 = toScreen.andThen(toNetwork);

  
    List<Integer> l = List.of(1, 2, 3, 4);
    utilabs(l, toScreenAndNetwork);
  }
}