A Modern Primitive Discussion
A lot can be said — and a lot has been said — about Java's inclusion of primitive types. You know, types like int, long, byte, char, and so on (eight of them in total). And in some cases, people like to throw String in there because it acts a little like a primitive since it's immutable. However, the String class isn't a primitive since it's truly a class and hence renders true objects when instantiated. But I digress.
Why are they there, when Java is purportedly an object-oriented language? Here are the main reasons:
- Primitives are comfortable (coming from C/C++)
- They're fast! Here's why:
- The stack frame contains the actual value, which can be operated on directly. With objects, however, the stack frames contain references into the heap, which contains the value(s).
- With primitives, there's no garbage collection.
- Speed of operations is faster as the value is right in the stack — again, there's no object dereferencing.
- The available operators are fixed, hence there's no ambiguity.
However, the fact that Java also includes Object-ified versions of primitives (i.e. Integer, Boolean, and so on) can lead to some confusion. So, beyond the confusion to beginners as to the differences between int and Integer, why is having primitives in Java problematic? In fact, the auto boxing and unboxing features of Java (introduced in Java 1.5) help to eliminate or at least "smooth out" these differences. For example:
Before autoboxing:
int meaning=42; Integer theMeaning = new Integer(meaning);
...after:
int meaning=42; Integer theMeaning = meaning;
...or just:
Integer theMeaning = 42;
Before unboxing (which is really just the reverse of auto boxing):
Boolean ready = new Boolean( true );
if ( ready.booleanValue() == true ) { /* … */ }
...after:
Boolean theCondition = new Boolean( true );
if ( ready ) { /* … */ }
However, a lot of confusion remains. For example, you create objects using the new keyword, and use the dot-notation to pass messages (or call methods on) the resulting objects. Neither apply to primitives. This means that operators such as ++ work directly on the values of primitives, while they (kind of) result in method calls on objects. This isn't much of a problem, really, except that with objects, you never work directly with the data, hence the variable itself doesn't change. This means that you have a chance to bounds check or otherwise perform some error checking before the value is modified. With primitives, you do not.
Things get a little more confusing, and error-prone, when you tell a new Java programmer that you can compare two primitive types as such:
int i = …
int x = …
if ( i == x ) { /* … */ }
But you cannot do this with String (or other) objects, because it compares the object references themselves, not necessarily the data they represent. For example, the following will yield unintended results:
String root = "Eric";
…
String user = "Eric";
if ( user == root ) { /*…*/ } // Not what was intended
Instead, you need to do the following:
if ( user.equals( root ) ) { /*…*/ } // Good!
With other objects, this gets even more ambiguous and error-prone:
Boolean conditionOne = new Boolean(true);
Boolean conditionTwo = new Boolean(true);
if ( conditionOne == conditionTwo ) { /*…*/ } // Error!!!

