Warum verwenden Menschen in Java immer noch primitive Typen?

163

Seit Java 5 haben wir das Ein- und Auspacken primitiver Typen, so dass intes umbrochen wird java.lang.Integer, und so weiter und so fort.

Ich sehe in letzter Zeit viele neue Java-Projekte (für die definitiv eine JRE von mindestens Version 5, wenn nicht sogar 6 erforderlich ist), die inteher verwendet werden als java.lang.Integer, obwohl es viel bequemer ist, letztere zu verwenden, da es einige Hilfsmethoden zum Konvertieren gibt zu longWerten et al.

Warum verwenden einige noch primitive Typen in Java? Gibt es einen konkreten Vorteil?

Naftuli Kay
quelle
49
Haben Sie schon einmal über Speicherverbrauch und Leistung nachgedacht?
Tedil
76
Ich habe das Autoboxing-Tag hinzugefügt ... und herausgefunden, dass tatsächlich drei Personen ihm folgen. "Ja wirklich?" Leute folgen dem AUTOBOXING-Tag?
CorsiKa
4
@glowcoder Sie sind keine wirklichen Menschen, sondern nur abstrakte Konzepte, die eine menschliche Form annehmen, um auf SO zu antworten. :)
biziclop
9
@TK Kocheran Meistens, weil new IntegeR(5) == new Integer(5)nach den Regeln falsch bewertet werden sollte.
Biziclop
10
Lösungen für Sammlungen primitiver Typen finden Sie unter GNU Trove- oder Mahout-Sammlungen oder HPPC oder ... Diejenigen von uns , die auf Geschwindigkeit verbringen unsere Zeit mit mehr primitiven Typen, nicht weniger.
Bmargulies

Antworten:

395

In Joshua Blochs Effective Java , Punkt 5: "Vermeiden Sie unnötige Objekte", veröffentlicht er das folgende Codebeispiel:

public static void main(String[] args) {
    Long sum = 0L; // uses Long, not long
    for (long i = 0; i <= Integer.MAX_VALUE; i++) {
        sum += i;
    }
    System.out.println(sum);
}

und es dauert 43 Sekunden, um zu laufen. Wenn Sie das Long in das Primitiv aufnehmen, wird es auf 6,8 Sekunden reduziert ... Wenn dies ein Hinweis darauf ist, warum wir Primitive verwenden.

Der Mangel an nativer Wertgleichheit ist ebenfalls ein Problem ( .equals()ist im Vergleich zu ziemlich ausführlich ==)

für biziclop:

class Biziclop {

    public static void main(String[] args) {
        System.out.println(new Integer(5) == new Integer(5));
        System.out.println(new Integer(500) == new Integer(500));

        System.out.println(Integer.valueOf(5) == Integer.valueOf(5));
        System.out.println(Integer.valueOf(500) == Integer.valueOf(500));
    }
}

Ergebnisse in:

false
false
true
false

BEARBEITEN Warum kehrt (3) zurück trueund (4) zurück false?

Weil sie zwei verschiedene Objekte sind. Die 256 Ganzzahlen, die Null am nächsten kommen [-128; 127] werden von der JVM zwischengespeichert, sodass sie für diese das gleiche Objekt zurückgeben. Außerhalb dieses Bereichs werden sie jedoch nicht zwischengespeichert, sodass ein neues Objekt erstellt wird. Um die Sache noch komplizierter zu machen, fordert das JLS, dass mindestens 256 Fliehgewichte zwischengespeichert werden. JVM-Implementierer können auf Wunsch weitere hinzufügen, was bedeutet, dass dies auf einem System ausgeführt werden kann, auf dem die nächsten 1024 zwischengespeichert werden und alle true zurückgeben ... #awkward

