2016-11-05 2 views
9

Ich brauche eine ENUM ENUM-Konverter in Java zu implementieren: Enum_2>Enum_1 und ich möchte es in allgemeiner Weise zu tun.Warum muss dieser Konverter gegossen werden?

So definiert ich eine Schnittstelle:

interface LabelAware<T extends Enum> { 
    String getLabel(); 

    T getObject(); 
} 

und Enum_1:

enum Enum_1 { 
    A, B; 

    String getValue() { 
     return "whatever"; 
    } 
} 

und Enum_2 die LabelAware implementiert und muss Enum_1 umgewandelt werden:

enum Enum_2 implements LabelAware<Enum_1> { 
    C("c", Enum_1.A), D("d", Enum_1.B); 

    private final String label; 
    private final Enum_1 object; 

    Enum_2(String label, Enum_1 object) { 
     this.label = label; 
     this.object = object; 
    } 

    public String getLabel() { 
     return label; 
    } 

    public Enum_1 getObject() { 
     return object; 
    } 
} 

Schließlich ist hier ein generischer Konverter (List.ofAll() kommt von javaslang):

class Converter<S extends LabelAware, D extends Enum> { 

    private S[] values; 

    Converter(S[] values) { 
     this.values = values; 
    } 

    D map(String label) { 
     return (D) List.of(values) 
       .find(v -> v.getLabel().equals(label)) 
       .map(LabelAware::getObject) 
       .getOrElseThrow(() -> new RuntimeException("")); 
    } 
} 

Und eine Hauptmethode:

public class Main {   
    public static void main(String[] args) { 
     System.out.println(new Converter<Enum_2, Enum_1>(Enum_2.values()).map("c").getValue()); 
    } 
} 

es alles kompiliert und läuft gut, aber ich habe keine Ahnung, warum ich brauche das Ergebnis Converter.map Verfahren zu gieße D, da ich DEnum zu verlängern erklärt haben. Kann es generisch ohne Warnungen gemacht werden?

+0

Ist 'List.of (Werte)' vom Typ 'S' nicht? –

+2

Ich bin auf meinem Handy, so dass es schwer zu lesen ist, aber beachten Sie, dass Enum eine generische Klasse ist, so dass Ihre Generika einen rohen Typ wie geschrieben enthalten. In der Regel werden Sie wollen, > '. Nicht sicher, ob das dein Problem ist. – yshavit

+0

@yshavit, es ändert nichts - ungeprüfte Warnung ist immer noch vorhanden. – Opal

Antwort

5

In der Regel sollten alle Warnungen in Bezug auf Generika so behandelt werden, dass sie einen sichereren Code enthalten und eine Warnkette vermeiden (die sichtbare Warnung wird durch eine sehr weitgehende Warnung der Abhängigkeitskette verursacht).

Aber in Ihrem Fall haben Sie kein Warnkettenproblem seit extern, LabelAware ist sicher.
LabelAware hat nur eine interne Warnung (in seiner Implementierung) als Enum in extends Enum ist roh deklariert.

Hier wird eine einzelne fehlende allgemeine Erklärung erklärt, warum die Besetzung in Converter.map() Methode ist nicht sicher: Converter Klassendeklaration nicht die generische für LabelAware spezifiziert.

Sie erklären Converter Klasse:

class Converter<S extends LabelAware, D extends Enum> { 

mit seinem value Feld vom Typ S:

private S[] values; 

und seine map() Methode wie:

D map(String label) { 
     return (D) List.of(values) 
       .find(v -> v.getLabel().equals(label)) 
       .map(LabelAware::getObject) 
       .getOrElseThrow(() -> new RuntimeException("")); 
    } 

In 012., hier .find(v -> v.getLabel().equals(label)), Ihre Abfrage so eine S Instanz und Sie haben diese S extends LabelAware deklariert. Daher schließlich, holen Sie eine Instanz von oder erweitern es.

Und LabelAware wird getippt mit Enum generic:

interface LabelAware<T extends Enum> { 
    String getLabel();  
    T getObject(); 
} 


in map() Methode Also, wenn .map(LabelAware::getObject) genannt wird, Sie rufen Sie eine Enum Typ.

Und ein Enum Typ ist nicht unbedingt ein Typ, während das Gegenteil der Fall ist.

Deshalb, wenn Sie die Besetzung (und die damit verbundene Warnung) in map() vermeiden wollen, sollten Sie festlegen, dass der generische Typ zurückgegeben von getObject() ist eine Instanz D von LabelAware mit D generic eingeben:

class Converter<S extends LabelAware<D>, D extends Enum> { 
4

Sie haben an mehreren Stellen roh Typen wurden (nicht nur die, die im Kommentar yshavit darauf hingewiesen). Insbesondere die

class Converter<S extends LabelAware, D extends Enum> 

class Converter<S extends LabelAware<D>, D extends Enum<D>> 

Die folgende sein muss sollte ohne Warnungen kompilieren:

import javaslang.collection.List; 

interface LabelAware<T extends Enum<?>> 
{ 
    String getLabel(); 

    T getObject(); 
} 

enum Enum_1 
{ 
    A, B; 

    String getValue() 
    { 
     return "whatever"; 
    } 
} 

enum Enum_2 implements LabelAware<Enum_1> 
{ 
     C("c", Enum_1.A), D("d", Enum_1.B); 

    private final String label; 
    private final Enum_1 object; 

    Enum_2(String label, Enum_1 object) 
    { 
     this.label = label; 
     this.object = object; 
    } 

    public String getLabel() 
    { 
     return label; 
    } 

    public Enum_1 getObject() 
    { 
     return object; 
    } 
} 

class Converter<S extends LabelAware<D>, D extends Enum<D>> 
{ 

    private S[] values; 

    Converter(S[] values) 
    { 
     this.values = values; 
    } 

    D map(String label) 
    { 
     return List.of(values) 
      .find(v -> v.getLabel().equals(label)) 
      .map(LabelAware::getObject) 
      .getOrElseThrow(() -> new RuntimeException("")); 
    } 
} 

(EDIT:. Das nur erfahren Sie, wie das Problem zu beheben, pragmatisch sehen die answer by davidxxx für Details darüber, was dort schief gelaufen ist, und vergessen Sie nicht, eine +1 dort zu lassen :-))

Verwandte Themen