Conversione di BigDecimal in intero


135

Ho il metodo Hibernate che mi restituisce un BigDecimal. Ho un altro metodo API a cui devo passare quel numero ma accetta Integer come parametro. Non riesco a cambiare i tipi di ritorno o i tipi variabili di entrambi i metodi.

Ora come convertire il BigDecimal in intero e passarlo al secondo metodo?

C'è una via d'uscita da questo?


6
Ho corretto il tuo titolo. Questa è conversione, non casting.
Marchese di Lorne,

Risposte:


209

Chiameresti myBigDecimal.intValueExact()(o semplicemente intValue()) e lanci anche un'eccezione se perdi informazioni. Ciò restituisce un int ma l'autoboxing si occupa di quello.


1
intValueExact()è una buona raccomandazione; è stato aggiunto in 1.5
Anon il

Chiamare intValue()è pericoloso a meno che tu non abbia scommesso al 100% la tua vita su di esso positivo che il numero rientri Integernell'intervallo.
Snekse,

1
Ha senso: "Integer.valueOf (myBigDecimal.intValueExact ())"?
OddDev,

32

Potete garantire che BigDecimalnon conterrà mai un valore maggiore di Integer.MAX_VALUE?

Se sì, allora ecco il tuo codice chiamando intValue:

Integer.valueOf(bdValue.intValue())

Sì. Immagino che non conterrà un valore maggiore di Integer.MAX_VALUE
Vishal,

2
Non c'è motivo di fare il valore Se non quello di ottenere un oggetto anziché un diritto primitivo?
Basilio,

Direi che questa dovrebbe essere la risposta ufficiale perché a. menziona i limiti, b. impedisce l'autoboxing.
ledlogic,

22

TL; DR

Utilizzare uno di questi per esigenze di conversione universali

//Java 7 or below
bigDecimal.setScale(0, RoundingMode.DOWN).intValueExact()
//Java 8    
bigDecimal.toBigInteger().intValueExact()

Ragionamento

La risposta dipende da quali sono i requisiti e da come rispondi a queste domande.

  • Potrà BigDecimalpotenzialmente avere una parte frazionaria diversa da zero?
  • Intende la BigDecimalnon potenzialmente adatta alla Integergamma?
  • Vorresti arrotondare o troncare parti frazionarie diverse da zero?
  • Come desideri arrotondare le parti frazionarie diverse da zero?

Se hai risposto no alle prime 2 domande, potresti semplicemente usare BigDecimal.intValueExact()come altri hanno suggerito e lasciarlo saltare in aria quando succede qualcosa di inaspettato.

Se non si è assolutamente sicuri al 100% circa la domanda numero 2, poi intValue()è sempre la risposta sbagliata.

Rendendolo migliore

Usiamo i seguenti presupposti in base alle altre risposte.

  • Stiamo bene perdendo precisione e troncando il valore perché è ciò che fanno intValueExact()e l'auto-boxing
  • Vogliamo un'eccezione generata quando BigDecimalè maggiore Integerdell'intervallo perché qualsiasi altra cosa sarebbe pazza a meno che tu non abbia una necessità molto specifica per l'avvolgimento che accade quando si rilasciano i bit di ordine superiore.

Dati questi parametri, intValueExact()genera un'eccezione quando non lo vogliamo se la nostra parte frazionaria è diversa da zero. D'altra parte, intValue()non getta un'eccezione quando dovrebbe se la nostra BigDecimalè troppo grande.

Per ottenere il meglio da entrambi i mondi, completa il BigDecimalprimo, quindi converti. Ciò ha anche il vantaggio di darti un maggiore controllo sul processo di arrotondamento.

Spock Groovy Test

void 'test BigDecimal rounding'() {
    given:
    BigDecimal decimal = new BigDecimal(Integer.MAX_VALUE - 1.99)
    BigDecimal hugeDecimal = new BigDecimal(Integer.MAX_VALUE + 1.99)
    BigDecimal reallyHuge = new BigDecimal("10000000000000000000000000000000000000000000000")
    String decimalAsBigIntString = decimal.toBigInteger().toString()
    String hugeDecimalAsBigIntString = hugeDecimal.toBigInteger().toString()
    String reallyHugeAsBigIntString = reallyHuge.toBigInteger().toString()

    expect: 'decimals that can be truncated within Integer range to do so without exception'
    //GOOD: Truncates without exception
    '' + decimal.intValue() == decimalAsBigIntString
    //BAD: Throws ArithmeticException 'Non-zero decimal digits' because we lose information
    // decimal.intValueExact() == decimalAsBigIntString
    //GOOD: Truncates without exception
    '' + decimal.setScale(0, RoundingMode.DOWN).intValueExact() == decimalAsBigIntString

    and: 'truncated decimal that cannot be truncated within Integer range throw conversionOverflow exception'
    //BAD: hugeDecimal.intValue() is -2147483648 instead of 2147483648
    //'' + hugeDecimal.intValue() == hugeDecimalAsBigIntString
    //BAD: Throws ArithmeticException 'Non-zero decimal digits' because we lose information
    //'' + hugeDecimal.intValueExact() == hugeDecimalAsBigIntString
    //GOOD: Throws conversionOverflow ArithmeticException because to large
    //'' + hugeDecimal.setScale(0, RoundingMode.DOWN).intValueExact() == hugeDecimalAsBigIntString

    and: 'truncated decimal that cannot be truncated within Integer range throw conversionOverflow exception'
    //BAD: hugeDecimal.intValue() is 0
    //'' + reallyHuge.intValue() == reallyHugeAsBigIntString
    //GOOD: Throws conversionOverflow ArithmeticException because to large
    //'' + reallyHuge.intValueExact() == reallyHugeAsBigIntString
    //GOOD: Throws conversionOverflow ArithmeticException because to large
    //'' + reallyHuge.setScale(0, RoundingMode.DOWN).intValueExact() == reallyHugeAsBigIntString

    and: 'if using Java 8, BigInteger has intValueExact() just like BigDecimal'
    //decimal.toBigInteger().intValueExact() == decimal.setScale(0, RoundingMode.DOWN).intValueExact()
}

18

Bene, potresti chiamare BigDecimal.intValue():

Converte questo BigDecimal in un int. Questa conversione è analoga a una conversione primitiva restrittiva da doppia a breve come definito nella specifica del linguaggio Java: qualsiasi parte frazionaria di questo BigDecimal verrà scartata e se il "BigInteger" risultante è troppo grande per rientrare in un int, solo il basso - vengono restituiti 32 bit. Si noti che questa conversione può perdere informazioni sull'entità e la precisione complessive di questo valore BigDecimal, nonché restituire un risultato con il segno opposto.

Puoi quindi chiamare esplicitamente Integer.valueOf(int)o lasciare che l'auto-boxing lo faccia per te se stai usando una versione sufficientemente recente di Java.


9

Di seguito dovrebbe fare il trucco:

BigDecimal d = new BigDecimal(10);
int i = d.intValue();



-4

Ho scoperto che quanto sopra non ha funzionato per me. Stavo estraendo un valore di cella da una JTable ma non potevo eseguire il cast in double o int ecc. La mia soluzione:

Object obj = getTable().getValueAt(row, 0);

dove la riga 0 sarebbe sempre un numero. Spero che questo aiuti tutti ancora a scorrere!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.