corsiKa
quelle
54
Stellen Sie sich nun vor, Sie wären iauch deklariert Long!
ColinD
14
@TREE - Die Spezifikation erfordert tatsächlich, dass VMs Fliehgewichte innerhalb eines bestimmten Bereichs erstellen. Leider können sie diesen Bereich erweitern, was bedeutet, dass sich Programme auf verschiedenen VMs möglicherweise unterschiedlich verhalten. Soviel zur Cross-Plattform ...
Daniel Earwicker
12
Java ist den Bach runtergegangen, mit immer mehr schlechten Designentscheidungen. Autoboxing ist ein völliger Fehler, es ist weder robust, vorhersehbar noch tragbar. Ich frage mich wirklich wirklich, was sie dachten ... anstatt die gefürchtete Dualität zwischen primitiven Objekten zu reparieren, haben sie es geschafft, sie schlimmer zu machen als an erster Stelle.
Pop Catalin
34
@Catalin Ich bin nicht einverstanden mit Ihnen, dass Autoboxing ein völliger Fehler ist. Es weist einige Mängel auf, die sich nicht von jedem anderen Design unterscheiden, das hätte verwendet werden können (einschließlich nichts). Sie machen sehr deutlich, was Sie erwarten können und was nicht, und wie jedes andere Design erwarten sie, dass Entwickler die Verträge kennen und befolgen dieser Entwürfe.
CorsiKa
9
@NaftuliTzviKay Das ist kein "Fehler". Sie machen es SEHR KLAR, dass der ==Operator Referenzidentitätsvergleiche für IntegerAusdrücke und Wertegleichheitsvergleiche für intAusdrücke durchführt. Integer.equals()existiert aus genau diesem Grund. Sie sollten nie verwenden ==in jedem nicht-primitiven Typ Wert zu vergleichen. Dies ist Java 101.
NullUserException
86

Autounboxing kann zu schwer zu erkennenden NPEs führen

Integer in = null;
...
...
int i = in; // NPE at runtime

In den meisten Situationen ist die Nullzuweisung zu inviel weniger offensichtlich als oben.

Heiko Rupp
quelle
43

Boxed-Typen haben eine schlechtere Leistung und benötigen mehr Speicher.

Orbit
quelle
40

Primitive Typen:

int x = 1000;
int y = 1000;

Bewerten Sie nun:

x == y

Es ist true. Kaum überraschend. Probieren Sie nun die Box-Typen aus:

Integer x = 1000;
Integer y = 1000;

Bewerten Sie nun:

x == y

Es ist false. Wahrscheinlich. Hängt von der Laufzeit ab. Ist das Grund genug?

Daniel Earwicker
quelle
36

Neben Leistungs- und Speicherproblemen möchte ich noch ein weiteres Problem ansprechen: Die ListSchnittstelle wäre ohne defekt int.
Das Problem ist die überladene remove()Methode ( remove(int)vs. remove(Object)). remove(Integer)würde immer beschließen, letzteres aufzurufen, so dass Sie ein Element nicht durch Index entfernen konnten.

Auf der anderen Seite gibt es eine Gefahr beim Hinzufügen und Entfernen von int:

final int i = 42;
final List<Integer> list = new ArrayList<Integer>();
list.add(i); // add(Object)
list.remove(i); // remove(int) - Ouch!
xehpuk
quelle
7
Es wäre kaputt, ja. Entfernen (int) ist jedoch ein Konstruktionsfehler IMO. Methodennamen sollten niemals überladen werden, wenn die geringste Wahrscheinlichkeit einer Verwechslung besteht.
MrBackend
4
@ MrBackend Fair genug. Interessanterweise Vectorhatte removeElementAt(int)von Anfang an. remove(int)wurde mit dem Sammlungsframework in Java 1.2 eingeführt.
Xehpuk
6
@ MrBackend: Als die ListAPI entwickelt wurde, gab es weder Generics noch Autoboxing, so dass es keine Chance gab, sich zu verwechseln remove(int)und remove(Object)
Holger
@Franklin Yu: Sicher, aber wenn Sie eine neue Sprache / Version ohne Kompatibilitätsbeschränkungen entwerfen, werden Sie nicht aufhören, diese unglückliche Überlastung zu ändern. Sie würden einfach die Unterscheidung zwischen Grundelementen und Boxwerten insgesamt aufheben, so dass die zu verwendende Frage niemals auftaucht.
Holger
27

Kannst du dir wirklich eine vorstellen?

  for (int i=0; i<10000; i++) {
      do something
  }

