4

I am a junior developer and I use java to do website development. I know org.apache.common.lang.StringUtils is recommended because of its null safty. But what is null safe or null safty exacty? why the codes as follows is ugly?

if( sth != null ) { ... }

GsM
  • 161
  • 1
  • 1
  • 13

4 Answers4

6

This is the most common problem to beginner to intermediate level programmer: they either don't know or don't trust the contracts they are participating in and defensively over check for nulls.

why the codes as follows is ugly?

 if( sth != null ) { ... }

It's not ugly as much as you know , but we thought it's extra check and not readable code if we have alot of null check condition in project. (For the case, if you accept where null is a valid response in terms of the contract; and ...)

But what is null safe or null safty exacty?
Below is my suggestion for "null safe" way to code according to my experienced and favorite authors.

For Collection Object Case

(1) Return empty arrays or collections, not nulls (Effective Java (See Item 43) - Joshua Bloch )

// The right way to return an array from a collection
private final List<Cheese> cheesesInStock = ...;

private static final Cheese[] EMPTY_CHEESE_ARRAY = new Cheese[0];
/**
* @return an array containing all of the cheeses in the shop.
*/
public Cheese[] getCheeses() {
     return cheesesInStock.toArray(EMPTY_CHEESE_ARRAY);
}

In similar fashion, a collection-valued method can be made to return the same immutable empty collection every time it needs to return an empty collection. The Collections.emptySet, emptyList, and emptyMapmethods provide exactly what you need, as shown below:

// The right way to return a copy of a collection
public List<Cheese> getCheeseList() {
    if (cheesesInStock.isEmpty())
     return Collections.emptyList(); // Always returns same list
   else
     return new ArrayList<Cheese>(cheesesInStock);
}

In summary, there is no reason ever to return null from an array- or collection-valued method instead of returning an empty array or collection.

(2) Don't Return Null - (Clean Code - Uncle Bob)
In many cases, special case objects are an easy remedy. Imagine that you have code like this:

List<Employee> employees = getEmployees();
if (employees != null) {
  for(Employee e : employees) {
   totalPay += e.getPay();
  }
}

Right now, getEmployees can return null, but does it have to? If we change getEmployeeso that it returns an empty list, we can clean up the code:

List<Employee> employees = getEmployees();
for(Employee e : employees) {
  totalPay += e.getPay();
}

Fortunately, Java has Collections.emptyList(), and it returns a predefined immutable list that we can use for this purpose:

public List<Employee> getEmployees() {
   if( .. there are no employees .. ) 
     return Collections.emptyList();
}

If you code this way, you will minimize the chance of NullPointerExceptions and your code will be cleaner.

Don’t Pass Null
Returning null from methods is bad, but passing null into methods is worse. Unless you are working with an API which expects you to pass null, you should avoid passing null in your code whenever possible.

Let’s look at an example to see why. Here is a simple method which calculates a metric for two points:

public class MetricsCalculator 
{
    public double xProjection(Point p1, Point p2) {
        return (p2.x – p1.x) * 1.5;
    }
…
}

What happens when someone passes null as an argument?

calculator.xProjection(null, new Point(12, 13));

We’ll get a NullPointerException, of course.

How can we fix it? We could create a new exception type and throw it:

public class MetricsCalculator 
{
    public double xProjection(Point p1, Point p2) {
        if (p1 == null || p2 == null) {
        throw InvalidArgumentException(
        "Invalid argument for MetricsCalculator.xProjection");
        }
        return (p2.x – p1.x) * 1.5;
    }
}


Is this better? It might be a little better than a nullpointerexception, but remember, we have to define a handler for InvalidArgumentException. What should the handler do? Is there any good course of action?

There is another alternative. We could use a set of assertions:

public class MetricsCalculator 
    {
        public double xProjection(Point p1, Point p2) {
        assert p1 != null : "p1 should not be null";
        assert p2 != null : "p2 should not be null";
        return (p2.x – p1.x) * 1.5;
    }
}

It’s good documentation, but it doesn’t solve the problem. If someone passes null, we’ll still have a runtime error.
In most programming languages there is no good way to deal with a null that is passed by a caller accidentally. Because this is the case, the rational approach is to forbid passing null by default. When you do, you can code with the knowledge that a null in an argument list is an indication of a problem, and end up with far fewer careless mistakes.

Extra Note: The null-return idiom is likely a holdover from the C programming language, in which array lengths are returned separately from actual arrays. In C, there is no advantage to allocating an array if zero is returned as the length.

For Non-Collection Object Case

(1) Use Null Object Pattern (old approach)
eg.(assume you are using dao pattern to access db)
All you need to do is return an empty object - say a customer entry you would have in your DAO something like.....

if (result == null) { return new EmptyUser(); }

where EmptyUser extends User and returns appropriate entries to getter calls to allow the rest of your code to know it is an empty object (id = -1 etc) code sample:

public class User {
    private int id;
    private String name;
    private String gender;
    public String getName() {
       //Code here
    }
    public void setName() {
       //Code here
    }
}

public class EmptyUser extends User {

    public int getId() {
       return -1;
    }

    public String getName() {
       return String.Empty();
   }
}

public User getEntry() {
   User result = db.query("select from users where id = 1");
   if(result == null) {
       return new EmptyUser();
   }
   else {
       return result;
    }
}

(2) Use Java 8 Optional
Indeed introducing null reference is probably one of the worse mistake in the programming languages' history even its creator Tony Hoare calls it his billion-dollar mistake.

