Hat Java veränderbare Typen für Integer, Float, Double, Long?


81

Ich bin in einer Situation, in der ich veränderbare Versionen von Dingen wie Integer verwenden möchte. Muss ich diese Klassen verwenden (siehe unten) oder ist in Java etwas integriert?

http://www.java2s.com/Code/Java/Data-Type/Amutableintwrapper.htm


8
Die Frage ist, warum Sie das tun wollen?
Hilfsmethode

2
In einigen Fällen (z. B. bei einem Spiel, bei dem ein Lebensmittel mit nKalorien gespeichert wird , das aufgebraucht / ergänzt werden kann) ist es möglicherweise besser, eine nach der Verwendung benannte Klasse zu verwenden (z. B. class FoodItem { int calories; }weil es klarer ist und Methoden dies können wird bei Bedarf später hinzugefügt.
GKFX

7
Java 8 Lambdas funktionieren nur mit effektiv endgültigen Variablen. Um diese Einschränkung zu umgehen, wird ein veränderbares int benötigt.
Alex

Möglicherweise möchten Sie einen Zähler, der zwischen den Methoden übergeben werden muss. Das Übergeben von intfunktioniert nicht so, als ob es in einer Methode inkrementiert wäre, dann wird der Wert in der anderen Methode nicht wiedergegeben.
Adam Burley

Antworten:


51

Nein, Java hat diese nicht eingebaut. Und das hat einen Grund. Die Verwendung veränderlicher Typen ist gefährlich, da sie leicht missbraucht werden können. Darüber hinaus ist es sehr einfach zu implementieren. Zum Beispiel hat commons-lang eine MutableInt.


5
Ich vermute, der Java-Entwickler wollte, dass sich Integer wie ein Int 'verhält'. Das heißt, sobald Sie einen Verweis darauf haben, ändert er sich nie (vermeiden Sie Verwirrung). Aber ... es scheint mir immer noch seltsam, irgendwie keine veränderbare Option zu haben ...
Rogerdpack

35
"Die Verwendung veränderlicher Typen ist gefährlich, da sie leicht missbraucht werden können." Die meisten Dinge können missbraucht werden. Unveränderliche Typen existieren für Fälle, in denen Sicherheit wichtig ist, obwohl sie durch Reflexion geändert werden können. Wenn diese Fälle nicht im Weg sind, gibt es keinen Grund, Menschen daran zu hindern, veränderbare Typen zu verwenden, wenn sie diese benötigen.
GKFX

2
Um es besser auszudrücken: Unveränderliche Typen sorgen weniger für Verwirrung in z. B. Karten und Mengen. Wenn Sie eine veränderbare Ganzzahl hätten und ihren Wert dort ändern würden, wo sie als Schlüssel diente, würde dies die Sammlung durcheinander bringen. Wenn Sie jedoch eine veränderbare Implementierung von Integer benötigen, ist nichts einfacher als das Erstellen einer Klasse mit einem int-Wert. Und Sie können dort kreativ sein - machen Sie es zB zu einem Counter oder Countdown, nicht nur zu einem einfachen Int, der so ziemlich alles ermöglicht. Geben Sie ihm eine Logik (es sei denn, Sie entwickeln in Java EE, das von unten nach oben funktioniert).
Vlasec

Sicherlich eine alte Frage, aber hoffentlich kann jemand beantworten, wie er missbraucht werden kann. Was ist so gefährlich daran, sie zu benutzen?
Der flauschige Roboter

@ user1175807 Wie Vlasec kommentiert hat, führt dies zu seltsamen Fehlern, wenn Sie versehentlich eine Variable ändern, die Sie an einer anderen Stelle verwendet haben. Schlimmer noch, nehmen wir an, Sie schreiben ein Programm, das mit dem Code eines Kunden zusammenarbeitet. Sie müssen eine Methode implementieren, die einen Parameter vom Typ mutable Integer hat. Wenn Sie nun die veränderbare Ganzzahl aus irgendeinem Grund ändern, wird sie auch im Programm des Clients geändert, was völlig unerwartet ist und Fehler verursacht, die schwer zu finden sind.
GregT

90

Sie können den Wert jederzeit in ein Array int[] mutable = {1};einschließen, wenn das Einfügen des Codes für eine veränderbare Wrapper-Klasse zu umständlich ist.


30
Klug, Käfer hässlich wie Sünde.
Gvlasov

2
Das ist super clever und nimmt fast keinen Platz ein. plus vermeidet das Sychen mit AtomicInt.
CompEng88

52

Seit JDK 1.5 hat Java nun java.util.concurrent.atomic.AtomicInteger

Dies ist eine thread-sichere veränderbare Ganzzahl, ein Anwendungsbeispiel:

final AtomicInteger value = new AtomicInteger(0);

dann später:

value.incrementAndGet();

12
Diese Kopfsicherheit ist mit Leistungskosten verbunden, die in vielen Fällen nicht benötigt werden. Ein häufiger Anwendungsfall für mich ist beispielsweise das Inkrementieren eines von einem Lambda erfassten Zählers. Die Verwendung eines Atoms ist übertrieben.
Minas Mina

12

Hier ist eine kleine Klasse, die ich für eine veränderbare Ganzzahl erstellt habe:

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;
    }
}