Schleife mit java.lang.Integer statt? Eine java.lang.Integer ist unveränderlich, sodass bei jedem Inkrementieren der Schleife ein neues Java-Objekt auf dem Heap erstellt wird, anstatt nur das int auf dem Stapel mit einem einzelnen JVM-Befehl zu inkrementieren. Die Leistung wäre teuflisch.

Ich würde wirklich nicht zustimmen, dass es viel bequemer ist, java.lang.Integer als int zu verwenden. Andererseits. Autoboxing bedeutet, dass Sie int dort verwenden können, wo Sie sonst gezwungen wären, Integer zu verwenden, und der Java-Compiler kümmert sich um das Einfügen des Codes, um das neue Integer-Objekt für Sie zu erstellen. Beim Autoboxing geht es darum, Ihnen die Verwendung eines Int zu ermöglichen, bei dem eine Ganzzahl erwartet wird, wobei der Compiler die entsprechende Objektkonstruktion einfügt. Es beseitigt oder reduziert in keiner Weise die Notwendigkeit des int in erster Linie. Mit Autoboxing bekommen Sie das Beste aus beiden Welten. Sie erhalten automatisch eine Ganzzahl, die für Sie erstellt wird, wenn Sie ein Heap-basiertes Java-Objekt benötigen, und Sie erhalten die Geschwindigkeit und Effizienz eines Int, wenn Sie nur arithmetische und lokale Berechnungen durchführen.

Tom Quarendon
quelle
19

Primitive Typen sind viel schneller:

int i;
i++;

Ganzzahl (alle Zahlen und auch eine Zeichenfolge) ist ein unveränderlicher Typ: Einmal erstellt, kann er nicht mehr geändert werden. Wenn iInteger i++wäre, würde ein neues Integer-Objekt erstellt - viel teurer in Bezug auf Speicher und Prozessor.

Peter Knego
quelle
Sie möchten nicht, dass sich eine Variable ändert, wenn Sie dies i++für eine andere Variable tun. Daher muss Integer unveränderlich sein, um dies zu tun (oder zumindest i++müsste dies ohnehin ein neues Integer-Objekt erstellen). (Und die primitiven Werte sind auch unveränderlich - Sie bemerken dies nur nicht, da sie keine Objekte sind.)
Paŭlo Ebermann
4
@ Paŭlo: Zu sagen, dass primitive Werte unveränderlich sind, ist irgendwie bedeutungslos. Wenn Sie eine primitive Variable einem neuen Wert neu zuweisen, erstellen Sie nichts Neues. Es ist keine Speicherzuordnung erforderlich. Peters Punkt lautet: i ++ für ein Grundelement führt keine Speicherzuweisung durch, für ein Objekt jedoch unbedingt.
Eddie
@Eddie: (Es benötigt nicht unbedingt Speicherzuweisung, es könnte auch einen zwischengespeicherten Wert zurückgeben. Für einige kleine Werte ist dies meiner Meinung nach der Fall.) Mein Punkt war, dass die Unveränderlichkeit von Ganzzahlen hier nicht der entscheidende Punkt ist, den Sie sowieso wollen würden ein anderes Objekt zu haben, unabhängig von der Unveränderlichkeit.
Paŭlo Ebermann
@ Paŭlo: Mein einziger Punkt war, dass Integer eine Größenordnung langsamer ist als Primitive. Dies liegt an der Tatsache, dass Boxed-Typen unveränderlich sind und jedes Mal, wenn Sie einen Wert ändern, ein neues Objekt erstellt wird. Ich habe nicht behauptet, dass etwas mit ihnen nicht stimmt oder dass sie unveränderlich sind. Nur dass sie langsamer sind und dass ein Codierer das wissen sollte. Schauen Sie sich an, wie Groovy ohne primitive Typen abschneidet. Jroller.com/rants/entry/why_is_groovy_so_slow
Peter Knego
1
Unveränderlichkeit und ++ist hier ein roter Hering. Stellen Sie sich vor, Java wurde erweitert, um das Überladen von Operatoren auf wirklich einfache Weise zu unterstützen, sodass Sie, wenn eine Klasse (z. B. Integereine Methode) plus, i + 1stattdessen schreiben können i.plus(1). Nehmen Sie auch an, dass der Compiler intelligent genug ist, um i++in ihn zu expandieren i = i + 1. Jetzt können Sie sagen i++und effektiv "die Variable i inkrementieren", ohne Integerveränderlich zu sein.
Daniel Earwicker
16

