web-dev-qa-db-fra.com

Le formatage utilisant DecimalFormat lève une exception - "Impossible de formater un objet donné sous forme de nombre"

Cela pourrait ressembler à une question répétée, mais j'ai essayé tous les liens ci-dessous et je ne peux pas obtenir une réponse correcte.

Impossible de formater un objet donné sous forme de zone de liste déroulante numérique

Exception d'argument illégal

Mais je ne me trompe pas. Voici mon code

DecimalFormat twoDForm = new DecimalFormat("#.##");
double externalmark = 1.86;
double internalmark = 4.0;
System.out.println(String.valueOf((externalmark*3+internalmark*1)/4));
String val = String.valueOf((externalmark*3+internalmark*1)/4);
String wgpa1=twoDForm.format(val); // gives exception
String wgpa2=twoDForm.format((externalmark*3+internalmark*1)/4)); // works fine
System.out.println(wgpa1);

La méthode format prend l'argument de type Object, c'est pourquoi j'ai passé un objet String qui donne une exception

Exception dans le thread "principal" Java.lang.IllegalArgumentException: Impossible de formater l'objet donné sous forme de nombre.

Mais quand je donne une valeur double comme argument, le programme fonctionne bien. Mais si la méthode est définie avec l'argument de type Object pourquoi j'obtiens une exception en passant un String et que je n'obtiens pas d'exception en passant double?

9
Arun Sudhakaran

La méthode format() de DecimalFormat est surchargée.

Dans le cas de travail, vous invoquez:

 public final String format(double number)

Et dans le cas contraire, vous invoquez:

 public final String format (Object obj) 

La première méthode prend un argument très spécifique. Il attend un double.

Ce n'est pas le cas du second, dont le type accepté est très large: Object et où donc la vérification du type passé est effectuée lors de l'exécution.

En fournissant un argument qui n'est pas un double mais un String, la méthode invoquée est la deuxième.

Sous le capot, cette méthode repose sur la méthode format(Object number, StringBuffer toAppendTo, FieldPosition pos) qui attend un argument number qui est une instance de la classe Number (Short, Long, ... Double):

@Override
public final StringBuffer format(Object number,
                                 StringBuffer toAppendTo,
                                 FieldPosition pos) {
    if (number instanceof Long || 
        number instanceof Integer ||                   
        number instanceof Short || 
        number instanceof Byte ||                   
        number instanceof AtomicInteger ||
        number instanceof AtomicLong ||
        (number instanceof BigInteger && ((BigInteger)number).bitLength () < 64)) {

        return format(((Number)number).longValue(), toAppendTo, pos);
    } else if (number instanceof BigDecimal) {
        return format((BigDecimal)number, toAppendTo, pos);
    } else if (number instanceof BigInteger) {
        return format((BigInteger)number, toAppendTo, pos);
    } else if (number instanceof Number) {
        return format(((Number)number).doubleValue(), toAppendTo, pos);
    } else {
        throw new IllegalArgumentException("Cannot format given Object as a Number");
    }
}

Mais ce n'est pas le cas puisque vous lui avez passé une instance String.

Pour résoudre le problème, passez une primitive double comme dans le cas de réussite ou convertissez votre String en une instance de Number telle que Double avec Double.valueOf(yourString).
Je conseille la première façon (en passant un double) car c'est plus naturel dans votre code qui utilise déjà les primitives double.
La seconde nécessite une opération de conversion supplémentaire de String vers Double.

14
davidxxx

La réponse est dans le javadoc . Il dit clairement, "Le nombre peut être de n'importe quelle sous-classe de Nombre", et il dit qu'il jette IllegalArgumentException "si nombre est nul ou non une instance de Nombre."

(Alors pourquoi ne font-ils pas simplement du paramètre un type Number? Parce que la classe est une sous-classe de l'abstrait Format classe qui n'est pas limitée au numérique Apparemment, on s'attend à ce que, bien que la classe générale Format ait une méthode avec des paramètres Object, des sous-classes de Format devraient limiter les paramètres aux types d'objet qu'ils peuvent gérer, ce qu'ils doivent faire au moment de l'exécution.)

1
ajb