Convertendo BigDecimal em Inteiro

134

Eu tenho o método Hibernate que me retorna um BigDecimal. Eu tenho outro método de API para o qual preciso passar esse número, mas ele aceita Inteiro como parâmetro. Não posso alterar os tipos de retorno ou os tipos variáveis ​​dos dois métodos.

Agora, como converter o BigDecimal em número inteiro e passá-lo para o segundo método?

Existe uma maneira de sair disso?

Vishal
fonte
6
Eu corrigi seu título. Isso é conversão, não transmissão.
Marquês de Lorne

Respostas:

209

Você telefonaria myBigDecimal.intValueExact()(ou apenas intValue()) e isso causará uma exceção se você perder informações. Isso retorna um int, mas o autoboxing cuida disso.

willcodejavaforfood
fonte
1
intValueExact()é uma boa recomendação; foi adicionado em 1,5
Anon
Ligar intValue()é perigoso, a menos que você esteja 100% apostando sua vida com a certeza de que o número está dentro do Integerintervalo.
Snekse
1
Isso faz sentido: "Integer.valueOf (myBigDecimal.intValueExact ())"?
OddDev
32

Você pode garantir que BigDecimalnunca conterá um valor maior que Integer.MAX_VALUE?

Se sim, então aqui está a sua chamada de código intValue:

Integer.valueOf(bdValue.intValue())
Anon
fonte
Sim. Eu acho que não conterá um valor maior que Integer.MAX_VALUE
Vishal
2
Não há nenhuma razão para fazer o valor, exceto obter um Objeto, em vez de um direito primitivo, certo?
Basil
Eu diria que essa deve ser a resposta oficial porque a. menciona os limites, b. impede autoboxing.
ledlogic
22

TL; DR

Use um destes para necessidades de conversão universal

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

Raciocínio

A resposta depende de quais são os requisitos e como você responde a essas perguntas.

  • O BigDecimalpotencial terá uma parte fracionária diferente de zero?
  • Os BigDecimalpotencialmente não se encaixam no Integerintervalo?
  • Deseja que partes fracionárias diferentes de zero sejam arredondadas ou truncadas?
  • Como você gostaria que partes fracionárias diferentes de zero fossem arredondadas?

Se você respondeu não às 2 primeiras perguntas, você pode simplesmente usar BigDecimal.intValueExact()como as outras pessoas sugeriram e deixar explodir quando algo inesperado acontecer.

Se você não está absolutamente 100% confiante sobre a pergunta número 2, sempreintValue() é a resposta errada.

Tornando-o melhor

Vamos usar as seguintes premissas com base nas outras respostas.

  • Não há problema em perder precisão e truncar o valor, porque é isso que o intValueExact()boxe automático faz
  • Queremos uma exceção lançada quando BigDecimalfor maior que o Integerintervalo, porque qualquer outra coisa ficaria louca, a menos que você tenha uma necessidade muito específica de contornar o que acontece quando você solta os bits de alta ordem.

Dados esses parâmetros, intValueExact()lança uma exceção quando não queremos que nossa parte fracionária seja diferente de zero. Por outro lado, intValue()não lança uma exceção quando deveria, se a nossa BigDecimalfor muito grande.

Para obter o melhor dos dois mundos, termine o BigDecimalprimeiro e depois converta. Isso também tem o benefício de oferecer a você mais controle sobre o processo de arredondamento.

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()
}
Snekse
fonte
18

Bem, você poderia ligar para BigDecimal.intValue():

Converte esse BigDecimal em um int. Essa conversão é análoga a uma conversão primitiva restritiva de duplo para curto, conforme definido na Especificação da linguagem Java: qualquer parte fracionária desse BigDecimal será descartada e, se o "BigInteger" resultante for grande demais para caber em um int, apenas o baixo -order 32 bits são retornados. Observe que essa conversão pode perder informações sobre a magnitude geral e a precisão desse valor BigDecimal, além de retornar um resultado com o sinal oposto.

Você pode ligar explicitamente Integer.valueOf(int)ou deixar o boxe automático fazer isso por você, se estiver usando uma versão suficientemente recente do Java.

Jon Skeet
fonte
9

A seguir, faça o truque:

BigDecimal d = new BigDecimal(10);
int i = d.intValue();
Gareth Davis
fonte
-4

Eu descobri que o acima não funcionou para mim. Eu estava puxando um valor de célula de uma JTable, mas não foi possível converter para double ou int etc. Minha solução:

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

onde a linha 0 sempre seria um número. Espero que isso ajude alguém ainda rolando!

colméia
fonte