In erster Linie Gewohnheit. Wenn Sie acht Jahre lang in Java codiert haben, akkumulieren Sie eine beträchtliche Menge an Trägheit. Warum ändern, wenn es keinen zwingenden Grund dafür gibt? Es ist nicht so, als ob die Verwendung von Grundelementen in Schachteln zusätzliche Vorteile mit sich bringt.

Der andere Grund ist zu behaupten, dass dies nullkeine gültige Option ist. Es wäre sinnlos und irreführend, die Summe zweier Zahlen oder einer Schleifenvariablen als zu deklarieren Integer.

Es gibt auch den Leistungsaspekt, obwohl der Leistungsunterschied in vielen Fällen nicht kritisch ist (obwohl er ziemlich schlecht ist), schreibt niemand gerne Code, der genauso einfach und schneller geschrieben werden kann, als wir es bereits sind gewöhnt an.

biziclop
quelle
15
Ich bin nicht einverstanden. Der Leistungsaspekt kann kritisch sein. Sehr wenig davon ist wahrscheinlich Trägheit oder Gewohnheit.
Eddie
7
@ Eddie Es kann sein, aber es ist sehr selten. Vertrauen Sie mir, für die meisten Menschen sind Leistungsargumente nur eine Ausrede.
Biziclop
3
Auch ich möchte das Leistungsargument schützen. Unter Android mit Dalvik erhöht jedes Objekt, das Sie erstellen, das "Risiko", dass GC aufgerufen wird, und je mehr Objekte Sie haben, desto länger werden die Pausen. Das Erstellen von Ganzzahlen anstelle von int in einer Schleife kostet Sie wahrscheinlich einige abgelegte Frames.
Igor Čordaš
1
@PSIXO Es ist ein fairer Punkt, ich habe es mit rein serverseitigem Java geschrieben. Mobile Geräte sind ein ganz anderes Tier. Mein Punkt war jedoch, dass selbst Entwickler, die ansonsten schrecklichen Code ohne Rücksicht auf die Leistung schreiben, dies als Grund anführen werden. Für sie klingt dies sehr nach einer Ausrede.
Biziclop
12

Übrigens hat Smalltalk nur Objekte (keine Grundelemente), und dennoch hatten sie ihre kleinen Ganzzahlen (mit nicht allen 32 Bits, nur 27 oder so) optimiert, um keinen Heap-Speicherplatz zuzuweisen, sondern einfach ein spezielles Bitmuster zu verwenden. Auch andere gängige Objekte (true, false, null) hatten hier spezielle Bitmuster.

Zumindest auf 64-Bit-JVMs (mit einem 64-Bit-Zeigernamensraum) sollte es also möglich sein, überhaupt keine Objekte mit Integer, Character, Byte, Short, Boolean, Float (und Small Long) zu haben (abgesehen von diesen erstellt) durch explizite new ...()) nur spezielle Bitmuster, die von den normalen Operatoren recht effizient manipuliert werden könnten.

Paŭlo Ebermann
quelle
Ich hätte "einige Implementierungen" sagen sollen, da dies meiner Meinung nach nicht durch die Sprachspezifikationen geregelt wird. (Und leider kann ich hier keine Quellen zitieren, es ist nur von dem, was ich irgendwo gehört habe.)
Paŭlo Ebermann
ŭlo, JIT hält bereits Meta im Zeiger; Inkl. kann der Zeiger GC-Informationen oder die Klass speichern (die Optimierung der Klasse ist eine viel bessere Idee als die Optimierung von Ganzzahlen, für die ich mich weniger interessieren kann). Zum Ändern des Zeigers müsste vor jedem Laden des Zeigers der Code / cmp / jnz (oder ähnliches) verschoben werden. Der Zweig wird von der Hardware wahrscheinlich nicht sehr gut vorhergesagt (da er sowohl Werttyp als auch normales Objekt sein kann) und würde zu Leistungseinbußen führen.
Bests
3
Ich habe einige Jahre Smalltalk gemacht. Die Optimierung war immer noch ziemlich teuer, da sie für jede Operation auf einem Int entlarvt und erneut angewendet werden mussten. Derzeit ist Java bei der Manipulation primitiver Zahlen mit C vergleichbar. Mit Demask + Maske wird es wahrscheinlich> 30% langsamer sein.
R. Moeller
9

