Arnaud Labourel
14 ou 26 novembre 2018
En Java, un projet peut être découpé en paquets (package
).
Les paquets permettent de :
Un paquet (package
) :
Java utilise l’arborescence de fichier pour retrouver les fichiers .class
.class
Les .class
du paquet com.univ_amu
doivent :
ClassPath
Le ClassPath
inclut :
-classpath path
)Le mot-clé package
permet de préciser le paquet des classes ou interfaces définies dans le fichier :
Java utilise l’arborescence pour retrouver le code des classes ou interfaces :
MyClass
est cherchée dans le fichier MyClass.java
MyClass.java
est cherché dans le dossier associé au paquet de MyClass
Dans l’exemple précédent, il est donc conseillé que le fichier :
MyClass.java
com/univ_amu
(Par défaut, la compilation crée MyClass.class
dans com/univ_amu
)Accessibilité :
On peut désigner une classe qui se trouve dans un autre paquet :
Vous pouvez également importer une classe :
package com.my_project;
import com.univ_amu.MyClass;
public class Main {
public static void main(String[] args) {
MyClass myClass = new MyClass();
}
}
Deux classes de deux paquets différents peuvent avoir le même nom :
java.util.List
et java.awt.List
Vous pouvez également importer toutes les classes d’un paquet :
package com.my_project;
import com.univ_amu.*;
public class Main {
public static void main(String[] args) {
MyClass myClass = new MyClass();
}
}
Remarques :
java.lang
est importé par défautDepuis Java 5, il est possible d’importer directement des méthodes ou attributs de classes (static
).
La syntaxe est la suivante :
Exemple :
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World!");
System.out.println(
"A circle with a diameter of 5 cm has");
System.out.println("a circumference of "
+ (Math.PI * 5) + " cm");
System.out.println("and an area of "
+ (Math.PI * Math.pow(2.5, 2))
+ " sq. cm");
}
}
import static java.lang.Math.PI;
import static java.lang.Math.pow;
import static java.lang.System.out;
public class HelloWorld {
public static void main(String[] args) {
out.println("Hello World!");
out.println(
"A circle with a diameter of 5 cm has");
out.println("a circumference of "
+ (PI * 5) + " cm");
out.println("and an area of "
+ (PI * pow(2.5, 2)) + " sq. cm");
}
}
Le fichier com/univ_amu/HelloWorld.java
:
package com.univ_amu;
public class HelloWorld {
public static void main(String[] arg) {
System.out.println("Hello world ! ");
}
}
$ javac com/univ_amu/HelloWorld.java
$ ls com/univ_amu
HelloWorld.java HelloWorld.class
$ java com.univ_amu.HelloWorld
Hello world !
Nommage des paquets :
com.google.gson
, com.oracle.jdbc
com.univ_amu
Fichier JAR (Java Archive) :
ClassPath
jar
) ou avec un IDEIl est possible de définir une classe à l’intérieur d’une autre (classe imbriquée ou nested class) :
public class LinkedList {
public static class Node {
private String data; private Node next;
public Node(String data, Node next) {
this.data = data; this.next = next;
}
}
}
Il est possible d’instancier la classe interne sans qu’une instance de LinkedList
existe car elle est statique :
Une classe non-imbriquée publique (public
) doit être dans un fichier portant son nom.
Fichier LinkedList.java
\(\Rightarrow\) erreur à la compilation :
Une classe imbriquée peut être publique et accessible depuis l’extérieur.
Il est également possible de la rendre privée à la classe LinkedList
:
public class LinkedList {
private static class Node {
private String data;
private /*LinkedList.*/Node next;
public Node(String data, Node next) {
this.data = data;
this.next = next;
}
}
}
Dans ce cas, seules les méthodes de LinkedList
pourront l’utiliser. Notez que des méthodes statiques définies dans LinkedList
peuvent également utiliser cette classe interne du fait qu’elle soit statique.
Exemple d’implémentation de méthodes dans la classe LinkedList
:
Exemple d’utilisation de la classe précédente :
Cet exemple produit la sortie suivante :
[c][b][a]
Une classe imbriquée statique ne peut accéder qu’aux champs et méthodes statiques de la classe qui la contient :
En revanche, si la classe interne n’est pas statique, elle peut accéder aux champs de classe qui la contient :
Java insère dans l’instance de Node
une référence vers l’instance de LinkedList
qui a permis de la créer :
Il est possible d’utiliser la méthode isFirst
dans LinkedList
:
Exemple d’utilisation de la classe précédente :
Cet exemple produit la sortie suivante :
[c,true][b,false][a,false]
class Greatest {
private String element;
public void add(String element) {
if (this.element==null ||
this.element.compareTo(element)<0)
this.element = element;
}
public String get() { return element; }
}
Comment rendre la classe Greatest
générique ?
Supposons que nous ayons les classes suivantes :
class Greatest<T extends Comparable<T>> {
/* ... */
public void add(T element) { /* ... */ }
public T get() { return element; }
}
class Card implements Comparable<Card> { /* ... */ }
class PrettyCard extends Card { /* ... */ }
Il n’est pas possible d’écrire les lignes suivantes car PrettyCard n’implémente pas l’interface Comparable<PrettyCard>
:
Supposons que nous ayons les classes suivantes :
class Greatest<T extends Comparable<? super T>> {
/* ... */
public void add(T element) { /* ... */ }
public T get() { return element; }
}
Il est possible d’écrire les lignes suivantes car PrettyCard
implémente l’interface Comparable<Card>
et Card super PrettyCard
:
Supposons que nous ayons les classes suivantes :
class Greatest<T extends Comparable<? super T>> {
/* ... */
public void add(T element) { /* ... */ }
public void addAll(List<T> list) {
for (T element : list) add(element);
}
}
Il n’est pas possible d’écrire les lignes suivantes :
Supposons que nous ayons les classes suivantes :
class Greatest<T extends Comparable<? super T>> {
/* ... */
public void add(T element) { /* ... */ }
public void addAll(List<? extends T> list) {
for (T element : list) add(element);
}
}
Il est maintenant possible d’écrire les lignes suivantes :
class Tools {
static <T extends Comparable<T>>
boolean isSorted(T[] array) {
for (int i = 0; i < array.length-1; i++)
if (array[i].compareTo(array[i+1]) > 0)
return false;
return true;
}
}
Exemple :
Méthode pour copier une liste src
vers une autre liste dest
:
static <T> void copy(List<? super T> dest, List<? extends T> src)
On suppose qu’on a une classe MovingPixel
qui étend Pixel
qui elle-même étend Point
.
On peut écrire :
extends
et super
Lorsqu’on a une collection d’objets de type T
:
En entrée/écriture, on veut donner des objets qui ont au moins tous les services des objets de type T
.
On doit donc donner des objets dont la classe étend T
: ? extends T
En sortie/lecture, on veut récupérer des objets qui ont au plus tous les services des objets de type T
.
On doit donc récupérer des objets qui sont étendu par la classe T
: ? super T
Supposons que nous ayons l’interface suivante :
Il est possible de :
Il est possible d’utiliser des attributs de la classe “externe” :
Il est possible d’utiliser des variables finales de la méthode :
Avec Java 8, il est possible d’écrire directement :
public class Window {
public Window() {
Button button = new Button("button");
button.addActionListener(
event -> System.out.println(event)
);
}
}
Explication : ActionListener possède une seule méthode donc on peut affecter une lambda expression à une variable de type ActionListener.
En Java 8, une interface n’ayant qu’une méthode abstraite est une interface fonctionnelle. Les quatre interfaces fonctionnelles suivantes (et plein d’autres) sont déjà définies :
Pour instancier une interface fonctionnelle, on peut utiliser une lambda expression :
L’interface suivante :
peut être instancier par :
MyFunctionalInterface fonc =
(arg1, arg2, arg2)
->/* expression définissant le résultat de myMethod */
Si T
est void
alors l’expression peut être void
comme un println
.
On considère une classe Person
avec deux attributs name
et age
et les getters et setters associés.
On a le droit d’écrire les lambda expressions suivantes en Java :
person -> person.getAge() >= 18
de type Predicate<Person>
person -> person.getName()
de type Function<Person,String>
name -> System.out.println(name)
de type Consumer<Person>
Dans un certain nombre de cas, une lambda expression se contente d’appeler une méthode ou un constructeur.
Il est plus clair dans ce cas de se référer directement à la méthode ou au constructeur.
Lambda expression | référence de méthode |
---|---|
x -> Math.sqrt(x) |
Math::sqrt |
name -> System.out.println(name) |
System.out::println |
person -> person.getName() |
Person::getName |
name -> new Person(name) |
Person::new |
Stream
= Abstraction d’un flux d’éléments sur lequel on veut faire des calculs
Ce n’est pas une Collection
d’élément car un Stream
ne contient pas d’élément
list.stream()
Files.lines(Path path)
IntStream.range(int start, int end)
persons
.stream()
.filter(person -> person.getAge() >= 18)
.map(person -> person.getName())
.forEach(name -> System.out.println(name));
Types des paramètres et retours des méthodes :
stream()
→ Stream<Person>
filter(Predicate<Person>)
→ Stream<Person>
map(Function<Person, String>)
→ Stream<String>
forEach(Consumer<String>)
Stream
Stream<E> filter(Predicate<? super E>)
: sélectionne si un élement reste dans le Stream
<R> Stream<R> map(Function<? super E, ? extends R)
: transforme les éléments du Stream
en leur appliquant une fonction
Stream<E> sorted(Comparator<? super E>)
: trie les éléments
Stream
long count()
: compte le nombre d’éléments
long sum()
: somme les éléments (entiers ou double)
Stream<E> forEach(Consumer<? super E>)
: Appele le consumer
pour chaque élément
allMatch(Predicate<? super E>)
: vrai si le prédicat est vrai pour tous les éléments
anyMatch(Predicate<? super E>)
: vrai si le prédicat est vrai pour au moins un élément
collect(Collectors.toList())
: crée une liste avec les éléments du Stream