Qual é a maneira mais idiomática em Java para verificar se uma conversão de long
para int
não perde nenhuma informação?
Esta é minha implementação atual:
public static int safeLongToInt(long l) {
int i = (int)l;
if ((long)i != l) {
throw new IllegalArgumentException(l + " cannot be cast to int without changing its value.");
}
return i;
}
Respostas:
Um novo método foi adicionado ao Java 8 para fazer exatamente isso.
Jogará um
ArithmeticException
em caso de estouro.Vejo:
Math.toIntExact(long)
Vários outros métodos seguros de estouro foram adicionados ao Java 8. Eles terminam com exatidão .
Exemplos:
Math.incrementExact(long)
Math.subtractExact(long, long)
Math.decrementExact(long)
Math.negateExact(long),
Math.subtractExact(int, int)
fonte
addExact
emultiplyExact
. É importante notar que a divisão (MIN_VALUE/-1
) e o valor absoluto (abs(MIN_VALUE)
) não possuem métodos de conveniência seguros.Math.toIntExact()
invés do elenco habitualint
? A implementação deMath.toIntExact()
apenas lançalong
paraint
.Eu acho que faria isso simplesmente:
Eu acho que expressa a intenção mais claramente do que o elenco repetido ... mas é um pouco subjetivo.
Nota de interesse em potencial - em C # seria apenas:
fonte
(!(Integer.MIN_VALUE <= l && l <= Integer.MAX_VALUE))
. Acho difícil entender outras maneiras de fazê-lo. Pena que o Java não temunless
.int
.Com a classe Ints do Google Guava , seu método pode ser alterado para:
Dos documentos vinculados:
Aliás, você não precisa do
safeLongToInt
wrapper, a menos que queira deixá-lo no lugar para alterar a funcionalidade sem refatoração extensiva, é claro.fonte
Ints.checkedCast
faz exatamente o OP faz, aliásInts.checkedCast(l)
diretamente.Ints.saturatedCast
que retornará o valor mais próximo em vez de lançar uma exceção.Com BigDecimal:
fonte
BigDecimal.valueOf(aLong)
, em vez denew BigDecimal(aLong)
, para denotar que uma nova instância não é necessária. Se o ambiente de execução faz cache nesse método, é específico da implementação, assim como a possível presença do Escape Analysis. Na maioria dos casos da vida real, isso não afeta o desempenho.aqui está uma solução, caso você não se importe com valor, caso seja maior que o necessário;)
fonte
too low
? por favor, forneça casos de uso.NÃO: Esta não é uma solução!
Minha primeira abordagem foi:
Mas isso apenas converte o long para um int, potencialmente criando novas
Long
instâncias ou recuperando-as do pool Long.As desvantagens
Long.valueOf
cria uma novaLong
instância se o número não estiver dentroLong
do intervalo do pool [-128, 127].A
intValue
implementação nada mais faz do que:Portanto, isso pode ser considerado ainda pior do que apenas lançar o
long
paraint
.fonte
Afirmo que a maneira óbvia de ver se a conversão de um valor alterou o valor seria lançar e verificar o resultado. No entanto, eu removeria o elenco desnecessário ao comparar. Também não gosto muito de nomes de variáveis de uma letra (exceção
x
ey
, mas não quando eles significam linha e coluna (às vezes respectivamente)).No entanto, eu realmente gostaria de evitar essa conversão, se possível. Obviamente, às vezes não é possível, mas nesses casos
IllegalArgumentException
é quase certamente a exceção errada a ser lançada no que diz respeito ao código do cliente.fonte
Os tipos inteiros Java são representados como assinados. Com uma entrada entre 2 31 e 2 32 (ou -2 31 e -2 32 ), o elenco terá êxito, mas seu teste falhará.
O que verificar é se todos os bits altos do
long
são todos iguais:fonte
(int) 0xFFFFFFFF
e(long) 0xFFFFFFFFL
têm valores diferentes, mas ambos contêm a mesma "informação" e é quase trivial extrair o valor longo original do int.mas Long não pode exceder o máximo :)
fonte
+ 0
acrescenta nada a esta conversão, ele poderia funcionar se o Java tratados tipo de concatenação numérico de forma semelhante às cordas, mas uma vez que não o seu fazer uma operação de adição sem motivo.Uma outra solução pode ser:
Eu tentei isso nos casos em que o cliente está executando um POST e o banco de dados do servidor entende apenas números inteiros enquanto o cliente possui um Long.
fonte
Integer.valueOf(Long.MAX_VALUE.toString());
resulta emjava.lang.NumberFormatException: For input string: "9223372036854775807"
praticamente ofuscar a exceção fora do intervalo, porque agora é tratada da mesma maneira que uma string contendo letras é tratada.