Ich kann nicht glauben, dass niemand erwähnt hat, was meiner Meinung nach der wichtigste Grund ist: "int" ist so viel einfacher zu tippen als "Integer". Ich denke, die Leute unterschätzen die Wichtigkeit einer prägnanten Syntax. Die Leistung ist nicht wirklich ein Grund, sie zu vermeiden, da die meiste Zeit, wenn man Zahlen verwendet, in Schleifenindizes liegt und das Inkrementieren und Vergleichen dieser Kosten in keiner nicht trivialen Schleife (unabhängig davon, ob Sie int oder Integer verwenden) nichts kostet.

Der andere gegebene Grund war, dass Sie NPEs erhalten können, aber das ist mit Boxed-Typen extrem einfach zu vermeiden (und es wird garantiert vermieden, solange Sie sie immer mit Nicht-Null-Werten initialisieren).

Der andere Grund war, dass (new Long (1000)) == (new Long (1000)) falsch ist, aber das ist nur eine andere Art zu sagen, dass ".equals" keine syntaktische Unterstützung für Boxed-Typen hat (im Gegensatz zu den Operatoren <,>) , =, etc), also kommen wir zurück zum Grund der "einfacheren Syntax".

Ich denke, Steve Yegges nicht-primitives Loop-Beispiel veranschaulicht meinen Standpunkt sehr gut: http://sites.google.com/site/steveyegge2/language-trickery-and-ejb

Denken Sie darüber nach: Wie oft verwenden Sie Funktionstypen in Sprachen, die eine gute Syntax für sie haben (wie jede funktionale Sprache, Python, Ruby und sogar C), im Vergleich zu Java, wo Sie sie mithilfe von Schnittstellen wie Runnable und Callable und simulieren müssen namenlose Klassen.

CromTheDestroyer
quelle
8

Einige Gründe, Primitive nicht loszuwerden:

  • Abwärtskompatibilität.

Wenn es beseitigt wird, würden keine alten Programme ausgeführt.

  • JVM neu schreiben.

Die gesamte JVM müsste neu geschrieben werden, um diese neue Sache zu unterstützen.

  • Größerer Speicherbedarf.

Sie müssten den Wert und die Referenz speichern, wodurch mehr Speicher benötigt wird. Wenn Sie ein großes Array von Bytes haben, ist die Verwendung von byte's erheblich kleiner als die Verwendung von Byte' s.

  • Nullzeigerprobleme.

Zu deklarieren, int idann Sachen zu machen, iwürde zu keinen Problemen führen, aber zu deklarieren Integer iund dann dasselbe zu tun, würde zu einer NPE führen.

  • Gleichstellungsfragen.

Betrachten Sie diesen Code:

Integer i1 = 5;
Integer i2 = 5;

i1 == i2; // Currently would be false.

Wäre falsch. Die Bediener müssten überlastet werden, und das würde zu einer umfassenden Umschreibung führen.

  • Langsam

Objekt-Wrapper sind erheblich langsamer als ihre primitiven Gegenstücke.

Anubian Noob
quelle
i1 == i2; wäre nur falsch, wenn i1> = 128. Also, aktuelles Beispiel ist falsch
Geniy
7

Objekte sind viel schwerer als primitive Typen, daher sind primitive Typen viel effizienter als Instanzen von Wrapper-Klassen.

Primitive Typen sind sehr einfach: Zum Beispiel ist ein int 32 Bit groß und nimmt genau 32 Bit im Speicher ein und kann direkt bearbeitet werden. Ein Integer-Objekt ist ein vollständiges Objekt, das (wie jedes Objekt) auf dem Heap gespeichert werden muss und auf das nur über einen Verweis (Zeiger) zugegriffen werden kann. Es nimmt höchstwahrscheinlich auch mehr als 32 Bit (4 Bytes) Speicher in Anspruch.

