Often times, primitives (strings and numbers in particular) have special meaning. Phone numbers, addresses, email addresses, usernames… all of those are either numbers of strings, but those are numbers or strings with some associated “behaviour”, specially in terms of how they are represented or validated.

For example, consider a class that models a User. The proper way of modelling an User using a POJO would be something like this:

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

classUser{

privatefinalStringname;

privatefinalStringsurname;

privatefinalStringuserId;

privatefinalStringemailAddress;

publicUser(Stringname,Stringsurname,StringuserId,StringemailAddress){

this.name=name;

this.surname=surname;

this.userId=userId;

this.emailAddress=emailAddress;

}

publicStringgetName(){

returnname;

}

publicStringgetSurname(){

returnsurname;

}

publicStringgetEmail(){

returnemailAddress;

}

}

That class would pass 99% of code reviews without a single comment. It is immutable, it encapsulates the user data properly, and it does not expose anything it should not expose.

Promoting primitives to objects

Let’s discuss first the email address. An email address can be represented as a string, but there is some behaviour associated to it, because not all strings are valid email addresses. Email addresses need to be validated!

So, representing an email address as a string means that it will need to be validated every time it is going to be used.

However, if we have an EmailAddress class, we can either guarantee that instances of that class will only be created when they are provided a valid email address (as a string) or declare a method that validates the address.

If we did that, the previous constructor could be rewritten as:

Java

1

2

3

4

5

6

publicUser(Stringname,Stringsurname,StringuserId,Email emailAddress){

this.name=name;

this.surname=surname;

this.userId=userId;

this.emailAddress=emailAddress;

}

Now, what about the name and surname? Well, we might want to add some behaviour to them as well, but I think the most compelling reason to promote them to objects would be type safety. Check this out:

Now, it is impossible to mess up the order of the arguments. The compiler will complain loudly as soon as you do not pass the right thing at the right place.

Isn’t that unnecessary complexity?

I wouldn’t say so. I would say that it is proper object orientation. A first name is not a string, although it is usually represented as a string, the same way an email address is not a string, but something with semantic value that, yes, can be represented as a string.

Now, obviously, this means more classes and most likely more objects living within the application cycle. True.

But software engineering is all about considering and balancing the trade-offs. And in this case, an extra class is a price I’m willing to pay in exchange for safer, more robust, and more cohesive code.