Czy Java ma zmienne typy dla Integer, Float, Double, Long?
81
Jestem w sytuacji, w której chcę używać mutowalnych wersji rzeczy, takich jak Integer. Czy muszę używać tych klas (poniżej), czy też Java ma coś wbudowanego?
W niektórych przypadkach (np. Gra, w której przechowywany jest kawałek żywności zawierającej nkalorie, który może zostać zubożony / dodany), może być lepiej użyć klasy nazwanej na podstawie użycia (np. class FoodItem { int calories; }Ponieważ jest ona bardziej przejrzysta, a metody mogą być dodane w razie potrzeby później
GKFX
7
Lambdy Java 8 działają tylko z efektywnymi zmiennymi końcowymi. Aby obejść to ograniczenie, potrzebny jest mutable int.
Alex
Możesz potrzebować licznika, który musi być przekazywany między metodami. Przekazywanie an intnie działa tak, jakby było inkrementowane w jednej metodzie, wtedy wartość nie zostanie odzwierciedlona w drugiej metodzie.
Adam Burley
Odpowiedzi:
51
Nie, Java nie ma ich wbudowanych. Nie bez powodu. Używanie typów zmiennych jest niebezpieczne, ponieważ można je łatwo nadużywać. Dodatkowo jest to naprawdę łatwe do wdrożenia. Na przykład commons-lang ma rozszerzenie MutableInt.
Domyślam się, że programista Java chciał, aby Integer „zachowywał się” jak int, co oznacza, że… gdy masz do niego odniesienie, nigdy się nie zmienia (unikaj zamieszania). Ale… nadal wydaje mi się dziwne, że jakoś nie mam opcji
mutowalnej
35
„Używanie zmiennych typów jest niebezpieczne, ponieważ można je łatwo nadużywać”. Większość rzeczy można nadużyć. Niezmienne typy istnieją w przypadkach, w których bezpieczeństwo jest ważne, chociaż można je zmienić przez refleksję. Po usunięciu tych przypadków nie ma powodu, aby uniemożliwić ludziom używanie mutowalnych typów, gdy ich potrzebują.
GKFX
2
Lepiej ujmując, niezmienne typy powodują mniej zamieszania np. W mapach i zestawach. Gdybyś miał zmienną liczbę całkowitą i zmienił jej wartość tam, gdzie służyła jako klucz, zepsułby to kolekcję. Jeśli jednak potrzebujesz jakiejś mutowalnej implementacji Integer, nie ma nic prostszego niż utworzenie klasy z wartością int wewnątrz. I możesz tam być kreatywny - zrób to np. Licznik lub Odliczanie, a nie zwykły int, który umożliwia wszystko. Daj mu trochę logiki (chyba że programujesz w Java EE, która działa od podstaw).
Vlasec,
Z pewnością stare pytanie, ale miejmy nadzieję, że ktoś może odpowiedzieć, JAK można je nadużywać. Co jest takiego niebezpiecznego w ich używaniu?
The Fluffy Robot
@ user1175807 Jak skomentował Vlasec, jeśli przypadkowo zmodyfikujesz zmienną, której użyłeś gdzie indziej, spowoduje to dziwne błędy. Co gorsza, powiedzmy, że piszesz program, który współpracuje z kodem klienta. Musisz zaimplementować metodę, która ma parametr typu mutable Integer. Jeśli zmodyfikujesz zmienną liczbę całkowitą z jakiegokolwiek powodu, zostanie ona również zmieniona w programie klienta, co jest całkowicie nieoczekiwane i spowoduje błędy, które są trudne do znalezienia.
GregT
90
Zawsze możesz zawinąć wartość w tablicę, tak jak int[] mutable = {1};wtedy, gdy dołączenie kodu dla mutowalnej klasy opakowania jest zbyt kłopotliwe.
To bezpieczeństwo wiąże się z kosztem wydajności, który w wielu przypadkach nie jest potrzebny. Na przykład częstym przypadkiem użycia jest dla mnie zwiększenie licznika przechwyconego przez lambdę. Używanie atomów to przesada.
Minas Mina
12
Oto mała klasa, którą utworzyłem dla mutowalnej liczby całkowitej:
IMHO, najlepsza opcja, nie daje fałszywych wskazówek dotyczących współbieżności, jak robi to użycie atomowego interger. I tablica, naprawdę nigdy nie zrobiłbym tak złej rzeczy w swoim kodzie ..;)
Snicolas
Może być dobry pomysł, aby zapewnić jednolite rodzajowe klasy otoki zamiast więc nie kończy się z MutableInteger, MutableDouble, MutableStringitd., Ale zamiast mieć Mutable<Integer>, Mutable<Double>... Szczytowy pamięci (z użyciem Integerponad intzazwyczaj nie wchodzą pod uwagę. Ale otrzymujesz jedną, gotową do użycia klasę, która może obsłużyć większość przypadków (jeśli chcesz, aby twoja liczba całkowita była porównywalna lub podobna, nadal musisz
Nie można powiedzieć, że typ prymitywny jest zmienny . Można to zmienić, ale tak samo może się stać z każdym nieokończonym obiektem, jeśli wskażesz nowy obiekt. Na przykład Integer a = 4;wtedy a = 5;jest prawidłowy kod, ale Integernie jest zmienny.
mjaggard
Zgadzam się, że Integerinstancje nie są modyfikowalne, nawet jeśli istnieją odniesienia do nich, ale to inny typ.
Peter Lawrey
Czy to nie jest dobry sposób, aby mieć parametr int odniesienia? Na przykład funkcja, która zwraca podzieloną na strony listę elementów (z bazy danych), ale także całkowitą liczbę rekordów. W takim przypadku przydatne wydają się być AtomicInteger lub MutableInteger. Oczywiście innym sposobem byłoby posiadanie właściwości getTotalRecords zamiast zwracania jej tą samą metodą.
msanjay
1
intNie jest zmienny, ponieważ jeśli przekazać ją do metody, nie ma sposobu na sposób zmienić swoją wartość i mają nową wartość odzwierciedlenie w sposobie dzwoniącej
Adam Burley
5
AtomicIntegerzostało już wspomniane. Zmienne Doubles można emulować za pomocą AtomicReference<Double>. Wspomniane już ostrzeżenia obowiązują i jest to zły styl, ale czasami masz taki kod
i chcesz go zrefaktoryzować w funkcjonalnym stylu Java 8. Jeśli kod jest zgodny z tym wzorcem, ale dodaje mu znaczną złożoność, najbardziej sensowna może być konwersja
Oczywiście jest to co najmniej wątpliwy styl. Ale wielokrotnie znajdowałem się w sytuacji, w której pętla była zakręcona na ResultSetkomputerze i częściowo gromadziła z niej trzy różne informacje. To sprawia, że naprawdę trudno jest przekształcić kod w odpowiedni styl funkcjonalny. Konwersja kumulowanych części zgodnie z powyższym wzorem wydawała mi się rozsądnym kompromisem między czystym kodem a nadmiernie uproszczoną refaktoryzacją.
Powinieneś naprawdę przemyśleć swoje sformułowanie: nawet jeśli używasz lambdy, twój przykład nie działa , ponieważ zabrania efektów ubocznych. Jeśli naprawdę napisać to funkcjonalny, nie trzeba mutables: someStreamGenerator().mapToDouble(Data::getValue).sum(). Nawet w przypadku gromadzenia trzech różnych informacji istnieje funkcjonalny sposób za pomocą Stream.reducelub Stream.collect. Nie widzę powodu, aby refaktoryzować każdą pętlę do funkcjonalnego fragmentu kodu, ale jeśli chcesz iść w ten sposób, powinieneś to zrobić do końca.
Tobias Liefke
Jak napisałem: To nie jest właściwy styl i dla każdego nowego kodu nie należy tego używać. Ale podczas refaktoryzacji ponad 400 000 linii kodu, które ewoluowały w ciągu ponad 15 lat, odkrywasz konstrukcje, w których właściwe przepisanie na konstrukcje naprawdę funkcjonalne może być niezwykle trudne. Następnie przepisanie na taki styl hybrydowy może być rozsądnym kompromisem, ponieważ wyrównasz przynajmniej podstawową strukturę. fori foreachmogą być częściami złożonych frameworków, które zostały przepisane funkcjonalnie, więc musisz jakoś dopasować resztę kodu do nich.
Dirk Hillbrecht
Mylisz lambdy i programowanie funkcjonalne. W swoim przykładzie nie przepisałeś go na „funkcjonalny”. A jaki jest sens w przepisywaniu wszystkiego za pomocą lambd, kiedy tracisz czytelność, ale nie masz zalet programowania funkcjonalnego? Po co w ogóle próbować pozbyć się każdej pętli w złożonym frameworku, używając takich hybryd?
Tobias Liefke
Masz 1000 miejsc z określonym idiomem w swoim kodzie. Idiom jest napędzany przez bibliotekę lub jakąkolwiek globalną strukturę. Zastępujesz tę globalną strukturę nową opartą na podejściu funkcjonalnym i lambdach. 998 z 1000 miejsc można w prosty sposób przekształcić w funkcjonalny styl. Pozostałe 2 są niezwykle trudne do prawidłowej konwersji. W takich przypadkach zawsze zalecam przejście na nowy styl za pomocą takich hybrydowych konstrukcji. Tylko wtedy możesz pozbyć się wszelkich starych struktur globalnych, które były w kodzie. Chociaż nie jest doskonały, ogólna jakość kodu wzrasta.
Dirk Hillbrecht
2
Możesz zaimportować pakiet org.omg.CORBA (lub po prostu potrzebną Ci klasę) i użyć w nim klas Holder.
Na przykład ma „IntHolder”, gdzie pole, w którym przechowuje liczbę całkowitą, jest publiczne, co daje dostęp do jej modyfikacji.
Chociaż jest to bardzo sprytny sposób na rozwiązanie problemu, gdy pojawi się Java9, prawdopodobnie nie chcesz tego używać - zaimportowałoby to cały moduł CORBA tylko dla posiadacza int.
n
kalorie, który może zostać zubożony / dodany), może być lepiej użyć klasy nazwanej na podstawie użycia (np.class FoodItem { int calories; }
Ponieważ jest ona bardziej przejrzysta, a metody mogą być dodane w razie potrzeby późniejint
nie działa tak, jakby było inkrementowane w jednej metodzie, wtedy wartość nie zostanie odzwierciedlona w drugiej metodzie.Odpowiedzi:
Nie, Java nie ma ich wbudowanych. Nie bez powodu. Używanie typów zmiennych jest niebezpieczne, ponieważ można je łatwo nadużywać. Dodatkowo jest to naprawdę łatwe do wdrożenia. Na przykład commons-lang ma rozszerzenie
MutableInt
.źródło
Zawsze możesz zawinąć wartość w tablicę, tak jak
int[] mutable = {1};
wtedy, gdy dołączenie kodu dla mutowalnej klasy opakowania jest zbyt kłopotliwe.źródło
Od JDK 1.5 java ma teraz
java.util.concurrent.atomic.AtomicInteger
To jest zmienna liczba całkowita bezpieczna dla wątków, przykład użycia:
final AtomicInteger value = new AtomicInteger(0);
potem później:
źródło
Oto mała klasa, którą utworzyłem dla mutowalnej liczby całkowitej:
public class MutableInteger { private int value; public MutableInteger(int value) { this.value = value; } public void set(int value) { this.value = value; } public int intValue() { return value; } }
Możesz łatwo rozszerzyć to na dowolny inny prymityw. Oczywiście, jak wszyscy mówią, powinieneś używać go ostrożnie.
źródło
MutableInteger
,MutableDouble
,MutableString
itd., Ale zamiast miećMutable<Integer>
,Mutable<Double>
... Szczytowy pamięci (z użyciemInteger
ponadint
zazwyczaj nie wchodzą pod uwagę. Ale otrzymujesz jedną, gotową do użycia klasę, która może obsłużyć większość przypadków (jeśli chcesz, aby twoja liczba całkowita była porównywalna lub podobna, nadal musiszMożesz użyć nnnn [] jako zmiennego obiektu dla dowolnego typu pierwotnego, jak sugeruje @Alexandre, java ma również AtomicInteger i AtomicLong.
IMHO int jest zwykle lepszym wyborem niż Integer i jest zmienny.
Czy możesz dowiedzieć się więcej o tym, dlaczego potrzebujesz wielu obiektów, być może istnieje inny sposób na osiągnięcie tego samego.
źródło
int
jest zawsze zmienna, chyba że jej równieżfinal
Integer a = 4;
wtedya = 5;
jest prawidłowy kod, aleInteger
nie jest zmienny.Integer
instancje nie są modyfikowalne, nawet jeśli istnieją odniesienia do nich, ale to inny typ.int
Nie jest zmienny, ponieważ jeśli przekazać ją do metody, nie ma sposobu na sposób zmienić swoją wartość i mają nową wartość odzwierciedlenie w sposobie dzwoniącejAtomicInteger
zostało już wspomniane. ZmienneDouble
s można emulować za pomocąAtomicReference<Double>
. Wspomniane już ostrzeżenia obowiązują i jest to zły styl, ale czasami masz taki koddouble sum=0 for (Data data:someListGenerator()) sum+=data.getValue()
i chcesz go zrefaktoryzować w funkcjonalnym stylu Java 8. Jeśli kod jest zgodny z tym wzorcem, ale dodaje mu znaczną złożoność, najbardziej sensowna może być konwersja
AtomicReference<Double> sumref=new AtomicReference<>(0d); someStreamGenerator().forEach(data-> sumref.set(sumref.get().doubleValue()+data.getValue())); double sum=sumref.get().doubleValue();
Oczywiście jest to co najmniej wątpliwy styl. Ale wielokrotnie znajdowałem się w sytuacji, w której pętla była zakręcona na
ResultSet
komputerze i częściowo gromadziła z niej trzy różne informacje. To sprawia, że naprawdę trudno jest przekształcić kod w odpowiedni styl funkcjonalny. Konwersja kumulowanych części zgodnie z powyższym wzorem wydawała mi się rozsądnym kompromisem między czystym kodem a nadmiernie uproszczoną refaktoryzacją.źródło
someStreamGenerator().mapToDouble(Data::getValue).sum()
. Nawet w przypadku gromadzenia trzech różnych informacji istnieje funkcjonalny sposób za pomocąStream.reduce
lubStream.collect
. Nie widzę powodu, aby refaktoryzować każdą pętlę do funkcjonalnego fragmentu kodu, ale jeśli chcesz iść w ten sposób, powinieneś to zrobić do końca.for
iforeach
mogą być częściami złożonych frameworków, które zostały przepisane funkcjonalnie, więc musisz jakoś dopasować resztę kodu do nich.Możesz zaimportować pakiet org.omg.CORBA (lub po prostu potrzebną Ci klasę) i użyć w nim klas Holder.
Na przykład ma „IntHolder”, gdzie pole, w którym przechowuje liczbę całkowitą, jest publiczne, co daje dostęp do jej modyfikacji.
public static void triple(IntHolder x){ x.value = 3 * x.value; } IntHolder mutableInt = new IntHolder(10); triple(mutableInt); System.out.println(mutableInt.value);
Posiada również „LongHolder” i „DoubleHolder” oraz mnóstwo innych, których możesz używać. Używaj ostrożnie.
Oto jego interfejs API: https://docs.oracle.com/javase/7/docs/api/org/omg/CORBA/package-summary.html
źródło