Die Tatsache, dass Java zwischen primitiven und nicht-primitiven Typen unterscheidet, ist jedoch auch ein Zeichen des Alters der Java-Programmiersprache. Neuere Programmiersprachen haben diese Unterscheidung nicht; Der Compiler einer solchen Sprache ist intelligent genug, um selbst herauszufinden, ob Sie einfache Werte oder komplexere Objekte verwenden.

Zum Beispiel gibt es in Scala keine primitiven Typen; Es gibt eine Klasse Int für ganze Zahlen, und ein Int ist ein reales Objekt (auf das Sie Methoden anwenden können usw.). Wenn der Compiler Ihren Code kompiliert, verwendet er hinter den Kulissen primitive Ints. Die Verwendung eines Int ist also genauso effizient wie die Verwendung eines primitiven Int in Java.

Umesh K.
quelle
1
Ich hätte angenommen, dass die JRE "klug" genug wäre, um dies auch mit Java-umschlossenen Grundelementen zu tun. Scheitern.
Naftuli Kay
7

Zusätzlich zu dem, was andere gesagt haben, werden primitive lokale Variablen nicht vom Heap zugewiesen, sondern auf dem Stapel. Objekte werden jedoch vom Heap zugeordnet und müssen daher mit Müll gesammelt werden.

Eddie
quelle
3
Entschuldigung, das ist falsch. Eine intelligente JVM kann Escape-Analysen für alle Objektzuordnungen durchführen und, falls sie nicht entkommen können, diese auf dem Stapel zuordnen.
Rlibby
2
Ja, das ist Anfang ein Merkmal der modernen JVMs sein. In fünf Jahren wird das, was Sie sagen, für die meisten JVMs gelten, die dann verwendet werden. Heute ist es nicht. Ich hätte dies fast kommentiert, aber beschlossen, es nicht zu kommentieren. Vielleicht hätte ich etwas sagen sollen.
Eddie
6

Primitive Typen haben viele Vorteile:

  • Einfacherer Code zum Schreiben
  • Die Leistung ist besser, da Sie kein Objekt für die Variable instanziieren
  • Da sie keinen Verweis auf ein Objekt darstellen, muss nicht nach Nullen gesucht werden
  • Verwenden Sie primitive Typen, es sei denn, Sie müssen die Boxfunktionen nutzen.
Adriana
quelle
5

Es ist schwer zu wissen, welche Optimierungen unter der Decke stattfinden.

Für den lokalen Gebrauch erwarte ich, dass die Leistung gleich oder ähnlich ist , wenn der Compiler über genügend Informationen verfügt, um Optimierungen ohne die Möglichkeit des Nullwerts vorzunehmen .

Anordnungen von Grundelementen unterscheiden sich jedoch offensichtlich stark von Sammlungen von Grundelementen in Schachteln. Dies ist sinnvoll, da nur sehr wenige Optimierungen tief in einer Sammlung möglich sind.

Darüber hinaus Integerhat es einen viel höheren logischen Overhead im Vergleich zu int: Jetzt müssen Sie sich Gedanken darüber machen, ob int a = b + c;eine Ausnahme ausgelöst wird oder nicht .

Ich würde die Grundelemente so oft wie möglich verwenden und mich auf die Factory-Methoden und Autoboxing verlassen, um mir die semantisch leistungsfähigeren Box-Typen zu geben, wenn sie benötigt werden.

Matthew Willis
quelle
5
int loops = 100000000;

long start = System.currentTimeMillis();
for (Long l = new Long(0); l<loops;l++) {
    //System.out.println("Long: "+l);
}
System.out.println("Milliseconds taken to loop '"+loops+"' times around Long: "+ (System.currentTimeMillis()- start));

start = System.currentTimeMillis();
for (long l = 0; l<loops;l++) {
    //System.out.println("long: "+l);
}
System.out.println("Milliseconds taken to loop '"+loops+"' times around long: "+ (System.currentTimeMillis()- start));

Millisekunden, die benötigt werden, um '100000000' mal um Long zu schleifen: 468

Millisekunden, die benötigt werden, um '100000000'-Zeiten lang zu durchlaufen: 31

Nebenbei bemerkt, es würde mir nichts ausmachen, wenn so etwas seinen Weg nach Java findet.

