57 votes

Obtention de la valeur par défaut pour les types primitifs

J'ai un type primitif Java sous la main :

Class<?> c = int.class; // or long.class, or boolean.class

J'aimerais avoir un valeur par défaut pour cette classe -- plus précisément, la valeur est attribuée aux champs de ce type s'ils ne sont pas initialisés. Par exemple, 0 pour un numéro, false pour un booléen.

Existe-t-il un moyen générique de le faire ? J'ai essayé ceci :

c.newInstance()

Mais je reçois un InstantiationException et non une instance par défaut.

2 votes

C'est un problème courant, j'aimerais que Java ajoute une fonction default(T) comme en C#.

0 votes

C'est en soi une question intéressante, mais pourquoi en avez-vous besoin après tout ? Est-ce que c'est pour définir certaines propriétés du bean ou autre ? Ne sont-elles pas déjà initialisées implicitement avec ces valeurs par défaut ?

0 votes

@BalusC - Pour initialiser un formulaire HTML qui a un paramètre de méthode avec les valeurs par défaut.

61voto

whiskeysierra Points 2175

Les bibliothèques de Guava contiennent déjà cela :
http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/base/Defaults.html

Appel à defaultValue retournera la valeur par défaut pour tout type primitif (tel que spécifié par le JLS), et null pour tout autre type.

Utilisez-le comme ça :

import com.google.common.base.Defaults;
Defaults.defaultValue(Integer.TYPE); //will return 0

2 votes

J'améliorerais cette réponse en ajoutant un exemple de ligne de code. Par exemple : Defaults.defaultValue(long.class) Je dis cela parce que jusqu'à maintenant je ne savais pas que vous pouviez appeler .class sur les types primitifs.

0 votes

Comment l'utiliser avec le paramètre de type générique de la classe <T> ?

0 votes

Les types génériques ne sont jamais des primitifs et la valeur par défaut est donc toujours nulle.

18voto

Jack Leow Points 11081

C'est ce à quoi je pense (mais qui ne passe pas le test de l'élégance) :

public class PrimitiveDefaults {
    // These gets initialized to their default values
    private static boolean DEFAULT_BOOLEAN;
    private static byte DEFAULT_BYTE;
    private static short DEFAULT_SHORT;
    private static int DEFAULT_INT;
    private static long DEFAULT_LONG;
    private static float DEFAULT_FLOAT;
    private static double DEFAULT_DOUBLE;

    public static Object getDefaultValue(Class clazz) {
        if (clazz.equals(boolean.class)) {
            return DEFAULT_BOOLEAN;
        } else if (clazz.equals(byte.class)) {
            return DEFAULT_BYTE;
        } else if (clazz.equals(short.class)) {
            return DEFAULT_SHORT;
        } else if (clazz.equals(int.class)) {
            return DEFAULT_INT;
        } else if (clazz.equals(long.class)) {
            return DEFAULT_LONG;
        } else if (clazz.equals(float.class)) {
            return DEFAULT_FLOAT;
        } else if (clazz.equals(double.class)) {
            return DEFAULT_DOUBLE;
        } else {
            throw new IllegalArgumentException(
                "Class type " + clazz + " not supported");
        }
    }
}

0 votes

@PatriceM. Que diriez-vous d'un enum variante pour cela ?

0 votes

@Guillaume Polet : Je ne suis pas tout à fait sûr, pour être honnête :-).

3 votes

En fait, c'est plutôt chouette. Ce devrait être la réponse acceptée par l'IMO.

7voto

Julien Royer Points 694

Une alternative aux goyaves Defaults.java ce qui permet à l'implémentation de déterminer les valeurs par défaut (amélioré par l'utilisation de La réponse de Antag99 ) :

import static java.util.stream.Collectors.toMap;

import java.lang.reflect.Array;
import java.util.Map;
import java.util.stream.Stream;

public class DefaultValue {
    /**
     * @param clazz
     *            the class for which a default value is needed
     * @return A reasonable default value for the given class (the boxed default
     *         value for primitives, <code>null</code> otherwise).
     */
    @SuppressWarnings("unchecked")
    public static <T> T forClass(Class<T> clazz) {
        return (T) DEFAULT_VALUES.get(clazz);
    }

    private static final Map<Class<?>, Object> DEFAULT_VALUES = Stream
            .of(boolean.class, byte.class, char.class, double.class, float.class, int.class, long.class, short.class)
            .collect(toMap(clazz -> (Class<?>) clazz, clazz -> Array.get(Array.newInstance(clazz, 1), 0)));

    public static void main(String... args) {
        System.out.println(DefaultValue.forClass(int.class)); // 0
        System.out.println(DefaultValue.forClass(Integer.class)); // null
    }
}

0 votes

Pouvez-vous fournir un exemple de son utilisation ?

0 votes

C'est un peu tard, mais la réflexion n'est-elle pas un peu exagérée dans cette situation ? Vous pourriez les mettre vous-même dans la carte pour gagner beaucoup de temps CPU.

1 votes

@TadeasKriz - il s'agit simplement d'éviter de dupliquer les informations ; et je ne suis pas sûr que cela nécessite une si grande quantité de temps CPU (il n'est calculé qu'une fois). Mais je comprends que cela puisse être considéré comme exagéré.

2voto

mdma Points 33973

Vous pouvez le faire en réfléchissant, mais il est plus facile et plus clair de l'écrire, par ex.

Object defaultValue(Class cls)
{
  Map defaults = new HashMap();
  defaults.put(Integer.TYPE, Integer.valueOf(0));  
  defaults.put(Double.TYPE, Double.valueOf(0));  
  defaults.put(Boolean.TYPE, Boolean.FALSE);  
  //... etc
  return defaults.get(cls);
}

Bien sûr, vous voudrez probablement déplacer l'initialisation de la carte vers un constructeur ou un élément similaire pour une initialisation unique.

Raisonnablement concis - c'est élégant ?

4 votes

Vous pouvez le faire avec la réflexion Comment faites-vous avec la réflexion ?

3 votes

Pourquoi créer une carte si vous ne la réutilisez pas ?

1voto

Stephen C Points 255558

Il n'y a pas de moyen élégant de le faire. En fait, il n'est même pas possible de déclarer la signature d'une méthode qui renverra les valeurs primitives en tant que telles.

Le plus proche que vous puissiez trouver est quelque chose comme ça :

public Object defaultValue(Class cls) {
    if (class == Boolean.TYPE) {
        return Boolean.FALSE;
    } else if (class == Byte.TYPE) {
        return Byte.valueOf(0);
    } else if (class == Short.TYPE) {
        ...
    } else {
        return null;
    }
}

1 votes

La signature est simple : Objet getDefaultValue(Classe type)

0 votes

Cela ne fonctionnera pas à cause de la valeur de retour. int, long etc. ne sont pas java.lang.Object à moins que vous ne soyez d'accord pour renvoyer des classes d'enveloppe ( java.lang.Integer , java.lang.Long etc).

0 votes

@ripper234 - mais cela renvoie des instances de wrapper et non des instances de types primitifs.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X