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

4

8

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

Scrabble answered 15/5, 2021 at 0:29 Comment(6)
You should consider about the nullability of the field. If it can be null you should use ObjectInterstellar
This question is really opinion based which isn't probably on topic here. However I rarely see anyone use the boxed primitives outside of generics.Placard
@HenryTwist The "opinion-based" policy of Stack Overflow is aimed at avoiding long-winded open-ended discussions that are not likely to resolve. I do not see that necessarily applying to this Question. There are specific technical pros and cons that can be presented as considerations for any programmer making the decision between objects and primitives.Keenakeenan
@LêHoàngDững Very important point that I had encountered a serious problem with Boolean. Thanks a lot, I will keep it in mind.Scrabble
It is matter of codestyle. But using primitive types for fields is way more common practice. One thing to note if you go with object wrappers best practice is to annotate public API with nullable annotations to explicitly tell if null reference is acceptable. You don't have to do this for primitives since they can not be null. As alternative there is OptionalInt and similar containers for optional values that are self documenting.Coca
@Sokolov Very useful comments that complete other answers. Thanks a lot.Scrabble
B
10

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

Bennettbenni answered 15/5, 2021 at 0:57 Comment(0)
K
11

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:

Keenakeenan answered 15/5, 2021 at 0:59 Comment(1)
Thanks a lot for perfect explanations, voted up.Scrabble
B
10

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

Bennettbenni answered 15/5, 2021 at 0:57 Comment(0)
R
4

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

if (a < b)  // Compilation error

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 "not set", it makes your code more complicated. When you use a nullable type to do this, then you have to remember to test for null and deal with it appropriately wherever you use the (bare) field. Unless there is a clear business need for this feature, it is better to design your system so that "not set" fields are not possible.

Roorback answered 15/5, 2021 at 1:40 Comment(1)
Thanks a lot for perfect explanations, voted up.Scrabble
C
0

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 }
Capricecapricious answered 15/5, 2021 at 0:37 Comment(2)
But as far as I see, people seems to prefer List<T> instead of Array ([]). Any idea?Scrabble
Collections such as ArrayList<T> are mutable so they are easier to work with: you can easily add and remove elements (e.g. via methods such as List<T>.add(T e)). Arrays ([]) are immutable so each time you need to expand/shrink your collection you actually have to declare a new array instance with the new size and place your element there.Capricecapricious

© 2022 - 2024 — McMap. All rights reserved.