Item 61: Prefer primitive types to boxed primitives

61. Primitive type should be selected from boxed primitive type

Differences between boxed primitive types and primitive types

As mentioned in Item 6, autoboxing and autounboxing obscure the difference between boxed primitive types (hereinafter boxed primitives) and primitive types (hereinafter primitives). However, there are differences between the two, and you must be aware of the differences when using them. There are three differences

Example of error when using boxed primitive

primitive has only a value, but boxed primitive has a reference different from the value

At first glance, the code below looks like a method that makes a good comparison.

// Broken comparator - can you spot the flaw?
Comparator<Integer> naturalOrder =
    (i, j) -> (i < j) ? -1 : (i == j ? 0 : 1);

However, if you use this method like ``` naturalOrder.compare (new Integer (42), new Integer (42))` ``, it should return 0 because it is supposed to be equal, but it actually returns 1. .. The first decision (i <j) is auto-unboxed and works correctly. On the other hand, the second judgment (i == j) looks at the equivalence, that is, whether the references are the same. Therefore, this comparison is not true and 1 is returned as a result. It is usually wrong to use the == operator for boxed primitives.

To prevent the above error, use `Comparator.naturalOrder ()`, or if you write the comparator yourself, make a primitive comparison as follows.

Comparator<Integer> naturalOrder = (iBoxed, jBoxed) -> {
    int i = iBoxed, j = jBoxed; // Auto-unboxing
    return i < j ? -1 : (i == j ? 0 : 1);
};

A primitive can only have a functional value, but a boxed primitive can have null (nonfunctional value)

In the following program, nullpo occurs.

package tryAny.effectiveJava;

public class BoxedPrimitive {
    static Integer i;

    public static void main(String[] args) {
        if (i == 42)
            System.out.println("Unbelievable");
    }

}

At i == 47, we are comparing Integer and int. In a process where boxed primitive and primitive are mixed, ** In most cases, boxed primitive is auto-unboxed. ** ** Unboxing an object that references null causes a nullpo, which is happening here.

primitive is better in terms of time and memory space

The following is the program handled in Item6.

package tryAny.effectiveJava;

public class BoxedPrimitive2 {
    // Hideously slow program! Can you spot the object creation?
    public static void main(String[] args) {
        Long sum = 0L;
        for (long i = 0; i < Integer.MAX_VALUE; i++) {
            sum += i;
        }
        System.out.println(sum);
    }

}

This is much slower than when the type of a local variable is set to long, because boxing and unboxing occur repeatedly.

Summary

There were three issues, the first two had bad results and the last one had poor performance.

There are the following cases when using the boxed primitive.

Recommended Posts

Item 61: Prefer primitive types to boxed primitives
Item 89: For instance control, prefer enum types to readResolve
Item 28: Prefer lists to arrays
Item 65: Prefer interfaces to reflection
Item 43: Prefer method references to lambdas
Item 39: Prefer annotations to naming patterns
Item 85: Prefer alternatives to Java serialization
Item 41: Use marker interfaces to define types
Item 58: Prefer for-each loops to traditional for loops
Item 23: Prefer class hierarchies to tagged classes
Item 81: Prefer concurrency utilities to wait and notify
Item 80: Prefer executors, tasks, and streams to threads
Item 47: Prefer Collection to Stream as a return type
Item 29: Favor generic types