Should I use Primitive or Object for entity and models in Java?

Viewed 1434

As a beginner at Java, I am confused while choosing the variable types in entity or model classes. As mentioned on Java Primitives versus Objects, both of them have some pros and cons e.g. memory usage. However, I would like to know the general approach while creating entity or model classes. So, in this case, should I prefer Primitive or Object type for variables for long, boolean, int, etc. as shown below?

public class Student {
    private Long id;              // long ?
    private String name;    
    private Boolean isGraduated;  // boolean ?
    private Integer age;          // int ?
}

4 Answers

Default value of Long and Integer variable is null.

But default value of long and int is 0

Compare:

If you use Objects:

public class Student {
    private Long id;              // long ?
    private String name;    
    private Boolean isGraduated;  // boolean ?
    private Integer age;          // int ?
}

id => null
age => null

If you use primitives:

public class Student {
    private long id;              // long ?
    private String name;    
    private Boolean isGraduated;  // boolean ?
    private int age;          // int ?
}

id => 0
age => 0

In many scenarios having 0 as default value is confusing, so it makes sense to use Objects in this case. If object value is "null" you know for sure that the value was not initialized. But if primitive value is "0", then it is not clear: is it a default uninitialized value, or this value was initialized with "0".

I generally prefer using primitive types, unless I need explicit null-check

Either works

As you noted, primitives require less memory. But objects have advantages, especially in some situations where objects will be expected rather than primitives. And in some situations, a primitive may be expected, though auto-boxing generally handles that. The compiler will certainly alert you when encountering these situations.

And Skliar makes a valid point about primitives having default values while objects do not. Either might be an advantage depending on the coding situation.

Keep in mind that, for most of your work, you should not worry about this. Such worries are an example of premature optimization. You almost certainly have more important things to worry about.

For many common business apps, the memory usage is inconsequential. My own default is to use objects, for the convenience and the features. From what I have noticed over the years, usage seems fairly split with some folks tending towards primitives and some towards objects.

The only situation where I think twice about primitive-versus-object is where auto-boxing may be invoked when dealing with loops through much data. In such a case, a mere declaration of int versus Integer might make a significant impact by avoiding pointless boxing. But, again, do not worry excessively about this, as relying on auto-boxing is perfectly acceptable and is usually the best policy.

record

Java 16+ now offers the records feature. A record is a brief way to write a class whose main purpose is to communicate data transparently and immutably. You simply declare the member field types and names. The compiler implicitly generates the constructor, getters, equals & hashCode, and toString methods.

I mention records merely to say this handy new feature, likely to become very popular, supports both objects and primitives. So using records does not affect the object-versus-primitive decision.

Your example class would be:

public record Student( Long id , String name , Boolean isGraduated , Integer age ) {}

… or:

public record Student( long id , String name , boolean isGraduated , int age ) {}

Usage is the same as a conventional class.

Student alice = new Student( 101L , "Alice" , false , 33 ) ;

Blurring the difference

You should know that the Java team at Oracle, and related community, are interested in blurring the difference between primitives and objects. Of course, the trick is doing so while honoring the extreme backward-compatibility that is a hallmark of the Java platform.

Some of this work is being done as part of Project Valhalla, including the possible addition of value types to Java.

To learn more about possible future directions in this regard, see talks given by Brian Goetz of Oracle, and others. Use your favorite search engine to search for “Java JEP primitive”. You will find links to JEPs such as:

As others have noted, you can use either approach.

As Basil Bourque notes, if you are using memory usage (or some other kind of runtime efficiency measure) as your reason for deciding ... this is most likely premature optimization. The chances are that the differences will be too small to matter.


So how should you decide?

That's up to you. But >>my<< rule is:

  • If the modelling tells you that you need to be able to represent "this field is not set" (or similar), then you can1 use (say) Integer rather than int ... and consider using null to represent the "not set" case.

  • When you need to use the type as a generic parameter (as in List<Integer>) you have no choice but to use the object type. (In current versions of Java.)

  • If you have no specific reasons to use the object type (e.g. Integer) use the primitive type (e.g. int). In other words, this is my default choice.


Why is >>my<< default choice to use the primitive types?

Because of things like this:

private Integer field;  // defaults to null which may lead to an NPE

and

Integer a = ...
Integer b = ...

if (a == b) // MISTAKE

In other words, some aspects of primitive wrapper types are more susceptible to programmer error than their primitive type equivalents.


1 - The flip-side is that if you support "unset", it makes your code more complicated. If you use a nullable type to do this, then you have test for null and deal with it appropriately wherever you use the (bare) field. So, it is better to design your system so that an "unset" field is not possible.

I see no reason to use objects in your case, but also don't think that using them would greatly impact performance. Personally, if I did not have a specific reason to use objects — like for example the need for an ArrayList<Integer> or any other generic collection — I would use primitives.

Then again, if I did need a huge collection of integers I would work with arrays (e.g. int[]).

Edit: Someone in the comments asked why people prefer List<T> as opposed to traditional arrays. Collections such as ArrayList<T> are mutable and easy to work with. Compare adding an element to an ArrayList<T>:

List<MyClass> collection = new ArrayList<MyClass>();
collection.add(new MyClass());

...to adding an element to an array:

public static int[] addElement(int sourceArr[], int e)
{
    int newArr[] = new int[sourceArr.length + 1];

    for (int i = 0; i < sourceArr.length; i++)
    {
        newArr[i] = sourceArr[i];
    }

    newArr[newArr.length - 1] = e;
    return newArr;
}

// ...

int arr[] = { 1, 2, 3 };
arr = addElement(arr, 4); // { 1, 2, 3, 4 }
Related