Programing

사람들이 왜 여전히 Java에서 기본 유형을 사용합니까?

crosscheck 2020. 6. 5. 18:54
반응형

사람들이 왜 여전히 Java에서 기본 유형을 사용합니까?


Java 5부터는 기본 유형의 boxing / unboxing이있어서 등등 int으로 포장되었습니다 java.lang.Integer.

나는 (즉, 최근에 새로운 자바 프로젝트를 많이 볼 확실히 사용되는하지 (6) 경우, 적어도 버전 5의 JRE를 필요로) int보다는 java.lang.Integer그것이 후자를 사용하는 것이 훨씬 더 편리하지만 그것을 변환하는 몇 가지 헬퍼 메소드를 가지고로, 행 long값 등의 알.

왜 일부는 여전히 Java에서 기본 유형을 사용합니까? 실질적인 이점이 있습니까?


Joshua Bloch의 Effective Java , 항목 5 : "불필요한 오브젝트 작성을 피하십시오"에서 다음 코드 예제를 게시합니다.

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

실행하는 데 43 초가 걸립니다. Long을 프리미티브로 가져 가면 6.8 초로 줄어 듭니다. 이것이 프리미티브를 사용하는 이유에 대한 증거라면.

고유 가치 평등의 부족 또한 우려됩니다 ( .equals()에 비해 상당히 장황합니다 ==)

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

결과 :

false
false
true
false

편집 왜 (3)이 반환 true되고 (4)가 반환 false됩니까?

그것들은 두 개의 다른 객체이기 때문입니다. 0에 가장 가까운 256 개의 정수 [-128; 127]는 JVM에 의해 캐시되므로 동일한 객체를 반환합니다. 그러나이 범위를 넘어 서면 캐시되지 않으므로 새 객체가 만들어집니다. 더 복잡하게하기 위해 JLS 는 최소 256 개의 플라이 웨이트를 캐시해야합니다. JVM 구현자는 원하는 경우 더 많은 것을 추가 할 수 있습니다. 즉, 가장 가까운 1024가 캐시되어 모두 true를 반환하는 시스템에서 실행될 수 있습니다 ... #awkward


자동 박스 해제로 인해 NPE를 찾기가 어려울 수 있습니다.

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

대부분의 경우 null 할당 in은 위의 것보다 훨씬 덜 명확합니다.


박스형은 성능이 떨어지고 더 많은 메모리가 필요합니다.


기본 유형 :

int x = 1000;
int y = 1000;

이제 평가하십시오 :

x == y

그것은이다 true. 놀랍지 않습니다. 이제 박스 타입을 사용해보십시오 :

Integer x = 1000;
Integer y = 1000;

이제 평가하십시오 :

x == y

그것은이다 false. 아마. 런타임에 따라 다릅니다. 그 이유는 충분합니까?


성능 및 메모리 문제 외에도 다른 문제가 발생합니다. List인터페이스 가없이 손상되었습니다 int.
문제는 오버로드 된 remove()방법 ( remove(int)vs. remove(Object))입니다. remove(Integer)항상 후자를 호출하여 해결할 수 있으므로 색인으로 요소를 제거 할 수 없습니다.

반면에 int: 를 추가하고 제거하려고 할 때 함정이 있습니다 .

final int i = 42;
final List<Integer> list = new ArrayList<Integer>();
list.add(i); // add(Object)
list.remove(i); // remove(int) - Ouch!

당신은 정말 상상할 수 있습니까

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

대신 java.lang.Integer로 루프? java.lang.Integer는 변경할 수 없으므로 루프마다 증가 할 때마다 단일 JVM 명령으로 스택에서 int를 증가시키는 대신 힙에 새로운 Java 객체를 작성합니다. 성능은 악마적일 것입니다.

I would really disagree that it's much mode convenient to use java.lang.Integer than int. On the contrary. Autoboxing means that you can use int where you would otherwise be forced to use Integer, and the java compiler takes care of inserting the code to create the new Integer object for you. Autoboxing is all about allowing you to use an int where an Integer is expected, with the compiler inserting the relevant object construction. It in no way removes or reduces the need for the int in the first place. With autoboxing you get the best of both worlds. You get an Integer created for you automatically when you need a heap based java object, and you get the speed and efficiency of an int when you are just doing arithmetic and local calculations.


Primitive types are much faster:

int i;
i++;

Integer (all Numbers and also a String) is an immutable type: once created it can not be changed. If i was Integer, than i++ would create a new Integer object - much more expensive in terms of memory and processor.


First and foremost, habit. If you've coded in Java for eight years, you accumulate a considerable amount of inertia. Why change if there is no compelling reason to do so? It's not as if using boxed primitives comes with any extra advantages.

The other reason is to assert that null is not a valid option. It would be pointless and misleading to declare the sum of two numbers or a loop variable as Integer.

There's the performance aspect of it too, while the performance difference isn't critical in many cases (though when it is, it's pretty bad), nobody likes to write code that could be written just as easily in a faster way we're already used to.


By the way, Smalltalk has only objects (no primitives), and yet they had optimized their small integers (using not all 32 bits, only 27 or such) to not allocate any heap space, but simply use a special bit pattern. Also other common objects (true, false, null) had special bit patterns here.

So, at least on 64-bit JVMs (with a 64 bit pointer namespace) it should be possible to not have any objects of Integer, Character, Byte, Short, Boolean, Float (and small Long) at all (apart from these created by explicit new ...()), only special bit patterns, which could be manipulated by the normal operators quite efficiently.


I can't believe no one has mentioned what I think is the most important reason: "int" is so, so much easier to type than "Integer". I think people underestimate the importance of a concise syntax. Performance isn't really a reason to avoid them because most of the time when one is using numbers is in loop indexes, and incrementing and comparing those costs nothing in any non-trivial loop (whether you're using int or Integer).

The other given reason was that you can get NPEs but that's extremely easy to avoid with boxed types (and it is guaranteed to be avoided as long as you always initialize them to non-null values).

The other reason was that (new Long(1000))==(new Long(1000)) is false, but that's just another way of saying that ".equals" has no syntactic support for boxed types (unlike the operators <, >, =, etc), so we come back to the "simpler syntax" reason.

I think Steve Yegge's non-primitive loop example illustrates my point very well: http://sites.google.com/site/steveyegge2/language-trickery-and-ejb

Think about this: how often do you use function types in languages that have good syntax for them (like any functional language, python, ruby, and even C) compared to java where you have to simulate them using interfaces such as Runnable and Callable and nameless classes.


Couple of reasons not to get rid of primitives:

  • Backwards compatability.

If it's eliminated, any old programs wouldn't even run.

  • JVM rewrite.

The entire JVM would have to be rewritten to support this new thing.

  • Larger memory footprint.

You'd need to store the value and the reference, which uses more memory. If you have a huge array of bytes, using byte's is significantly smaller than using Byte's.

  • Null pointer issues.

Declaring int i then doing stuff with i would result in no issues, but declaring Integer i and then doing the same would result in an NPE.

  • Equality issues.

Consider this code:

Integer i1 = 5;
Integer i2 = 5;

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

Would be false. Operators would have to be overloaded, and that would result in a major rewrite of stuff.

  • Slow

Object wrappers are significantly slower than their primitive counterparts.


Objects are much more heavyweight than primitive types, so primitive types are much more efficient than instances of wrapper classes.

Primitive types are very simple: for example an int is 32 bits and takes up exactly 32 bits in memory, and can be manipulated directly. An Integer object is a complete object, which (like any object) has to be stored on the heap, and can only be accessed via a reference (pointer) to it. It most likely also takes up more than 32 bits (4 bytes) of memory.

That said, the fact that Java has a distinction between primitive and non-primitive types is also a sign of age of the Java programming language. Newer programming languages don't have this distinction; the compiler of such a language is smart enough to figure out by itself if you're using simple values or more complex objects.

For example, in Scala there are no primitive types; there is a class Int for integers, and an Int is a real object (that you can methods on etc.). When the compiler compiles your code, it uses primitive ints behind the scenes, so using an Int is just as efficient as using a primitive int in Java.


In addition to what others have said, primitive local variables are not allocated from the heap, but instead on the stack. But objects are allocated from the heap and thus have to be garbage collected.


Primitive types have many advantages:

  • Simpler code to write
  • Performance is better since you are not instantiating an object for the variable
  • Since they do not represent a reference to an object there is no need to check for nulls
  • Use primitive types unless you need to take advantage of the boxing features.

It's hard to know what kind of optimizations are going on under the covers.

For local use, when the compiler has enough information to make optimizations excluding the possibility of the null value, I expect the performance to be the same or similar.

However, arrays of primitives are apparently very different from collections of boxed primitives. This makes sense given that very few optimizations are possible deep within a collection.

Furthermore, Integer has a much higher logical overhead as compared with int: now you have to worry about about whether or not int a = b + c; throws an exception.

I'd use the primitives as much as possible and rely on the factory methods and autoboxing to give me the more semantically powerful boxed types when they are needed.


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

Milliseconds taken to loop '100000000' times around Long: 468

Milliseconds taken to loop '100000000' times around long: 31

On a side note, I wouldn't mind seeing something like this find it's way into Java.

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

Where the for loop automatically increments loop1 from 0 to 1000 or

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

Where the for loop automatically decrements loop1 1000 to 0.


  1. You need primitives for doing mathematical operations
  2. Primitives takes less memory as answered above and better performing

You should ask why Class/Object type is required

Reason for having Object type is to make our life easier when we deal with Collections. Primitives cannot be added directly to List/Map rather you need to write a wrapper class. Readymade Integer kind of Classes helps you here plus it has many utility methods like Integer.pareseInt(str)


I agree with previous answers, using primitives wrapper objects can be expensive. But, if performance is not critical in your application, you avoid overflows when using objects. For example:

long bigNumber = Integer.MAX_VALUE + 2;

The value of bigNumber is -2147483647, and you would expect it to be 2147483649. It's a bug in the code that would be fixed by doing:

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

And bigNumber would be 2147483649. These kind of bugs sometimes are easy to be missed and can lead to unknown behavior or vulnerabilities (see CWE-190).

If you use wrapper objects, the equivalent code won't compile.

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

So it's easier to stop these kind of issues by using primitives wrapper objects.

Your question is so answered already, that I reply just to add a little bit more information not mentioned before.


Because JAVA performs all mathematical operations in primitive types. Consider this example:

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

Here, reminder and unary plus operations can not be applied on Integer(Reference) type, compiler performs unboxing and do the operations.

So, make sure how many autoboxing and unboxing operations happen in java program. Since, It takes time to perform this operations.

Generally, it is better to keep arguments of type Reference and result of primitive type.


The primitive types are much faster and require much less memory. Therefore, we might want to prefer using them.

On the other hand, current Java language specification doesn’t allow usage of primitive types in the parametrized types (generics), in the Java collections or the Reflection API.

When our application needs collections with a big number of elements, we should consider using arrays with as more “economical” type as possible, as it’s illustrated on the plot above.

*For detailed info see the source : https://www.baeldung.com/java-primitives-vs-objects

참고URL : https://stackoverflow.com/questions/5199359/why-do-people-still-use-primitive-types-in-java

반응형