IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Java Discussion :

Cast dans fonction générique


Sujet :

Langage Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé Avatar de GrosLapin
    Homme Profil pro
    Ingénieur et Etudiant
    Inscrit en
    Avril 2013
    Messages
    47
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur et Etudiant

    Informations forums :
    Inscription : Avril 2013
    Messages : 47
    Par défaut Cast dans fonction générique
    Bonjour à tous,

    Les casts et les fonctions génériques sont le sujet de beaucoup de question et mal-grès tous les posts que j'ai pu lire sur le sujet je n'arrive pas à savoir si ma solution est la plus propre (honnêtement j’espère pas, car je la trouve sale)

    Mon problème :

    Je stock mes constants dans un fichier .properties que je lis avec un Properties. Jusque la rien de fou. Mais getProperty(key) retourne un string et j'aimerais créer un classe "MesProperties" qui ne retourne pas forcement un string.

    En C++ j'aurais écris quelque chose comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    template<class T> T getValue(string key) { return (T) uneFonctionQuiConvertieStringEnDouble(getProperty(key));}
    Maintenant en java :
    1) Je ne peut pas faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
            public  <T> T getValue(final String key){
     
    		return (T)Double.valueOf(prop.getProperty(key));
    	}
    FAIL : java.lang.Double cannot be cast to java.lang.Float
    2) Je ne peut pas faire un truc du genre T.valueOf(..) parce que on peut pas utiliser de static sur un generic.
    3) Un truc du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
           	public  <T> T getValue(final String key,Class<T> clazz){
     
    		return clazz.cast(Double.valueOf(prop.getProperty(key)));
    	}
    Échoue pareille : FAIL : java.lang.Double cannot be cast to java.lang.Float

    4) la seule solution que j'ai trouvé ressemble à ça
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    @SuppressWarnings("unchecked")
    	public  <T> T getValue(final String key,Class<T> clazz){
    		if (clazz.equals(String.class))
    		{
    			return (T)(prop.getProperty(key));
    		}
    		else if(clazz.equals(Boolean.class))
    		{
    			return (T)(Boolean.valueOf(prop.getProperty(key)));
    		}
    		else if (clazz.equals(Float.class))
    		{
    			return (T)(Float.valueOf(prop.getProperty(key)));
    		}
    		else if (clazz.equals(Double.class))
    		{
    			return (T)(Double.valueOf(prop.getProperty(key)));
    		}
    		else if (clazz.equals(Integer.class))
    		{
    			return (T)(Integer.valueOf(prop.getProperty(key)));
    		}
    		throw new IllegalArgumentException(clazz+" n'est pas pris en compte, sorry");
    	}
    Si vous avez des idées / remarques je suis preneur car mon code ne me plaît pas

    TL;DR
    Je sais faire une conversion de Double vers Float mais je ne sais pas faire une conversion de Double vers <N extends Numbers>

  2. #2
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Billets dans le blog
    2
    Par défaut
    Salut,

    Le cast ne sert pas à convertir mais à adapter le type avec le type compatible. Je ne vois pas ce qui ne te plait pas dans le code que tu as écrit : on convertit une chaine dans le type qu'on veut avec les moyens adaptés (tu pourrais étendre ta méthode pour récupérer une propriété d'un type autre que String, Boolean ou Number, de type java.awt.Color par exemple, ou java.awt.Point, ou collection, etc.
    Éventuellement, faire une méthode pour chaque type, du type getBooleanProperty(), getDoubleProperty() ,getFloatProperty()... ne serait pas plus mal.


    Sinon, on peut faire la conversion Double vers <N extends Number> comme ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    @SuppressWarnings("unchecked")
    public static <T extends Number> T getProperty(String name, Class<T> klass) {
    	Double value = Double.valueOf(getProperty(name));
    	 try {
    	    	final String method = klass.getField("TYPE").get(null).toString()+"Value";
    	    	return (T) Double.class.getMethod(method).invoke(value, new Object[0] );
    	} catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException | InvocationTargetException | NoSuchMethodException e) {
    			throw new IllegalStateException("Cannot get a " + klass.getSimpleName(), e)
    	}
    } 
    public static void main(String[] args) {
    	float f = getProperty("toto", Float.class);
    	System.out.println(f);
    }
    Je ne suis pas sûr que cela soit mieux que ta méthode, même si ça fonctionnerait pour lire une valeur double directement en int. D'ailleurs l'alternative de même fonctionnement que la tienne (sur la partie number) serait plutôt :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    @SuppressWarnings("unchecked")
    public static <T extends Number> T getProperty(String name, Class<T> klass) {
     
    	String value = getProperty(name); 
    	try {
    		return (T)klass.getMethod("valueOf",new Class[]{String.class}).invoke(null, new Object[]{value});
    	} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {
    			throw new IllegalStateException("Not a " + klass.getSimpleName(), e);
    	}
     
    } 
    public static void main(String[] args) {
    	Integer f = getProperty("toto", Integer.class);
    	System.out.println(f);
    }
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  3. #3
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Salut,



    Si tu utilises un type précis (Double en l’occurrence) tu ne peux pas caster dans un autre type totalement différent car cela n'a aucun sens.
    Bref si tu paramètre ta méthode avec T, tu ne peux pas utiliser Double.valueOf() dans ton code car tu ignores le type réel.


    Perso j'aurais remplacé ta solution par plusieurs méthode distincte, plus simple à l'usage (ex getString(), getDouble, getFloat() ...).

    Sinon si la forme getValue(String,Class) doit être conservé, j'aurais plus tendance à utiliser une Map pour associer les "convertisseurs" à chaque type, ce qui donnerait quelque chose comme cela :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    34
    35
    36
    37
    38
    39
    class MyProperties extends Properties {
     
        private final Map<Class<?>, Function<String,?>> converters = new HashMap<>();
     
        public MyProperties() {
        	addConverter(Double.class, Double::valueOf);
            addConverter(Float.class, Float::valueOf);
            addConverter(Integer.class, Integer::valueOf);
            addConverter(Short.class, Short::valueOf);
            addConverter(Boolean.class, Boolean::valueOf);
            addConverter(String.class, Function.identity());
            // ... etc pour tous les types qu'on veut supporter de base...
        }
     
        public <T> void addConverter(Class<T> clazz, Function<String,T> func) {
            this.converters.put(clazz, func);
        }
     
     
        public <T> Function<String,T> getConverter(Class<T> clazz) {
        	// Ceci n'est correct que si la Map est correctement renseigné
        	// (cad seulement via la méthode addConverter)
    	@SuppressWarnings("unchecked")
        	Function<String,T> func = (Function<String,T>) this.converters.get(clazz);
    	if (func==null) {
    		throw new IllegalStateException("Missing converter for type " + clazz);
    	}
    	return func;
        }
     
     
        public <T> T getValue(final String key, final Class<T> clazz) {
            String value = this.getProperty(key);
            if (value==null) {
                return null;
            }
            return getConverter(clazz).apply(value);
        }
    }
    C'est du Java 8 mais cela peut très bien s'écrire en version antérieur avec des classes anonymes...


    a++

  4. #4
    Membre éclairé Avatar de GrosLapin
    Homme Profil pro
    Ingénieur et Etudiant
    Inscrit en
    Avril 2013
    Messages
    47
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur et Etudiant

    Informations forums :
    Inscription : Avril 2013
    Messages : 47
    Par défaut
    @joel.drigo
    je ne vois pas ce qui ne te plait pas dans le code que tu as écrit :
    Le fait que je dois écrire à la main chacune des conversions et que je suis donc susceptible de ne pas avoir celle que l'utilisateur veut.
    Ton code répond à mon problème, il va falloir que je le creuse un peu car je suis pas a l'aise avec les truc comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    final String method = klass.getField("TYPE").get(null).toString()+"Value";
    	    	return (T) Double.class.getMethod(method).invoke(value, new Object[0] );
    @diGuba
    Si tu utilises un type précis (Double en l’occurrence) tu ne peux pas caster dans un autre type totalement différent car cela n'a aucun sens.
    J'avais pris le double parce que dans mon cas, tous les valeurs que j'avais pouvais rentrer dans un double, et après j'avais juste a "diminuer la précision". J'ai du mal a voir un cas dans lequel cela ne marche pas un Long Long Int peut etre ?

    Perso j'aurais remplacé ta solution par plusieurs méthode distincte, plus simple à l'usage (ex getString(), getDouble, getFloat() ...).
    Même problème qu'avec ma solution, ça doit être écrit à la main, et j'aime pas ça ^^' même si on se dit que l'utilisateur peut toujours étendre ma classe pour rajouter ce qu'il manque

    J'aime bien ta solution avec la map, c'est plus modulable que mes if/else.

    Merci pour vos réponses.

    Je tag en résolu ce soir histoire de voir si il y a d'autre proposition !

  5. #5
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par GrosLapin Voir le message
    J'avais pris le double parce que dans mon cas, tous les valeurs que j'avais pouvais rentrer dans un double, et après j'avais juste a "diminuer la précision". J'ai du mal a voir un cas dans lequel cela ne marche pas un Long Long Int peut etre ?
    Non dans tous les cas un Double ne peut pas être caster en Long/Integer/Short ou autre...
    Le cast d'un objet ne change pas sont type. C'est du transtypage et cela change seulement le type déclaré du point de vue du code, mais pas le type réel de l'objet.

    Bref pour pour pouvoir caster un Double en Integer il aurait fallut qu'il y ait une relation père/fils entre ces deux types, ce qui n'est pas le cas.



    Tu confonds avec le cast sur les types primitifs qui agit comme une conversion et non pas comme un transtypage


    a++

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Explication Cast dans une Fonction
    Par krugarka dans le forum MS SQL Server
    Réponses: 3
    Dernier message: 02/01/2007, 09h17
  2. Switch dans fonction membre
    Par Raish dans le forum C++
    Réponses: 11
    Dernier message: 30/03/2005, 14h41
  3. Utilisation de cast dans de l'héritage
    Par dreamanoir dans le forum C++
    Réponses: 4
    Dernier message: 21/02/2005, 21h01
  4. cast dans un template
    Par olivic dans le forum Langage
    Réponses: 15
    Dernier message: 20/10/2004, 14h10
  5. Réponses: 5
    Dernier message: 13/08/2004, 15h40

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo