Bezpiecznie rzucać long do int w Javie

Jaki jest najbardziej idiomatyczny sposób w Javie, aby sprawdzić, czy Obsada od long do int nie traci żadnych informacji?

To jest moja obecna implementacja:

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;
}
 504
Author: Hash, 2009-10-19

10 answers

Została dodana nowa metoda zJava 8 w tym celu.

import static java.lang.Math.toIntExact;

long foo = 10L;
int bar = toIntExact(foo);

Rzuci ArithmeticException w przypadku przepełnienia.

Zobacz: Math.toIntExact(long)

Do Java 8 dodano kilka innych bezpiecznych metod przepełnienia. Kończą się na dokładnie .

Przykłady:

  • Math.incrementExact(long)
  • Math.subtractExact(long, long)
  • Math.decrementExact(long)
  • Math.negateExact(long),
  • Math.subtractExact(int, int)
 596
Author: Pierre-Antoine,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-15 23:32:48

Myślę, że zrobiłbym to tak po prostu:

public static int safeLongToInt(long l) {
    if (l < Integer.MIN_VALUE || l > Integer.MAX_VALUE) {
        throw new IllegalArgumentException
            (l + " cannot be cast to int without changing its value.");
    }
    return (int) l;
}

Myślę, że to wyraża intencję wyraźniej niż powtarzający się casting... ale to trochę subiektywne.

Uwaga o potencjalnym zainteresowaniu-w C# byłoby po prostu:

return checked ((int) l);
 305
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-11 17:24:17

Z klasą Ints twoja metoda może zostać zmieniona na:

public static int safeLongToInt(long l) {
    return Ints.checkedCast(l);
}

Z linked docs:

CheckedCast

public static int checkedCast(long value)

Zwraca wartość int, która jest równa value, jeśli to możliwe.

Parametry: value - dowolna wartość z zakresu typu int

Zwraca: wartość int równa się value

Rzuca: IllegalArgumentException - jeżeli {[2] } jest większa niż Integer.MAX_VALUE lub mniej niż Integer.MIN_VALUE

Nawiasem mówiąc, nie potrzebujesz wrappera safeLongToInt, chyba że chcesz go zostawić na swoim miejscu, aby zmienić funkcjonalność bez rozbudowanej refaktoryzacji, oczywiście.

 134
Author: prasopes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-29 13:35:53

Z BigDecimal:

long aLong = ...;
int anInt = new BigDecimal(aLong).intValueExact(); // throws ArithmeticException
                                                   // if outside bounds
 29
Author: Jaime Saiz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-04 13:23:35

Oto rozwiązanie, jeśli nie zależy ci na wartości, jeśli jest ona większa niż potrzebna;)

public static int safeLongToInt(long l) {
    return (int) Math.max(Math.min(Integer.MAX_VALUE, l), Integer.MIN_VALUE);
}
 17
Author: Vitaliy Kulikov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-10 21:33:53

DONT: to nie jest rozwiązanie!

Moje pierwsze podejście było:

public int longToInt(long theLongOne) {
  return Long.valueOf(theLongOne).intValue();
}

Ale to tylko rzuca long do int, potencjalnie tworząc nowe instancje Long lub pobierając je z długiej puli.


Wady

  1. Long.valueOf tworzy nową instancję Long, jeśli liczba nie mieści się w zakresie puli Long [-128, 127].

  2. Implementacja intValue nie robi nic więcej niż:

    return (int)value;
    

Więc to można uznać nawet za gorsze niż samo rzucanie long na int.

 11
Author: Andreas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-02 11:21:15

Twierdzę, że oczywistym sposobem sprawdzenia, czy rzucanie wartości zmieniło wartość, byłoby rzucenie i sprawdzenie wyniku. Ja jednak przy porównywaniu usunąłbym niepotrzebny gips. Nie przepadam też za jednoliterowymi nazwami zmiennych (wyjątek x i y, ale nie wtedy, gdy oznaczają one wiersz i kolumnę (czasami odpowiednio)).

public static int intValue(long value) {
    int valueInt = (int)value;
    if (valueInt != value) {
        throw new IllegalArgumentException(
            "The long value "+value+" is not within range of the int type"
        );
    }
    return valueInt;
}

Jednak naprawdę chciałbym uniknąć tego nawrócenia, jeśli w ogóle jest to możliwe. Oczywiście czasami nie jest to możliwe, ale w tych przypadkach {[3] } jest prawie z pewnością błędnym wyjątkiem jest rzucanie, jeśli chodzi o kod klienta.

 7
Author: Tom Hawtin - tackline,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-19 20:22:37

Typy liczb całkowitych Javy są reprezentowane jako Podpisane. Z wejściem pomiędzy 231 oraz 232 (lub -231 oraz -232) Obsada by się powiodła, ale twój test by się nie powiódł.

Należy sprawdzić, czy wszystkie wysokie bity long są takie same:

public static final long LONG_HIGH_BITS = 0xFFFFFFFF80000000L;
public static int safeLongToInt(long l) {
    if ((l & LONG_HIGH_BITS) == 0 || (l & LONG_HIGH_BITS) == LONG_HIGH_BITS) {
        return (int) l;
    } else {
        throw new IllegalArgumentException("...");
    }
}
 2
Author: mob,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-19 20:39:41
(int) (longType + 0)

Ale długo nie może przekroczyć maksimum:)

 0
Author: Maury,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-06 08:23:38

Innym rozwiązaniem może być:

public int longToInt(Long longVariable)
{
    try { 
            return Integer.valueOf(longVariable.toString()); 
        } catch(IllegalArgumentException e) { 
               Log.e(e.printstackstrace()); 
        }
}

Próbowałem tego w przypadkach, gdy klient robi POST i serwer DB rozumie tylko liczby całkowite, podczas gdy Klient ma długi.

 -7
Author: Rajat Anantharam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-03 09:22:47