Qu'est ce qu'une crue de type et pourquoi ne pas l'utiliser?
Questions:
- que sont les types bruts en Java, et pourquoi j'entends souvent qu'ils ne devraient pas être utilisés dans le nouveau code?
- Quelle est l'alternative si nous ne pouvons pas utiliser les types bruts, et comment est-ce mieux?
14 réponses
Qu'est-ce qu'un type brut?
la spécification Java language définit un type brut comme suit:
JLS 4.8 types bruts
un type brut est défini comme suit:
le type de référence qui est formé en prenant le nom d'une déclaration de type générique sans un argument de type accompagnant liste.
un type de tableau dont le type d'élément est un type brut.
type de membre non
static
type brutR
qui n'est pas hérité d'une superclasse ou d'une surfac e deR
.
voici un exemple pour illustrer:
public class MyType<E> {
class Inner { }
static class Nested { }
public static void main(String[] args) {
MyType mt; // warning: MyType is a raw type
MyType.Inner inn; // warning: MyType.Inner is a raw type
MyType.Nested nest; // no warning: not parameterized type
MyType<Object> mt1; // no warning: type parameter given
MyType<?> mt2; // no warning: type parameter given (wildcard OK!)
}
}
ici, MyType<E>
est un type paramétré ( JLS 4.5 ). Il est courant de se référer familièrement à ce type comme simplement MyType
pour faire court, mais techniquement le nom est MyType<E>
.
mt
a un type brut (et génère un avertissement de compilation) par le premier point de la définition ci-dessus; inn
a également un type brut par le troisième point de la définition.
MyType.Nested
n'est pas un type paramétré, même si c'est un type de membre d'un type paramétré MyType<E>
, parce que c'est static
.
mt1
, et mt2
sont tous deux déclarés avec des paramètres de type réels, donc ils ne sont pas des types bruts.
Qu'est-ce que les types crus ont de si spécial?
essentiellement, les types crus se comportent comme ils étaient avant que les génériques ont été introduits. C'est-à-dire que ce qui suit est entièrement légal au moment de la compilation.
List names = new ArrayList(); // warning: raw type!
names.add("John");
names.add("Mary");
names.add(Boolean.FALSE); // not a compilation error!
le code ci-dessus fonctionne très bien, mais supposons que vous ayez aussi le suivant:
for (Object o : names) {
String name = (String) o;
System.out.println(name);
} // throws ClassCastException!
// java.lang.Boolean cannot be cast to java.lang.String
maintenant nous avons des problèmes à l'exécution, parce que names
contient quelque chose qui n'est pas un instanceof String
.
probablement, si vous voulez que names
contienne seulement String
, vous pourrait peut-être encore utiliser un type brut et vérifier manuellement chaque add
vous-même, puis moulé manuellement à String
chaque article de names
. encore mieux , mais N'est pas d'utiliser un type brut et laisser le compilateur faire tout le travail pour vous , en exploitant la puissance de Java generics.
List<String> names = new ArrayList<String>();
names.add("John");
names.add("Mary");
names.add(Boolean.FALSE); // compilation error!
bien sûr, si vous FAIRE veulent names
pour permettre un Boolean
, puis vous pouvez la déclarer comme List<Object> names
, et le code ci-dessus serait compilé.
voir aussi
en quoi un type brut diffère-t-il de l'utilisation de <Object>
comme paramètres de type?
ce qui suit est une citation de Java efficace 2e édition, point 23: N'utilisez pas les types bruts dans le nouveau code :
Quelle est la différence entre le type brut
List
et le type paramétréList<Object>
? Vaguement parlant, le premier a opté pour la vérification de type générique, tandis que le second a explicitement dit au compilateur qu'il est capable de contenir des objets de n'importe quel type. Alors que vous pouvez passer unList<String>
pour un paramètre de typeList
, vous ne pouvez pas passer à un paramètre de typeList<Object>
. Il existe des règles de sous-typage pour les génériques, etList<String>
est un sous-type du type brutList
, mais pas du type paramétréList<Object>
. En conséquence, vous perdez la sécurité du type si vous utilisez le type brut commeList
, mais pas si vous utilisez un type paramétré commeList<Object>
.
pour illustrer le point, considérons la méthode suivante qui prend un List<Object>
et ajoute un new Object()
.
void appendNewObject(List<Object> list) {
list.add(new Object());
}
Génériques En Java sont invariants. Un List<String>
n'est pas un List<Object>
, donc ce qui suit générerait un avertissement de compilateur:
List<String> names = new ArrayList<String>();
appendNewObject(names); // compilation error!
si vous aviez déclaré appendNewObject
pour prendre un type brut List
comme paramètre, alors cela se compilerait, et vous perdriez donc le type de sécurité que vous obtenez de generics.
voir aussi
en quoi un type brut diffère-t-il de l'utilisation de <?>
comme paramètre de type?
List<Object>
, List<String>
, etc sont tous List<?>
, il peut donc être tentant de juste dire qu'ils sont juste List
à la place. Cependant , il y a une différence majeure: depuis un List<E>
ne définit que add(E)
, vous ne peut pas ajouter n'importe quel objet arbitraire à un List<?>
. D'autre part, puisque le type brut List
n'a pas de sécurité de type, vous pouvez add
à peu près n'importe quoi à un List
.
tenir compte de la variation suivante de l'extrait précédent:
static void appendNewObject(List<?> list) {
list.add(new Object()); // compilation error!
}
//...
List<String> names = new ArrayList<String>();
appendNewObject(names); // this part is fine!
le compilateur a fait un travail merveilleux de vous protéger de violer potentiellement l'invariance de type du List<?>
! Si vous aviez déclaré le paramètre comme étant brut tapez List list
, puis le code compilerait, et vous violeriez l'invariant de type de List<String> names
.
un type brut est l'effacement de ce type
retour à JLS 4.8:
Il est possible de l'utiliser comme un type de l'effacement d'un type paramétré ou l'effacement d'un type tableau dont le type d'élément est un type paramétré. un tel type est appelé un type brut .
[...]
les superclasses (respectivement, superinterfaces) d'un type brut sont les effacements des superclasses (superinterfaces) de n'importe laquelle des paramétrisations du type générique.
le type d'un constructeur, la méthode d'instance, ou non -
static
champ d'un type brutC
qui n'est pas hérité de ses superclasses ou superinterfaces sont le type brut qui correspond à l'effacement de son type dans la déclaration Générique correspondant àC
.
en termes plus simples, lorsqu'un type brut est utilisé, les constructeurs, les méthodes d'instance et les champs non - static
sont également effacés .
prendre l'exemple suivant:
class MyType<E> {
List<String> getNames() {
return Arrays.asList("John", "Mary");
}
public static void main(String[] args) {
MyType rawType = new MyType();
// unchecked warning!
// required: List<String> found: List
List<String> names = rawType.getNames();
// compilation error!
// incompatible types: Object cannot be converted to String
for (String str : rawType.getNames())
System.out.print(str);
}
}
quand on utilise le brut MyType
, getNames
devient effacé aussi bien, de sorte qu'il retourne une brute List
!
JLS 4.6 continue d'expliquer ce qui suit:
type erasure maps également la signature d'un constructeur ou d'une méthode à une signature qui n'a pas de types paramétrés ou variables de type. l'effacement d'une signature de constructeur ou de méthode
s
est une signature constituée du même nom ques
et les effacements de tous les types de paramètres formels donnés danss
.le type de retour d'une méthode et les paramètres de type d'une méthode générique ou d'un constructeur subissent également une effacement si la signature de la méthode ou du constructeur est effacée.
L'effacement de la signature d'une méthode générique n'a pas de paramètres de type.
le rapport de bogue suivant contient quelques réflexions de Maurizio Cimadamore, un compilateur dev, et Alex Buckley, un des auteurs du JLS, sur les raisons pour lesquelles ce genre de comportement devrait se produire: https://bugs.openjdk.java.net/browse/JDK-6400189 . (En bref, cela simplifie la spécification.)
si c'est dangereux, pourquoi est-il permis d'utiliser un type brut?
voici une autre citation de JLS 4.8:
L'utilisation de types bruts n'est autorisée qu'à titre de concession à la compatibilité du code hérité. l'utilisation de types bruts dans le code écrit après l'introduction de la généralité dans le langage de programmation Java est fortement déconseillée. Il est possible que les versions futures du langage de programmation Java interdisent l'utilisation de types bruts.
en vigueur Java 2e édition a aussi ceci à ajouter:
étant donné que vous ne devriez pas utiliser les types bruts, pourquoi les concepteurs de langue les ont-ils permis? Pour assurer la compatibilité.
la plate-forme Java était sur le point d'entrer dans sa deuxième décennie quand les génériques ont été introduits, et il y avait une énorme quantité de code Java existant qui n'ont pas utilisé les génériques. Il a été jugé essentiel que tout ce code demeure légal et interopérable avec le nouveau code qui utilise des génériques. Il fallait que ce soit légal d'accepter des cas de les types paramétrés aux méthodes qui ont été conçues pour être utilisées avec les types ordinaires, et vice versa. Cette exigence, connue sous le nom de compatibilité de migration , a conduit à la décision de soutenir les types bruts.
en résumé, les types bruts ne devraient jamais être utilisés dans le nouveau code. vous devez toujours utiliser les types paramétrés .
N'y a-t-il pas d'exceptions?
malheureusement, parce que les génériques Java ne sont pas revérifiés, il y a deux exceptions où les types bruts doivent être utilisés dans le nouveau code:
- littérales de classe, p.ex.
List.class
, pasList<String>.class
-
instanceof
opérande, par exemple,o instanceof Set
, paso instanceof Set<String>
voir aussi
que sont les types bruts en Java, et pourquoi j'entends souvent qu'ils ne devraient pas être utilisés dans le nouveau code?
Raw-types sont l'histoire ancienne de la langue Java. Au début il y avait Collections
et ils ont tenu Objects
rien de plus et rien de moins. Chaque opération sur Collections
nécessite des moulages de Object
au type désiré.
List aList = new ArrayList();
String s = "Hello World!";
aList.add(s);
String c = (String)aList.get(0);
alors que cela a fonctionné la plupart du temps, des erreurs ne se produisent
List aNumberList = new ArrayList();
String one = "1";//Number one
aNumberList.add(one);
Integer iOne = (Integer)aNumberList.get(0);//Insert ClassCastException here
les anciennes collections typographiques ne pouvaient pas imposer la sécurité de type de sorte que le programmeur devait se rappeler ce qu'il stockait dans une collection.
Les génériques ont été inventés pour contourner cette limitation, le développeur déclarerait le type stocké une fois et le compilateur le ferait à la place.
List<String> aNumberList = new ArrayList<String>();
aNumberList.add("one");
Integer iOne = aNumberList.get(0);//Compile time error
String sOne = aNumberList.get(0);//works fine
Pour Comparaison:
// Old style collections now known as raw types
List aList = new ArrayList(); //Could contain anything
// New style collections with Generics
List<String> aList = new ArrayList<String>(); //Contains only Strings
plus complexe l'interface Comparable:
//raw, not type save can compare with Other classes
class MyCompareAble implements CompareAble
{
int id;
public int compareTo(Object other)
{return this.id - ((MyCompareAble)other).id;}
}
//Generic
class MyCompareAble implements CompareAble<MyCompareAble>
{
int id;
public int compareTo(MyCompareAble other)
{return this.id - other.id;}
}
notez qu'il est impossible d'implémenter l'interface CompareAble
avec compareTo(MyCompareAble)
avec les types bruts.
Pourquoi ne pas les utiliser:
- Any
Object
stocké dans unCollection
doit être moulé avant qu'il puisse être utilisé - l'utilisation de generics permet de compiler des vérifications de temps
- utilisant des types bruts est la même que stocker chaque valeur comme
Object
ce que fait le compilateur: Les génériques sont rétrocompatibles, ils utilisent les mêmes classes java que les types bruts. La magie se produit surtout au moment de la compilation.
List<String> someStrings = new ArrayList<String>();
someStrings.add("one");
String one = someStrings.get(0);
sera compilé comme:
List someStrings = new ArrayList();
someStrings.add("one");
String one = (String)someStrings.get(0);
c'est le même code que vous écririez si vous utilisiez les types bruts directement. Je pensais que je ne suis pas sûr de ce qui se passe avec l'interface CompareAble
, je suppose qu'il crée deux compareTo
fonctions, l'un prenant un MyCompareAble
et l'autre prend un Object
et le passe au premier après le moulage.
quelles sont les alternatives aux types bruts: utilisez génériques
un type brut est le nom d'une classe générique ou d'une interface sans aucun argument de type. Par exemple, étant donné la classe de la boîte générique:
public class Box<T> {
public void set(T t) { /* ... */ }
// ...
}
pour créer un type paramétré de Box<T>
, vous fournissez un argument de type réel pour le paramètre de type formel T
:
Box<Integer> intBox = new Box<>();
si l'argument de type réel est omis, vous créez un type brut de Box<T>
:
Box rawBox = new Box();
donc, Box
est le type brut du type générique Box<T>
. Cependant, un type de classe ou d'interface non générique n'est pas un type brut.
apparaissent dans le code legacy parce que beaucoup de classes API (telles que les classes Collections) n'étaient pas génériques avant JDK 5.0. Lorsque vous utilisez des types crus, vous obtenez essentiellement un comportement pré-génériques - un Box
vous donne Object
S. Pour la compatibilité arrière, l'affectation d'un type paramétré à son type brut est autorisée.:
Box<String> stringBox = new Box<>();
Box rawBox = stringBox; // OK
mais si vous assignez un type brut à un type paramétré, vous obtenez un avertissement:
Box rawBox = new Box(); // rawBox is a raw type of Box<T>
Box<Integer> intBox = rawBox; // warning: unchecked conversion
vous recevez également un avertissement si vous utilisez un type brut pour invoquer des méthodes génériques définies dans le type générique correspondant:
Box<String> stringBox = new Box<>();
Box rawBox = stringBox;
rawBox.set(8); // warning: unchecked invocation to set(T)
l'avertissement montre que les types bruts contournent les contrôles de type génériques, reportant la capture de code dangereux à l'exécution. Par conséquent, vous devriez éviter d'utiliser des types bruts.
la section Type Erasure contient plus d'informations sur la façon dont le compilateur Java utilise les types bruts.
Messages D'Erreur Non Vérifiés
comme mentionné précédemment, lorsque vous mélangez du code d'héritage avec du code générique, vous pouvez rencontrer des messages d'avertissement similaires à ce qui suit:
Note: Exemple.java utilise des opérations non contrôlées ou dangereuses.
Remarque: Recompiler avec -Xlint:désactivée pour plus de détails.
cela peut se produire lorsque vous utilisez une ancienne API qui fonctionne sur des types bruts, comme indiqué dans l'exemple suivant:
public class WarningDemo {
public static void main(String[] args){
Box<Integer> bi;
bi = createBox();
}
static Box createBox(){
return new Box();
}
}
Le terme "unchecked" signifie que le compilateur n'a pas suffisamment d'informations pour effectuer toutes les vérifications de type nécessaires pour assurer la sécurité de type. L'avertissement "non vérifié" est désactivé, par défaut, bien que le compilateur donne une indication. Pour voir toutes les mises en garde "non vérifiées", recompiler avec-Xlint:non vérifiées.
recompilant l'exemple précédent avec-Xlint: unchecked révèle les informations supplémentaires suivantes:
WarningDemo.java:4: warning: [unchecked] unchecked conversion
found : Box
required: Box<java.lang.Integer>
bi = createBox();
^
1 warning
pour désactiver complètement les Avertissements non contrôlés, utilisez le drapeau-Xlint:-unchecked. L'annotation @SuppressWarnings("unchecked")
supprime les Avertissements non contrôlés. Si vous n'êtes pas familier avec la syntaxe @SuppressWarnings
, Voir Annotations.
source originale: tutoriels Java
private static List<String> list = new ArrayList<String>();
vous devez spécifier le type-paramètre.
la mise en garde indique que les types définis pour supporter génériques devraient être paramétrés, plutôt que d'utiliser leur forme brute.
List
est défini comme étant le support des génériques: public class List<E>
. Cela permet de nombreuses opérations de type-sûr, qui sont vérifiées Le temps de compilation.
un type "raw" en Java est une classe qui n'est pas générique et traite des objets "raw", plutôt que des paramètres de type générique.
par exemple, avant que Java generics ne soit disponible, vous utiliseriez une classe de collection comme celle-ci:
LinkedList list = new LinkedList();
list.add(new MyObject());
MyObject myObject = (MyObject)list.get(0);
quand vous ajoutez votre objet à la liste, il ne se soucie pas de quel type d'objet il s'agit, et quand vous l'obtenez à partir de la liste, vous devez le lancer explicitement au type que vous attendez.
en utilisant generics, vous supprimez le facteur "unknown", car vous devez spécifier explicitement quel type d'objets peut figurer dans la liste:
LinkedList<MyObject> list = new LinkedList<MyObject>();
list.add(new MyObject());
MyObject myObject = list.get(0);
notez qu'avec generics vous n'avez pas à lancer l'objet provenant de l'appel get, la collection est prédéfinie pour ne fonctionner qu'avec MyObject. C'est là le principal moteur des génériques. Il modifie une source d'erreurs d'exécution en quelque chose qui peut être vérifié au moment de la compilation.
Qu'est-ce qu'un type brut et pourquoi est-ce que j'entends souvent qu'ils ne devraient pas être utilisés dans le nouveau code?
Un "brut de type" est l'utilisation d'une classe générique, sans spécification d'un type d'argument(s) pour sa paramétrée type(s), par exemple à l'aide de List
au lieu de List<String>
. Lorsque les génériques ont été introduits en Java, plusieurs classes ont été mises à jour pour utiliser les génériques. L'utilisation de cette classe comme un "type brut" (sans spécifier un argument de type) a permis à legacy code de encore de la compilation.
Brut "types" sont utilisés pour assurer la compatibilité ascendante. Leur utilisation dans le nouveau code n'est pas recommandée parce que l'utilisation de la classe générique avec un argument de type permet de taper plus fort, ce qui à son tour peut améliorer la compréhensibilité du code et conduire à détecter des problèmes potentiels plus tôt.
Quelle est l'alternative si nous ne pouvons pas utiliser les types bruts, et comment est-ce mieux?
l'alternative préférée est de utilisez les classes génériques comme prévu - avec un argument de type approprié (par exemple List<String>
). Cela permet au programmeur de spécifier des types plus spécifiquement, donne plus de sens aux futurs responsables sur l'utilisation prévue d'une variable ou d'une structure de données, et permet au compilateur de renforcer une meilleure sécurité de type. Ces avantages peuvent améliorer la qualité du code et aider à prévenir l'introduction de certaines erreurs de codage.
Par exemple, pour une méthode où le programmeur veut assurez-vous qu'une variable de liste appelée 'names' ne contient que des chaînes de caractères:
List<String> names = new ArrayList<String>();
names.add("John"); // OK
names.add(new Integer(1)); // compile error
le compilateur veut que vous écriviez ceci:
private static List<String> list = new ArrayList<String>();
parce que sinon, vous pouvez ajouter n'importe quel type que vous voulez dans list
, ce qui rend l'instanciation comme new ArrayList<String>()
inutile. Les génériques Java ne sont qu'une fonctionnalité de compilation, donc un objet créé avec new ArrayList<String>()
acceptera volontiers les éléments Integer
ou JFrame
s'il est affecté à une référence de "type brut" List
- l'objet lui-même ne sait rien des types qu'il est supposé contenir contenir, seul le compilateur ne.
ici, je considère plusieurs cas à travers lesquels vous pouvez clarifier le concept
1. ArrayList<String> arr = new ArrayList<String>();
2. ArrayList<String> arr = new ArrayList();
3. ArrayList arr = new ArrayList<String>();
Cas 1
ArrayList<String> arr
il s'agit d'une ArrayList
variable de référence avec type String
qui se réfère à un ArralyList
objet de Type String
. Cela signifie qu'il ne peut contenir que des objets de type String.
C'est un Strict de String
pas une Crue de Type donc, Il ne sera jamais soulever un avertissement .
arr.add("hello");// alone statement will compile successfully and no warning.
arr.add(23); //prone to compile time error.
//error: no suitable method found for add(int)
Cas 2
dans ce cas ArrayList<String> arr
est un type strict mais votre objet new ArrayList();
est un type brut.
arr.add("hello"); //alone this compile but raise the warning.
arr.add(23); //again prone to compile time error.
//error: no suitable method found for add(int)
ici arr
est un type Strict. Ainsi, il soulèvera une erreur de temps de compilation lors de l'ajout d'un integer
.
Avertissement : Une
Raw
Type d'Objet est assimilé à uneStrict
type de la Variable en question deArrayList
.
Cas 3
dans ce cas ArrayList arr
est un type brut mais votre objet new ArrayList<String>();
est un type Strict.
arr.add("hello");
arr.add(23); //compiles fine but raise the warning.
il va ajouter n'importe quel type d'objet en elle parce que arr
est un Type brut.
Avertissement : Une
Strict
Type d'Objet est assimilé à uneraw
type de la Variable en question.
Un raw -type est le manque d'un paramètre de type lors de l'utilisation d'un type générique.
Raw-type ne doit pas être utilisé parce qu'il pourrait causer des erreurs d'exécution, comme l'insertion d'un double
dans ce qui était censé être un Set
de int
s.
Set set = new HashSet();
set.add(3.45); //ok
lorsque vous récupérez le matériel du Set
, vous ne savez pas ce qui sort. Supposons que vous vous attendez à être tous int
s, vous le moulez à Integer
; exception à l'exécution lorsque le double
3.45 vient le long.
avec un" paramètre de type 1519110920 ajouté à votre Set
, vous obtiendrez immédiatement une erreur de compilation. Cette erreur préventive vous permet de corriger le problème avant que quelque chose n'explose pendant l'exécution (économisant ainsi du temps et de l'effort).
Set<Integer> set = new HashSet<Integer>();
set.add(3.45); //NOT ok.
ce qui veut dire que votre list
est un List
d'objets non spécifiés. C'est-à-dire que Java ne sait pas quels types d'objets se trouvent dans la liste. Ensuite, lorsque vous voulez itérer la liste, vous devez lancer chaque élément, pour pouvoir accéder aux propriétés de cet élément (dans ce cas, String).
en général est une meilleure idée de paramétrer les collections, de sorte que vous n'avez pas de problèmes de conversion, vous serez seulement en mesure d'ajouter des éléments de la le type paramétré et votre éditeur vous offrira les méthodes appropriées pour sélectionner.
private static List<String> list = new ArrayList<String>();
un type brut est le nom d'une classe générique ou d'une interface sans aucun argument de type. Par exemple, étant donné la classe générique de la boîte:
public class Box<T> {
public void set(T t) { /* ... */ }
// ...
}
pour créer un type paramétré de boîte, vous fournissez un argument de type réel pour le paramètre de type formel T:
Box<Integer> intBox = new Box<>();
si l'argument de type réel est omis, vous créez un type brut de la boîte:
Box rawBox = new Box();
voici un autre cas où les types bruts vous mordront:
public class StrangeClass<T> {
@SuppressWarnings("unchecked")
public <X> X getSomethingElse() {
return (X)"Testing something else!";
}
public static void main(String[] args) {
final StrangeClass<Object> withGeneric = new StrangeClass<>();
final StrangeClass withoutGeneric = new StrangeClass();
final String value1,
value2;
// Works
value1 = withGeneric.getSomethingElse();
// Produces compile error:
// incompatible types: java.lang.Object cannot be converted to java.lang.String
value2 = withoutGeneric.getSomethingElse();
}
}
comme il a été mentionné dans la réponse acceptée, vous perdez tout soutien pour les génériques dans le code du type brut. Chaque paramètre de type est converti en son effacement (qui dans l'exemple ci-dessus est juste Object
).
j'ai trouvé cette page après avoir fait quelques exercices et avoir eu exactement la même énigme.
============== je suis allé à partir de ce code comme fournir par l'exemple ===============
public static void main(String[] args) throws IOException {
Map wordMap = new HashMap();
if (args.length > 0) {
for (int i = 0; i < args.length; i++) {
countWord(wordMap, args[i]);
}
} else {
getWordFrequency(System.in, wordMap);
}
for (Iterator i = wordMap.entrySet().iterator(); i.hasNext();) {
Map.Entry entry = (Map.Entry) i.next();
System.out.println(entry.getKey() + " :\t" + entry.getValue());
}
====================== Pour Ce code ========================
public static void main(String[] args) throws IOException {
// replace with TreeMap to get them sorted by name
Map<String, Integer> wordMap = new HashMap<String, Integer>();
if (args.length > 0) {
for (int i = 0; i < args.length; i++) {
countWord(wordMap, args[i]);
}
} else {
getWordFrequency(System.in, wordMap);
}
for (Iterator<Entry<String, Integer>> i = wordMap.entrySet().iterator(); i.hasNext();) {
Entry<String, Integer> entry = i.next();
System.out.println(entry.getKey() + " :\t" + entry.getValue());
}
}
===============================================================================
il peut être plus sûr, mais il a fallu 4 heures pour demuddle la philosophie...
les types bruts sont très bien quand ils expriment ce que vous voulez exprimer.
par exemple, une fonction de désérialisation peut renvoyer un List
, mais elle ne connaît pas le type d'élément de la liste. Donc List
est le type de retour approprié ici.