Here are the best alternatives to null according to new Java version:

2.1. Java 8 and above

Starting from Java 8 you can use java.util.Optional.

Here is an example of how you could use it in not null return case:

public Optional<MyEntity> findMyEntity() {
    MyEntity entity = // some query here
    return Optional.ofNullable(entity);
}


2.2. Prior to Java 8

Before Java 8 you can use com.google.common.base.Optional from Google Guava.

Here is an example of how you could use it in not null return case:

public Optional<MyEntity> findMyEntity() {
    MyEntity entity = // some query here
    return Optional.fromNullable(entity);
}



Note for Null Object Pattern Vs Java 8 Optional:

I definitively prefer Optional it is much more generic and it has been adopted by Oracle and Google, 2 of the biggest IT companies in the world which give a lot of credits to it.

I would even say that Null Object Pattern doesn't make any sense anymore in Java, it is outdated, Optional is the future if you check a little bit what's new in Java 9, you will see that Oracle makes Optional go a little bit further, read this article

Ye Win
  • 2,020
  • 14
  • 21
  • 1
    *In summary, there is no reason ever to return `null` from an `array`- or `collection`-valued method instead of returning an empty array or collection.* I think that's too much of a generalization. Null often means the method had no result. There's a semantic difference between no result and an empty result. Using an empty result is obviously preferable where appropriate, but it isn't always appropriate. The same goes for empty strings. – shmosel Nov 03 '16 at 04:44
  • @shmosel, this quotes was written in Effective Java book by Joshua Bloch. Yes you/we can say that it isn't always appropriate, but it's the best way I ever seen. – Ye Win Nov 03 '16 at 04:49
  • Then I retract my comment in deference to the great Joshua Bloch. – shmosel Nov 03 '16 at 04:52
  • @shmosel, :) there have always debated about null handling cases in programming, but I just figure out the current best ways in answers as to my favorite article and my best practice, I will always appreciate any others best alternative ways for that case. – Ye Win Nov 03 '16 at 04:56
  • an empty list simply is not the same as a null list. if i give you a grocery list and say "i need these things" and the list is empty, then you will know that you don't need to buy any groceries. if i say "i need these things" and i don't give you a list at all, that is completely different. in that case, you don't know what groceries you need to buy, but you know you need to get that information some other way (such as calling `#checkFridge()`). – Lucas Ross Nov 18 '17 at 02:31
1

Null pointers are arguably the most common source of runtime crashes - they are effectively ticking time-bombs. The dreaded null-check in java is considered a code smell by most senior developers, and is usually a sign of bad design.

A far safer approach is to use a Null Object Pattern as zhc mentioned. In this case you create an uninitialized object whenever you declare it rather than let it sit as a null until populated.

An overly simplified example of this would be to always instantiate a String with "". An empty label (in my opinion) is preferable to a crash.

  • 1
    It depends on the type of application, but [fail-fast](https://en.wikipedia.org/wiki/Fail-fast) code will generally produce more correct behavior than [fail-safe](https://en.wikipedia.org/wiki/Fail-safe) code. See also [Null_Object_pattern#Criticism](https://en.wikipedia.org/wiki/Null_Object_pattern#Criticism). – shmosel Nov 03 '16 at 02:45
1

I know org.apache.common.lang.StringUtils is recommended because of its null safety.

Often with String values, code will be riddled with if (foo != null) {... for the most basic of string operations.

Apache writes a lot of Java code so it has gone to great lengths to offer helper utilities for common operations.

For example:

int i = s.indexOf('foo');    // Can throw NullPointerException!
String b = s.toUpperCase();  // Can throw NullPointerException!!
if (s.equals('bar')          // Can throw NullPointerException!!!
   // ...

If you start reading through the StringUtils class you'll notice null is handled over and over -- indexOf, upperCase, equals -- all cover null safety. This can drastically simplify your code.

From apache.org:

"StringUtils handles null input Strings quietly. That is to say that a null input will return null. Where a boolean or int is being returned details vary by method"

From my experience, the decision to use StringUtils is directly influenced by how many if (foo == null) { ... statements you use in the project combined with whether or not a dependency you have in your code already imports this particular utility/library -- all subject to change over the lifespan of a project.

tresf
  • 7,103
  • 6
  • 40
  • 101
  • I am confused. I am curious why I should use, for example, ```StringUtils.isEmpty(s)``` instead of ```if(s != null)``` since they both of only one sentence for code clean. – GsM Nov 06 '16 at 08:55
  • @GsM there are two reasons.... 1. Many coders prefer to treat `null` as an empty string ([Classes do this automagically](http://stackoverflow.com/a/18226538/3196753)) so this can save an additional check for programmers. 2. Without it, code tends to "walk to the right", so to speak as you introduce more potentially `null` variables since each variable requires an additional conditional statement. Personally speaking, I don't use `StringUtils`, but over the years I've said the same about most Apache utilities, some of which I've changed my mind and since started using. – tresf Nov 07 '16 at 03:56
0

Code with null checking is not ugly. For example, if you check some code in C or Go languages, they are full of null checkings. Also, about your "null safe" way. I think it is some kind of using Null Object pattern from GoF.

zhc
  • 53
  • 1
  • 5
  • It is ugly, and just because one more limitation of java language. this could be easily solved with nulable operator: `Person x = foo.bar()?.parent`. Java has many ugly limitations, like multiple returns of a function, n-uple implementation, etc. – Maxwell s.c Nov 24 '20 at 15:15