NetBeans in the Classroom: Time to Say Goodbye to NULL as a Return Value
Join the DZone community and get the full member experience.
Join For Free
ken fogel is the program coordinator and chairperson of the computer science technology program at
dawson college
in montreal, canada. he is also a program consultant to and part-time instructor in the computer institute of
concordia university
's school of extended learning. he blogs at
omniprogrammer.com
and tweets
@omniprof
.
i loved
null
. when i taught c and then c++, i explained to my students how pointers had three states. the first state was that of a valid address to an object in memory. the second was an invalid address or garbage address that occurs when a local pointer is created or a pointer goes out of scope. unfortunately there was no way to tell a valid from an invalid address. then there was the
null
state. this is a pointer in waiting. not yet pointing at a valid object and easily recognized as such. i required my students to initialize local pointer references to
null
or to assign them a
null
after deleting them. every time a function returned a pointer the very next line of code after calling the function had to read “
if (ptr == null)
”.
when i moved on to teaching java, the pointer was gone. any student who sees their first null pointer error message may disagree but i leave that to another debate. in place of the pointer is the reference. like the c/c++ pointer, it too has three states. the major java enhancement is that the compiler will recognize that you are trying to use the invalid address state on the left hand side of an expression and will declare an error.
so that leaves us with a valid address or null. therefore, just like with c/c++, a programmer must test if a reference is null or not. this must never be ignored. it just takes one java method that attempts to access a value in, as an example, an arraylist whose reference is null to bring down a program.
to see the problem, let's look at this method:
public arraylist findall() throws sqlexception { arraylist rows = null; string selectquery = "select id, commonname, latin, ph, kh, temp, fishsize, speciesorigin, tanksize, stocking, diet from fish"; try (connection connection = drivermanager.getconnection(url, user, password); preparedstatement pstatement = connection .preparestatement(selectquery); resultset resultset = pstatement.executequery()) { if (resultset.next()) { // only create the arraylist if there is something to put in it rows = new arraylist<>(); do { fishdata fishdata = new fishdata(); fishdata.setcommonname(resultset.getstring("commonname")); fishdata.setdiet(resultset.getstring("diet")); fishdata.setkh(resultset.getstring("kh")); fishdata.setlatin(resultset.getstring("latin")); fishdata.setph(resultset.getstring("ph")); fishdata.setfishsize(resultset.getstring("fishsize")); fishdata.setspeciesorigin(resultset.getstring("speciesorigin")); fishdata.setstocking(resultset.getstring("stocking")); fishdata.settanksize(resultset.getstring("tanksize")); fishdata.settemp(resultset.getstring("temp")); fishdata.setid(resultset.getlong("id")); rows.add(fishdata); } while (resultset.next()); } } return rows; }
the way in which this method is coded, the arraylist is only created if there were any records returned from the database query otherwise a null is returned. here is a method that converts the arraylist of records into a string by calling upon findall() :
public string retrievefish() { stringbuilder sb = new stringbuilder(); fishdao fishdao = new fishdaoimpl(); arraylist data; try { data = fishdao.findall(); // must check for null if (data != null) { data.stream().foreach((fd) -> { sb.append(fd.tostring()).append("\n"); }); } } catch (sqlexception e) { log.error("error retrieving records: ", e.getcause()); } return sb.tostring(); }
there is nothing wrong with this code. what can go wrong is the programmer, especially a student programmer. the error is forgetting the if (data != null). here is a classic student error:
try { // oops, forgot to check for null data = fishdao.findall(); data.stream().foreach((fd) -> { sb.append(fd.tostring()).append("\n"); }); } catch (sqlexception e) { log.error("error retrieving records: ", e.getcause()); }
if only there was some way to make a programmer aware of the possibility of a
null
reference? there is and it appeared in java 8. it is the
optional
type. its primary purpose is to eliminate returning
null
from methods. by changing the return type to
optional
we can change the
findall()
method’s first and last lines:
public optional> findall() throws sqlexception { . . . // the original code does not change . . . return optional.ofnullable(rows); }
if the reference being returned is placed in an optional.ofnullable() then it may or may not be null. the caller of this method must deal with the possibility of a null .
here is how it is dealt with:
public optional retrievefish() { stringbuilder sb = new stringbuilder(); fishdao fishdao = new fishdaoimpl(); //arraylist data; try { // ifpresent is required so a check for null can never be forgotten fishdao.findall().ifpresent(data -> data.stream().foreach((fd) -> { sb.append(fd.tostring()).append("\n"); }) ); } catch (sqlexception e) { log.error("error retrieving records: ", e.getcause()); } return optional.of(sb.tostring()); }
notice that to access the arraylist in the optional the method ifpresent() is used. if this is true then the lambda is invoked to copy the arraylist into the stringbuilder object.
another feature of optional is in play in this method. the return type is optional<string> and the last statement reads return optional.of(sb.tostring()) . the of() member method of optional can only accept a non-null value so if the stringbuilder object is somehow null there will be an exception.
the next time you are writing a method that can return a null reference please don’t. return an optional instead.
Opinions expressed by DZone contributors are their own.
Trending
-
RBAC With API Gateway and Open Policy Agent (OPA)
-
Mastering Time Series Analysis: Techniques, Models, and Strategies
-
Competing Consumers With Spring Boot and Hazelcast
-
Transactional Outbox Patterns Step by Step With Spring and Kotlin
Comments