Do Primitives Need To Go?

John Hoestje Java, Opinion 3 Comments

I am currently working on an enterprise application using JSF as the view technology and JPA for the persistence layer. It may have been something in a backing bean or service method, but it struck me: Is there a good reason to use primitives anymore in enterprise applications?

When I started programming with Java around J2SE 1.2 (or was it J2SE 5.0, or maybe Java 2?), I only used primitives in my code. At that time, I thought it was nice I could rely on the default values instead of having to initialize something before I could use it. I didn’t know too much about wrappers at the time, and didn’t think I had a good reason to look into them any further.

I don’t have any clear memories of when I started to use the primitive wrappers, but I do remember when JDK 1.5 allowed for the automatic conversions between primitives and their respective primitive wrapper classes or commonly known as autoboxing/unboxing. This was nice as it didn’t matter if an int was passed to a method requiring an Integer or vice versa. It was syntactic sugar that seemingly made programming a little easier.


Even though Java enterprise frameworks such as JSF and JPA do a lot of work for you, it also exposes some of the weaknesses of relying on autoboxing and primitives.

These frameworks rely on the use of the primitive wrapper class instead of the respective primitive. If you use the JPA tool to create an entity based on an existing table, the tool will use the wrapper for the variable type. JSF inputs and converters operate on objects. With JPA, it has to. Remember the primitive defaults? A primitive’s default value can be confused with what is stored in the database.

If long was used as a simple entity id, the entity would have a default value of 0L. 0L is technically a value, so it makes it difficult to know whether the entity has been persisted or not. If id is of type Long, then it is easy to tell if the entity has been persisted since the id can now be null and therefore representing an un-persisted entity.

//id is long and entity is not persisted
long id = entity.getId();  //value of 0L
Long id = entity.getId();  //doesn’t help, still 0L

//id is Long and entity is not persisted
Long id = entity.getId();  //null
long id = entity.getId();  //what happens here?

Type Context

Primitive types do not adequately express the semantic context of the value. Let’s say we retrieve today’s temperature from a service and the returned value representing degrees is an int. Is it easy to determine what the context of int degrees is?

See Also:  Spring Batch Testing & Mocking Revisited with Spring Boot

First, is the value represented in celsius or fahrenheit? Second, what if the value is 0? You would have to assume the value was actually set and it isn’t the default value of 0. You may wonder why it feels like 70 degrees outside when the service says it’s 0.

Instead of using a primitive or even a primitive wrapper, the best solution may be to use a custom object that resolves to a proper value. For our value representing temperature, we could create a Fahrenheit object. This object would remove all doubt on the context of the value.

public class Fahrenheit {
	private Integer degrees;

Fahrenheit f = temperatureService.getDegrees(today);


A developer wouldn’t be able to accidently pass in a Celsius object when the method is expecting Fahrenheit.

public Celsius convertDegrees(Fahrenheit f) {

//only this would work
Celsius c = temperatureService.convertDegrees(f);


Using a primitive as a return value can also be ambiguous. Returning a boolean to represent if something worked or not doesn’t necessarily represent what did happen. Using a Result object is more descriptive by containing more information.


While mocking frameworks can handle primitives, mocking frameworks like to work with objects. The code snippet below is the the Expectations class in JMock. As the code snippet shows below, some autoboxing magic is allowing the framework to set the expectation that a int value of 6 will be returned.

Expectations.returnValue(Object result):        

  context.checking(new Expectations() {


JMock seems to handle primitive arrays properly since the object for arrays is dynamically created.

Expectations.returnValue(Object result):        

  context.checking(new Expectations() {
           	int[] ints = { 2, 3 };

Image 2

Even though primitives and primitive arrays worked with mocking frameworks, it feels like you are not working with the real values. Your parameter is an int, but the mocking framework would like you to use Integer.


Looking back at the history of the primitive wrappers, the increased functionality of the wrappers over time, autoboxing/unboxing, and reading articles from developers from other languages, it feels like primitives could have been left out of the initial implementation of Java. Java is an object-oriented language, but contains non-object primitives. The autoboxing feature feels more like a band-aid than a real solution.

See Also:  Building a Java Cloud Native Spring Microservice Application on Azure, Part 1

I am making this specific to enterprise applications due to the fact that enterprise applications have access to generous amounts of resources. The environment makes it easier to create descriptive code that use of objects like Integer and Fahrenheit. In constrained devices where garbage collection costs and heap size matter, primitives make sense and hold an advantage over object counterparts.

— John Hoestje, [email protected]

Comments 3

  1. Interesting article and food for thought regarding application design. I’ve seen way too much code where the type context is left wanting, because good OO design was lacking. One thing, however…an application should not be designed to serve the testing tools. Testing tools should serve the application. Thus, I do not believe the challenges of mocking contribute to your point. Otherwise, I think this is an article that can be expanded in a follow-up, possibly even a discussion of specific primitive types and how each one compares to its wrapper.

  2. Primitives are hard to work with, but their existence is fundamental to many things. I think in certain problem domains and at certain limited scale you can abandon primitives in favor of boxed types, but I can speak from absolute experience that when you’re deref is a tremendous cost, such as working with fast moving binary streams of data.

    Staying on the stack is critical for memory pressure and cache coherence in many scenarios, and in fact I think the future of Java is to make primitives better citizens in the Java space. See:

    Value Type Specialization:
    Primitives in Streams:
    Value Types:
    Packed Objects:
    Object Layout:

    Admittedly, not all Java platforms are doing high-frequency trading or high-throughput low-latency network stacks, but it’s worth understanding the cost of just throwing it away. The apparent sheer number of people now using sun.misc.Unsafe (based on mailing lists, stack-overflow, etc) to get around the forced de-refs and sometimes wasteful data layout in Java heap is a sign that there is a need for this, and is where all of the above proposals were borne.

    For the platform I run, I absolutely have to focus on every heap de-ref or indirection, every synchronized or atomic point of contention (what used to be “lock much?” has become “CAS much?”), every method that might not JIT. If we want to be able to use OO concepts at the rate we process data, we need those objects to not have spaghetti off to gobs of other objects.

    At scale, pennies turn into dollars turn into servers 🙂

    The same argument could be made for platforms like Minecraft where the sheer amount of math done to generate the voxel terrain would never manage even 2-3 FPS, let alone 60 with all boxed types. Just sneaking a couple boxed types into those tight loops, and the whole thing collapses.

    On another point, one thing primitives offer that boxed types don’t is null-safety. While Java 8 finally adds Optionals, they are yet-another-heap-allocated-object, and so are often not really appropriate yet for being used at volume:
    (Java 9+ hopes to value type specialize optionals, which would allow them to be stack based whenever possible, but they aren’t now).

    Java 8 also added the custom annotation-based type system, so you can start to use @NotNull in a standard way, which helps, but you have to be religious of its use, where-as primitives simply enforce it intuitively.

    Now, all that being said, I force our payment platform to be 100% BigDecimal based so we have explicit (and strict) control of rounding and mathematical coersion, with no possibility of IEEE issues from the CPU. So I think that illustrates that problem domain matters.

    So should they leave the language? Categorically No. Can certain problem domains operate without them? Almost certainly. Should Java get better explicit support for handling primitives? Absolutely – and that’s what I hope the above proposals will start to offer.

What Do You Think?