Skip to content

Instantly share code, notes, and snippets.

@manuelp
Last active August 29, 2015 14:15
Show Gist options
  • Save manuelp/5ebabe18145a4239a2a3 to your computer and use it in GitHub Desktop.
Save manuelp/5ebabe18145a4239a2a3 to your computer and use it in GitHub Desktop.
Never, never, never use String in Java (or at least less often :-)

This is a reproduction of a blog post written by Stephan Schmidt and originally published on May 2, 2008 at this URL. This version was retrieved using the Wayback Machine. Other than some minor formatting changes and modified links, this post is a copy of the original one.

Never, never, never use (unwrapped) String or long or int. Why? Those primitive types have no semantic meaning. They are hard to understand, hard to maintain, and hard to extend. I've been evangelizing this concept for some time, the essay "Object calisthenics" finally prompted be to write this post. Suppose we have an example of a cinema ticket booking service.

Update: If you just want to drop a comment telling me how revolting you find the idea, well, just don't. I appreciate your comment, but sit back, think some time about it and move on coding. When you read someone else code with String id and you wonder what on earth the id is, come back and read this post.

Compare

public void bookTicket(
  String name, 
  String firstName, 
  String film, 
  int count, 
  String cinema);

with (and I know one would introduce an Order object for real code):

public void bookTicket(
  Name name, 
  FirstName firstName, 
  Film film, 
  Count count, 
  Cinema cinema);

The second one is much easier to understand, especially when your IDE is one that tells you during autocompletion of a method call bookTicket(String arg0, String arg1, String arg2, int arg3, String arg4) versus bookTicket(Name arg0, FirstName arg1, Film arg2, Count arg3, Cinema arg4). The second one is also much easier to read. Compare

void book(String orderId);

with

void book(OrderId order);

In the first case the developer seeing the code wonders:

  1. Where to get an orderId.
  2. What an orderId really is: "1212", "ABC-123" or "12-34-45-SCHWEINEBACKE".

In the second case he can search for the usage of the OrderId class, how it is used, read the javadoc and only pass validated and correct order ids into an application. You might think an orderId is just an orderId, easy to find. Legacy systems will change the id, the naming and semantics in often inconsistent ways. I've seen systems that name an order ID in serveral ways as "orderId", "AuftragsId", "id" and several other names and all meaning the same thing!

It's easier to have a class with semantics than a domain-less String. Developers cannot as easily mess up. If you rely on static typing and use a startic type language (both object and reference) then maximize your benefits and create more classes. In the future an OrderId class can also easily be changed to hold long instead of an int, hold validation or id generation logic. It's much harder to extend the initial String based version.

Implementation with a fluent interface

The classes should be implemented as simple Domain classes, sometimes as immutable value objects, which just wrap String and attach some semantic meaning to the String.

public class Name {
   public Name(String name) {
      ...
   } 
   public static Name name(String name) {
     return new Name(name);
   }
}

One would wonder if the solution is too noisy. Assuming

new Customer(new FirstName("Stephan"), new Name("Schmidt"));

is certainly noiser than a String argument:

new Customer("Stephan", "Schmidt");

The first is easier to understand though, and with static methods can be changed to

new Customer(firstName("Stephan"), name("Schmidt"));

This also solves the problems that with many arguments developers from reading the code don't understand what each parameter means, especially in longer (refactor to parameter object!) parameter lists. This is another approach to Fluent Interface builders.

My last post on how to use generics with immutable objects could also be extended with value objects instead of primitives.

new Point(10,10);
new Point(x(10), y(10));

where x(10) and y(10) create Xpos and Ypos value objects.

Domain objects vs. primitives in interview questions

One of the interview questions I like is to ask people about an interface for a price search. I usually give them

... searchByPrice(...)

and let candidates fill in the missing parts. Some will write

Vector searchByPrice(double start, double end)

which is bad code from several points of view (using double for money, no domain objects, untyped Vector).

Others with more domain based thinking write

List<Product> searchByPriceRange(Price start, Price end)

or even us the Range pattern by Fowler:

List<Product> searchByPriceRange(PriceRange priceToSearch)

The last solution is easy to extend and understand. Answering this question often starts an interesting discussion on interface design, maintainablity and domain modelling. Whatever you think about this interview question, don't forget to, once and for all: do not use double for money.

Thanks for listening and don't use String, int and long (or double for money).

Update

If you find the usage of Classes instead of Strings repulsive, look at another example, zip code. Most people I've seen in lots of code use a primitive for zip code which creates a lot of problems when going i18n.

Customer {
   String name;
   String street;
   String city;
   String zip;
}

(some will have used int for the zip code but get faster into trouble than the String users) instead of

Customer {
   String name;
   Address address;
} 

Address {
   ZipCode code;
}

Still think Strings are a good idea in your code or "the simplest thing that could possibly work"?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment