Pergunta

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

Agora, como converter BigDecimal em Integer e passá-lo para o segundo método?

Existe uma maneira de sair disso?

Foi útil?

Solução

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

Outras dicas

Você pode garantir que o BigDecimal nunca conterá um valor maior que Integer.MAX_VALUE?

Se sim, então aqui está o seu código chamando intValue:

Integer.valueOf(bdValue.intValue())

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.

  • Será que BigDecimal potencialmente tem uma parte fracionária diferente de zero?
  • Será que BigDecimal potencialmente não se enquadra no Integer faixa?
  • Você gostaria de partes fracionárias diferentes de zero arredondadas ou truncadas?
  • Como você gostaria que as partes fracionárias diferentes de zero fossem arredondadas?

Se você respondeu não às 2 primeiras perguntas, você poderia simplesmente usar BigDecimal.intValueExact() como outros sugeriram e deixá-lo explodir quando algo inesperado acontecer.

Se você não estiver absolutamente 100% confiante sobre a pergunta número 2, então intValue() é sempre a resposta errada.

Tornando isso melhor

Vamos usar as seguintes suposições com base nas outras respostas.

  • Não há problema em perder precisão e truncar o valor porque é isso que intValueExact() e boxe automático fazem
  • Queremos que uma exceção seja lançada quando o BigDecimal é maior que o Integer intervalo porque qualquer outra coisa seria uma loucura, a menos que você tenha uma necessidade muito específica do que acontece quando você elimina os bits de ordem superior.

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

Para obter o melhor dos dois mundos, complete o BigDecimal primeiro e depois converta.Isso também tem a vantagem de lhe dar mais controle sobre o processo de arredondamento.

Teste Spock Groovy

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()
}

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

Converte este BigDecimal em um int.Esta conversão é análoga a uma conversão primitiva estreita de double para short conforme definido na especificação da linguagem Java:qualquer parte fracionária deste BigDecimal será descartada e, se o "BigInteger" resultante for muito grande para caber em um int, apenas os 32 bits de ordem inferior serão retornados.Observe que esta conversão pode perder informações sobre a magnitude geral e a precisão deste valor BigDecimal, bem como retornar um resultado com o sinal oposto.

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

O seguinte deve resolver o problema:

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

Você já tentou ligar BigInteger#intValue() ?

Descobri que o acima não funcionou para mim.Eu estava extraindo um valor de célula de uma JTable, mas não consegui converter para double ou int etc.Minha solução:

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

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

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top