Sie können dies leicht auf jedes andere Grundelement erweitern. Natürlich sollten Sie, wie alle anderen sagen, vorsichtig damit umgehen.


1
Meiner Meinung nach gibt die beste Option keine falschen Hinweise auf Parallelität, wie dies bei Verwendung eines atomaren Intergers der Fall ist. Und ein Array, wirklich würde ich niemals so etwas Schlechtes in meinem Code tun ..;)
Snicolas

Könnte eine gute Idee sein , anstatt eine einzige allgemeine Wrapper - Klasse zu schaffen , so dass Sie nicht mit einem Ende MutableInteger, MutableDouble, MutableStringusw. , sondern haben stattdessen ein Mutable<Integer>, Mutable<Double>... Die Overhead - Speicher (die Verwendung Integerüber intwird in der Regel nicht in Betracht fallen. Aber Sie erhalten eine einzelne, gebrauchsfertige Klasse, die die meisten Fälle behandeln kann (Wenn Sie möchten, dass Ihre Ganzzahl vergleichbar oder ähnlich ist, müssen Sie dennoch eine Unterklasse
erstellen

Es könnte eine gute Idee sein, die Anzahl zu erweitern .
Stijn de Witt

7

Sie können ein nnnn [] als veränderbares Objekt für jeden primitiven Typ verwenden, wie @Alexandre vorschlägt. Java verfügt außerdem über AtomicInteger und AtomicLong.

IMHO int ist normalerweise eine bessere Wahl als Integer und das ist veränderlich.

Können Sie näher erläutern, warum Sie ein Mehrfachobjekt benötigen? Vielleicht gibt es einen anderen Weg, um dasselbe zu erreichen.


8
int ist nicht veränderlich.
Mjaggard

7
intist immer veränderlich, es sei denn, es ist auchfinal
Peter Lawrey

18
Es ist nicht wirklich gültig zu sagen, dass ein primitiver Typ veränderlich ist . Es kann geändert werden, aber auch jedes nicht endgültige Objekt, wenn Sie nur auf ein neues Objekt zeigen. Zum Beispiel ist Integer a = 4;dann a = 5;gültiger Code, aber Integernicht veränderbar.
mjaggard

Ich bin damit einverstanden, dass IntegerInstanzen nicht veränderbar sind, selbst wenn Verweise darauf vorhanden sind, aber das ist ein anderer Typ.
Peter Lawrey

1
intist nicht veränderbar, denn wenn Sie es an eine Methode übergeben, kann die Methode ihren Wert nicht ändern und den neuen Wert in der aufrufenden Methode wiedergeben
Adam Burley,

5

AtomicIntegerwurde bereits erwähnt. Mutable Doubles können mit emuliert werden AtomicReference<Double>. Die bereits erwähnten Warnungen gelten und es ist ein schlechter Stil, aber manchmal haben Sie Code wie diesen

double sum=0
for (Data data:someListGenerator())
  sum+=data.getValue()

und möchten es im funktionalen Java 8-Stil umgestalten. Wenn der Code dieses Muster folgt , sondern fügt einen erheblichen Aufwand , um es, die vernünftigste Umwandlung könnte sein

AtomicReference<Double> sumref=new AtomicReference<>(0d);
someStreamGenerator().forEach(data->
  sumref.set(sumref.get().doubleValue()+data.getValue()));
double sum=sumref.get().doubleValue();

Das ist natürlich zumindest fragwürdiger Stil. Aber ich befand mich mehr als einmal in einer Situation mit einer verdrehten Schleife über einem ResultSetComputer, in der teilweise drei verschiedene Informationen daraus kumuliert wurden. Dies macht es wirklich schwierig, den Code in den richtigen Funktionsstil zu konvertieren. Das Konvertieren der kumulierten Teile nach dem obigen Muster schien mir ein vernünftiger Kompromiss zwischen sauberem Code und stark vereinfachtem Refactoring zu sein.


Sie sollten wirklich über Ihren Wortlaut nachdenken: Selbst wenn Sie ein Lambda verwenden, ist Ihr Beispiel nicht funktionsfähig , da dies Nebenwirkungen verhindert. Wenn Sie es wirklich funktional schreiben, brauchen Sie keine veränderlichen Elemente : someStreamGenerator().mapToDouble(Data::getValue).sum(). Selbst für die Kumulierung von drei verschiedenen Informationen gibt es eine funktionale Möglichkeit, indem Sie Stream.reduceoder verwenden Stream.collect. Ich sehe keinen Grund, jede Schleife in ein funktionales Codefragment umzugestalten, aber wenn Sie diesen Weg gehen möchten, sollten Sie ihn bis zum Ende gehen.
Tobias Liefke

Wie ich schrieb: Dies ist kein richtiger Stil und für jeden neuen Code sollte dieser nicht verwendet werden. Wenn Sie jedoch mehr als 400.000 Codezeilen überarbeiten, die sich innerhalb von mehr als 15 Jahren entwickelt haben, finden Sie Konstrukte, bei denen das ordnungsgemäße Umschreiben in wirklich funktionierende Konstrukte äußerst schwierig sein kann. Dann kann das Umschreiben in einen solchen Hybridstil ein vernünftiger Kompromiss sein, da Sie zumindest die Grundstruktur ausrichten. forund foreachkann Teile komplexer Frameworks sein, die funktional neu geschrieben werden, sodass Sie den Rest des Codes irgendwie um sie herum ausrichten müssen.
Dirk Hillbrecht

Sie verwirren Lambdas und funktionale Programmierung. In Ihrem Beispiel haben Sie es nicht "funktional" umgeschrieben. Und was bringt es, alles mit Lambdas neu zu schreiben, wenn Sie die Lesbarkeit verlieren, aber nicht die Vorteile der funktionalen Programmierung nutzen? Warum sollte man überhaupt versuchen, jede Schleife in einem komplexen Rahmen mit solchen Hybriden loszuwerden?
Tobias Liefke

Sie haben 1000 Stellen mit einer bestimmten Redewendung in Ihrem Code. Die Redewendung wird von einer Bibliothek oder einer beliebigen globalen Struktur gesteuert. Sie ersetzen diese globale Struktur durch eine neue, die auf funktionalem Ansatz und Lambdas basiert. 998 Ihrer 1000 Plätze können sauber in funktionalen Stil umgewandelt werden. Die restlichen 2 sind extrem schwer richtig zu konvertieren. In solchen Fällen habe ich immer das Mandat, mit solchen Hybridkonstrukten in einen neuen Stil umzuwandeln. Nur dann können Sie alle alten globalen Strukturen im Code entfernen. Obwohl es nicht perfekt ist, erhöht sich die Gesamtcodequalität.
Dirk Hillbrecht

2

Sie können das org.omg.CORBA-Paket (oder nur die benötigte Klasse) importieren und darin die Holder-Klassen verwenden.

Beispielsweise hat es den "IntHolder", in dem das Feld, in dem die Ganzzahl gespeichert ist, öffentlich ist und Zugriff zum Ändern bietet.

public static void triple(IntHolder x){
    x.value = 3 * x.value;
}

IntHolder mutableInt = new IntHolder(10);
triple(mutableInt);     
System.out.println(mutableInt.value);

Es hat auch "LongHolder" und "DoubleHolder" und Tonnen von anderen, die Sie verwenden können. Mit Vorsicht verwenden.

Hier ist die API dafür: https://docs.oracle.com/javase/7/docs/api/org/omg/CORBA/package-summary.html


2
Obwohl Java9 eine sehr clevere Möglichkeit ist, das Problem zu beheben, möchten Sie dies wahrscheinlich nicht verwenden - dies würde das gesamte CORBA-Modul nur für einen Int-Inhaber importieren.
Agoston Horvath
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.