Developpez.com - Rubrique Java

Le Club des Développeurs et IT Pro

Développer un Switch/Case en programmation fonctionnelle avec Java 8

Un tutoriel de François-Xavier Robin

Le 2020-01-27 12:18:25, par Mickael Baron, Rédacteur
Bonjour,

François-Xavier Robin nous propose une façon d'écrire en Java 8 le switch/case en programmation fonctionnelle en s’appuyant sur des lambdas.

Pour consulter le tutoriel : https://fxrobin.developpez.com/tutor...fonctionnelle/

N'hésitez pas à laisser des commentaires à la suite.

Mickael BARON pour l'équipe Java de Developpez.com

Retrouvez les meilleurs cours et tutoriels pour apprendre le développement avec le langage Java
  Discussion forum
4 commentaires
  • sergio_is_back
    Expert confirmé
    Bien que je développe plus en Java depuis de nombreuses années, je trouve ton implémentation intéressante et très instructive....
    ...
  • BugFactory
    Membre chevronné
    A la fois intéressant et utile. Un problème récurrent que j'ai eu avec la programmation fonctionnelle en Java est qu'elle devient illisible quand la logique implique des branchements complexes, voilà une bonne solution.

    Je modifierai SwitchExpression pour qu'elle étende Function. On pourrait ainsi s'en servir facilement avec Stream.map. Par exemple
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    List<String> reports = codes.stream()
        .map(
            Switch.defaultCase(code -> "Unknwown code " + code)
                .single(0, code -> "Success")
                // ...
                .build())
        .collect(Collectors.toList());
  • Gouyon
    Membre expérimenté
    Très bel exercice intellectuel.
  • fxrobin
    Membre chevronné
    Bonjour, et merci à vous tous pour vos retours positifs, ça fait plaisir.

    Envoyé par BugFactory

    Je modifierai SwitchExpression pour qu'elle étende Function. On pourrait ainsi s'en servir facilement avec Stream.map. Par exemple
    Merci pour cette idée, que je vais prendre en compte immédiatement.

    Disons que l'interface SwitchExpression était là aussi pour illustrer la pratique des différentes étapes (et états) quand on fait du method-chaining.

    Voici les modifs apportées (visibles sur GitHub, pas dans l'article):

    Code :
    1
    2
    3
    4
    public interface SwitchExpression <T, R> extends Function<T, R>
    {
       // unchanged
    }
    implémentation dans la classe Switch :

    Code :
    1
    2
    3
    4
    5
    @Override
    public R apply(T value)
    {
       return resolve(value);
    }
    et le test de son bon fonctionnement, ce qui a été le plus long à écrire ;-)

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    @Test
    public void StreamMapTest()
    {
            // switcher could have been written in the map method of the Stream.of(), 
            // but it's defined here for readability only.
            SwitchExpression<Integer, String> switcher = Switch.<Integer, String> start()
                                                               .defaultCase(v -> "ODD")
                                                               .predicate(v -> v % 2 == 0, v -> "EVEN")
                                                               .build();
    
            // just to check thats everything is fine
            assertNotNull(switcher, "cannot build the switcher");
    
            // let's run the Stream.map which will call the switcher.
            // the switcher implements Function <R, T> and its apply(T t) method.
            List<String> result = Stream.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
                                        .map(switcher)
                                        .collect(Collectors.toList());
    
            // few tests on the list
            assertNotNull(result, "the returned list is null, which is unacceptable!");
            assertEquals(10, result.size(), "the returned list size is wrong, which is totally unacceptable!");
            
            // then lets count the EVEN and the ODD to verify the switcher behavior inside a Stream.map().
            
            Map<String, Long> statistics = result.stream().collect(Collectors.groupingBy(String::toString, Collectors.counting()));
            
            assertNotNull(statistics, "the returned map is null, which is unbelievable!");
            assertEquals(5L, statistics.get("ODD").longValue());
            assertEquals(5L, statistics.get("EVEN").longValue());
            
            // it's working!
    }

    Je ferai une mise à jour de mon article sur mon blog directement :
    https://www.fxjavadevblog.fr/functional-switch/

    Merci encore pour cette belle idée !

    F.X.