Integer loop1 = new Integer(0);
for (loop1.lessThan(1000)) {
   ...
}

Wobei die for-Schleife loop1 automatisch von 0 auf 1000 oder 1000 erhöht

Integer loop1 = new Integer(1000);
for (loop1.greaterThan(0)) {
   ...
}

Wobei die for-Schleife loop1 1000 automatisch auf 0 dekrementiert.

Keith
quelle
2
  1. Sie benötigen Grundelemente für mathematische Operationen
  2. Primitive benötigen weniger Speicher wie oben beantwortet und bieten eine bessere Leistung

Sie sollten sich fragen, warum ein Klassen- / Objekttyp erforderlich ist

Der Grund für den Objekttyp ist, unser Leben im Umgang mit Sammlungen zu erleichtern. Grundelemente können nicht direkt zu List / Map hinzugefügt werden, sondern Sie müssen eine Wrapper-Klasse schreiben. Readymade Integer-Klassen helfen Ihnen hier und es gibt viele Dienstprogrammmethoden wie Integer.pareseInt (str)

Prabakaran
quelle
2

Ich stimme früheren Antworten zu, die Verwendung von primitiven Wrapper-Objekten kann teuer sein. Wenn die Leistung in Ihrer Anwendung jedoch nicht kritisch ist, vermeiden Sie Überläufe bei der Verwendung von Objekten. Beispielsweise:

long bigNumber = Integer.MAX_VALUE + 2;

Der Wert von bigNumberist -2147483647, und Sie würden erwarten, dass er 2147483649 beträgt. Dies ist ein Fehler im Code, der behoben werden würde, indem Folgendes ausgeführt wird:

long bigNumber = Integer.MAX_VALUE + 2l; // note that '2' is a long now (it is '2L').

Und bigNumberwäre 2147483649. Diese Art von Fehlern ist manchmal leicht zu übersehen und kann zu unbekanntem Verhalten oder Schwachstellen führen (siehe CWE-190 ).

Wenn Sie Wrapper-Objekte verwenden, wird der entsprechende Code nicht kompiliert.

Long bigNumber = Integer.MAX_VALUE + 2; // Not compiling

Daher ist es einfacher, diese Art von Problemen zu stoppen, indem Sie primitive Wrapper-Objekte verwenden.

Ihre Frage ist bereits so beantwortet, dass ich nur antworte, um ein bisschen mehr Informationen hinzuzufügen, die zuvor nicht erwähnt wurden.

Fernando Garcia
quelle
1

Weil JAVA alle mathematischen Operationen in primitiven Typen ausführt. Betrachten Sie dieses Beispiel:

public static int sumEven(List<Integer> li) {
    int sum = 0;
    for (Integer i: li)
        if (i % 2 == 0)
            sum += i;
        return sum;
}

Hier können Erinnerungs- und unäre Plus-Operationen nicht auf den Integer-Typ (Referenz) angewendet werden. Der Compiler führt das Unboxing durch und führt die Operationen aus.

Stellen Sie also sicher, wie viele Autoboxing- und Unboxing-Vorgänge im Java-Programm ausgeführt werden. Seitdem dauert es einige Zeit, um diese Vorgänge auszuführen.

Im Allgemeinen ist es besser, Argumente vom Typ Referenz und Ergebnis vom primitiven Typ beizubehalten.

user3462649
quelle
1

Die primitiven Typen sind viel schneller und benötigen viel weniger Speicher . Daher möchten wir sie vielleicht lieber verwenden.

Andererseits erlaubt die aktuelle Java-Sprachspezifikation nicht die Verwendung primitiver Typen in den parametrisierten Typen (Generika), in den Java-Sammlungen oder in der Reflection-API.

Wenn unsere Anwendung Sammlungen mit einer großen Anzahl von Elementen benötigt, sollten wir in Betracht ziehen, Arrays mit einem möglichst „wirtschaftlichen“ Typ zu verwenden.

* Detaillierte Informationen finden Sie in der Quelle: https://www.baeldung.com/java-primitives-vs-objects

Arun Joshla
quelle
0

Um es kurz zu machen: Primitive Typen sind schneller und benötigen weniger Speicher als Boxed-Typen

Weißer Link
quelle