AccueilActualités informatiqueLangage de programmation : Apache Groovy 4 adopte les nouveautés Java

Langage de programmation : Apache Groovy 4 adopte les nouveautés Java

Deux ans après Apache Groovy 3.0, la version 4 du langage de programmation est sortie. La nouvelle version principale du langage JVM (Java Virtual Machine) introduit quelques fonctionnalités du langage Java des dernières années, même si elles sont légèrement modifiées. En outre, elle se dote d’un langage de requête propre, GINQ, et mise sur la conception par contrat.

Au-delà des nouveautés linguistiques, la version fait ses adieux aux paquets legacy qui existaient en tant que doublons des paquets nouvellement introduits dans Groovy 3 pour l’interaction avec le Java Platform Module System (JPMS). Cette coexistence devait garantir une transition en douceur vers les nouvelles conventions. Les détails concernant les anciens et les nouveaux noms se trouvent dans les notes de publication de la version 3.0.

Sommaire

Java a introduit les Switch Expressions dans la version 13 en complément des Switch Statements et les a stabilisées dans Java 14. La variante de la construction de langage maintenant mise en œuvre dans Groovy s’inspire de l’approche de Java. Tandis que les Switch Statements ont pour chaque cas un case avec un : et le code qui s’ensuit, les expressions de commutation peuvent, entre autres, attribuer directement une valeur à une variable. Après le case est généralement suivie d’un ->. Beaucoup de switch-deviennent ainsi plus clairs :

// Switch Statement
def result
switch(i) {
  case 0: result = 'Null'; break
  case 1: result = 'Eins'; break
  case 2: result = 'Zwei'; break
  default: throw new IllegalStateException('unbekannt')
}

// Switch Expression
def result = switch(i) {
    case 0 -> 'Null'
    case 1 -> 'Eins'
    case 2 -> 'Zwei'
    default -> throw new IllegalStateException('unbekannt')
}

Derrière -> doit contenir exactement une seule expression. Il est toutefois possible de combiner plusieurs instructions dans un bloc entre accolades. Par ailleurs, il est possible de programmer des expressions Switch dans l’ancienne écriture à deux points. Pour cela, chaque cas doit avoir un yield pour attribuer la valeur à la variable. Le fait de mélanger les deux formes avec : et -> n’est pas autorisé.

Contrairement à Java, tous les cas ne doivent pas être couverts dans la mise en œuvre actuelle. Si aucun case-ne reflète pas la valeur et qu’il n’y a pas de default existe, Groovy ajoute implicitement null comme valeur par défaut. Cependant, des directives strictes sont probablement déjà en place pour une couverture obligatoire de tous les cas et l’évitement de null sont prévues.

Les classes scellées existent dans le monde Java depuis la version 15 et sont considérées comme stables depuis Java 17. Groovy permet désormais de sceller des classes, des interfaces et des traits afin de déterminer quels types peuvent être considérés comme enfants. Le scellement s’effectue à l’aide du mot-clé sealed ou l’annotation @Sealed. Les types d’enfants autorisés peuvent être explicitement définis via permits ou permittedSubclasses sont définis. De plus, le compilateur autorise implicitement les sous-types définis dans le même fichier.

En interaction avec Java à partir de la version 17 actuelle, Groovy crée le bytecode sous forme de classes scellées, compatibles avec celles de Java. Pour les anciennes variantes de Java, le compilateur Groovy reconnaît certes les types scellés, mais le compilateur Java les traite comme des types réguliers. Dans Groovy 4.0, les classes scellées sont marquées comme incubées. Il est donc potentiellement encore possible d’apporter des modifications à la mise en œuvre concrète.

Les enregistrements ont fait leur première apparition en Java 14 et sont considérés comme stables depuis Java 16. Ils servent de construction orientée objet pour stocker des valeurs simples sous forme de données immuables. Groovy connaît depuis un certain temps déjà l’annotation @Immutable pour les contenus immuables.

Avec la dernière version, Groovy introduit le mot-clé record et l’annotation @RecordType qui, en interaction avec Java à partir de la version 16, sont transposés en tant qu’enregistrements natifs. Comme pour les Sealed Types, une mise en œuvre émulée s’applique aux variantes antérieures de Java, qui se comportent certes de la même manière, mais que le compilateur Java ne reconnaît pas comme des enregistrements.

Une autre nouveauté marquée comme incubateur est le langage de requête Groovy-Integrated Query (GINQ). Il permet de créer des requêtes sur des collections de la même manière qu’avec SQL, comme le montre l’exemple de code suivant tiré des Release Notes :

from p in persons
leftjoin c in cities on p.city.name == c.name
where c.name == 'Shanghai'
select p.name, c.name as cityName

from p in persons
groupby p.gender
having p.gender == 'Male'
select p.gender, max(p.age)

from p in persons
orderby p.age in desc, p.name
select p.name

from n in numbers
where n > 0 && n <= 3
select n * 2

from n1 in nums1
innerjoin n2 in nums2 on n1 == n2
select n1 + 1, n2

La documentation de Groovy présente, outre la description de GINQ, d’autres exemples.

Également nouveau et incubateur est le module groovy.contractsqui introduit une programmation selon le principe du design by contract (DbC). Cette approche est issue du langage de programmation Eiffel et repose sur des sortes de contrats d’utilisation des interfaces qui doivent garantir l’interaction entre les différents modules du programme. Pour C++, les contrats étaient prévus pour C++20, mais il n’est pas certain qu’ils soient inclus dans le prochain C++23.

Les contrats du DbC définissent les pré-conditions et les post-conditions. L’appelant doit respecter les premières et l’appelé les secondes. Le troisième élément, les invariants, décrit les conditions qui doivent toujours être appliquées lors de l’exécution. Groovy propose des annotations spécifiques pour ces trois éléments. L’exemple de code suivant, tiré des Release Notes, en présente une mise en œuvre :

import groovy.contracts.*

@Invariant({ speed() >= 0 })
class Rocket {
    int speed = 0
    boolean started = true

    @Requires({ isStarted() })
    @Ensures({ old.speed < speed })
    def accelerate(inc) { speed += inc }

    def isStarted() { started }

    def speed() { speed }
}

def r = new Rocket()
r.accelerate(5)

Pour Groovy, il existe déjà depuis longtemps avec GContracts un projet externe pour le Design by Contract, qui n’est pas développé et qui est archivé.

D’autres nouveautés de Groovy 4, comme le JavaShell et les annotations POJO (Plain Old Java Object) pour une mise en œuvre plus légère des objets Groovy statiques, peuvent être consultées dans les notes de version. La page de téléchargement renvoie au code source ainsi qu’aux binaires pour différents systèmes d’exploitation.

Plus d'articles