Related
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 3 years ago.
Improve this question
Part of the project I'm working on got updated, and at some point somebody started sending empty collections instead of null as arguments to a method.
This led to a single bug first, which then led me to change if (null == myCollection) with if (CollectionUtils.isEmpty(myCollection)), which in the end led to a cascade of several bugs. This way I discovered that a lot of the code treats these collections differently:
when a collection is empty (i.e. the user specifically wanted to have nothing here)
when a collection is null (i.e. the user did not mention anything here)
Hence, my question: is this good or bad design practice?
In his (very good) book Effective Java, Joshua Bloch treats this question for the returned values of methods (not "in general" like your question) :
(About use of null) It is errorprone, because the programmer writing
the client might forget to write the special case code to handle a null
return.
(...)
It is sometimes argued that a null return value is preferable to an
empty array because it avoids the expense of allocating the array.
This argument fails on two counts. First, it is inadvisable to worry
about performance at this level unless profiling has shown that the
method in question is a real contributor to performance problems (Item
55). Second, it is possible to return the same zero-length array from every invocation that returns no items because
zero-length arrays are immutable and immutable objects may be shared
freely (Item 15).
(...)
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. (...)
Personnally I use this reasoning as a rule of thumb with any use of Collections in my code. Of course, there is some case where a distinction between null and empty makes sense but in my experience it's quite rare.
Nevertheless, as stated by BionicCode in the comments section, in the case of a method that returns null instead of empty to specify that something went wrong, you always have the possibility of throwing an exception instead.
I know this question already has an accepted answer. But because of the discussions I had, I decided to write my own to address this problem.
The inventor of NULL himself Mr. Tony Hoare says
I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn’t resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.
First of all it is very bad practice to introduce breaking changes when updating old code that was already released and tested. Refactoring in this situation is always dangerous and should be avoided. I know that it can hurt to release ugly or stupid code, but if this happened, then this is a clear sign of a lack of quality management tools (e.g. code reviews or conventions). But obviously there were no unit tests otherwise the changes would have been reverted immediately by the author of the changes, due to the failing tests. The main problem is that your team has no conventions how to handle NULL as argument or as result. The intention of the author of the update to switch from NULL arguments to empty collections is absolutely right and should be supported, but he shouldn't have done it for working code and he should have discussed with the team, so that the rest of the team can follow in order to make it more effective. Your Team definitely must come together and agree on abandoning NULL as an argument or result value or at least find a standard. Better send NULL to hell. Your only solution is to revert the changes done by the author of the update (I assume you are using version control). Then redo the update, but do it the old fashioned and nasty way using NULL like you were doing it before. Don't use NULL in new code - for a brighter future. Trying to fix the updated version will escalate the situation for sure and therefore will waste time. (I assume that we are talking about a bigger project). Roll back to the previous version if possible.
To make it short if you don't like to continue reading: yes it's very bad practice. You yourself can draw this conclusion from the situation you are in now. You now witness very unstable and unpredictable code. The irrational bugs are the proof that your code has become unpredictable. If you don't have unit tests for at least the business logic then the code is hot iron. The practice that has lead to this code can never be good. NULL has no intuitional meaning to the user of an API, when there is the possibility to get a neutral result or parameter (like this is the case with a collection). An empty collection is neutral. You can expect a collection to be empty or to contain at least one element. There is noting else you can expect from a collection. You want to indicate an error and that an operation couldn't terminate? Then prefer to throw an exception with a good name that communicates the root of the error clearly to the caller.
NULL is a historical relic. Stumbling over a NULL value meant that the programmer wrote sloppy code. He forgot to initialize a pointer by assigning a memory address to it. The compiler must know a memory address as a reference in order to create a valid pointer. If you wanted a pointer but don't waste memory for just declaring the pointer or didn't know the address to this point, NULL was a convention to have the pointer to point to nowhere, which means no memory must be allocated for the pointer's reference (except for the pointer itself). Today in modern OO-Languages with garbage collection and plenty of available memory, NULL has become irrelevant in programming. There are situations where it is used to express e.g. the absence of data like in SQL. But in OO programming you can absolutely avoid it and therefore make your application more robust.
You have the choice to apply the Null-Object Pattern. Also it is best practice to either use default parameters (if your language like C# supports this) or use overloads. E.g. if the method parameter is optional then use an overload (or a default parameter). If the parameter is mandatory but you can't provide the value, then simply don't call the method. If the parameter is a collection, then always use an empty collection whenever you have no values. The author of the method must handle this case as he must handle all possible cases or parameter states. This includes NULL. So it's the duty of the method's author to check for NULL and to decide how to handle it. Here kicks the convention in. If your team agreed on to never use NULL, this annoying and ugly NULL checks are not required anymore. Some frameworks offer a #NotNull attribute. The author can use it to decorate the method parameters to indicate that NULL is not a valid value. The compiler will now do the NULL checks and show an error to the programmer that (mis)uses the method and simply won't compile. Alongside code reviews, this can help to prevent or identify violations and lead to more robust code.
Most libraries provide helper classes e.g. Array.Empty() or Enumerable.Empty() (C#) to create empty collections that provide methods like IsEmpty(). This makes intentions semantically clear and code therefore nice to read. It's worth it to write your own helper if none exist in your standard library.
Try to integrate quality management into your team's routine. Do code reviews to make sure the code to be released is conform to your quality standards (unit tests, no NULL values, always use curly braces for statement bodies, naming, etc...)
I hope you can fix your problem. I know this is a stressful situation to clean up the mess of somebody else. This is why communication in teams is so important.
It depends on your needs. Null is definitele not empty collection. I'd say that it is a bad practice to treat separately empty and not empty collection.
Null howver indicates a kind of lack of data. I'd say that if such situation is legal and you are using java 8 or higher you should probably use Optional. In this case Optional.empty() means that there is no collection while Optional.of(collection) means that collection is here even if it itself is empty.
It is recommended to use like this in case of collection.
if(myCollection !=null && !myCollection.isEmpty()) {
//Process the logic
}
However as part of design, Joshua Bloch recommends to use empty collection in Effective Java.
To quote his statement,
there is no reason ever to return null from an array-valued method
instead of returning a zero-length array.
You can find the link for effective java.
https://www.amazon.com/dp/0321356683
well, by accessing a null value, you can get a NullPointerException directly, and most times (from my experience) it is bad practice to make a difference between a null value and empty collection in deeper hierarchy of the logic. it should just be empty instead of null.
Let’s put some downvote bait here, shall we? As I understand it, you have got a method like
public void foo(Collection myCollection) {
if (CollectionUtils.isEmpty(myCollection)) {
// ...
}
// ...
}
I also understand that this method is called from many places so it would most practical if you don’t need to change all the calls. And I understand that there is a semantic difference between passing null and passing an empty collection to it. An empty collection means that we know for a fact that there are no elements. Null means that it is not specified whether there are any (and I am assuming that your method is able to do useful work in this case too).
The nice design would have two methods:
/** #param myCollection a possibly empty collection; not null */
public void foo(Collection myCollection);
/** Call this method if you don’t want to specify elements */
public void foo();
However, considering your existing code base, you don’t want to introduce the non-null requirement mentioned all of a sudden and break code that has been working until now. One way forward would be to introduce a comment on the 1-arg method effectively saying
Passing null to this method is deprecated. It works but may be
prohibited in a future version.
This will buy you time to change the code base over the coming months or even years and still allow you to arrive at the better design at some point.
At the same time you may change your 1-arg method to just delegating to the no-arg method if it receives a null.
Caveat: You need to be very clear in your documentation (Javadoc) about the semantics of not specifying elements (ideally calling the no-arg method) and the semantic difference from passing an empty collection.
I've read on many Web sites Optional should be used as a return type only, and not used in method arguments. I'm struggling to find a logical reason why. For example I have a piece of logic which has 2 optional parameters. Therefore I think it would make sense to write my method signature like this (solution 1):
public int calculateSomething(Optional<String> p1, Optional<BigDecimal> p2) {
// my logic
}
Many web pages specify Optional should not be used as method arguments. With this in mind, I could use the following method signature and add a clear Javadoc comment to specify that the arguments may be null, hoping future maintainers will read the Javadoc and therefore always carry out null checks prior to using the arguments (solution 2):
public int calculateSomething(String p1, BigDecimal p2) {
// my logic
}
Alternatively I could replace my method with four public methods to provide a nicer interface and make it more obvious p1 and p2 are optional (solution 3):
public int calculateSomething() {
calculateSomething(null, null);
}
public int calculateSomething(String p1) {
calculateSomething(p1, null);
}
public int calculateSomething(BigDecimal p2) {
calculateSomething(null, p2);
}
public int calculateSomething(String p1, BigDecimal p2) {
// my logic
}
Now I try writing the code of the class which invokes this piece of logic for each approach. I first retrieve the two input parameters from another object which returns Optionals and then, I invoke calculateSomething. Therefore, if solution 1 is used the calling code would look like this:
Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();
int result = myObject.calculateSomething(p1, p2);
if solution 2 is used, the calling code would look like this:
Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();
int result = myObject.calculateSomething(p1.orElse(null), p2.orElse(null));
if solution 3 is applied, I could use the code above or I could use the following (but it's significantly more code):
Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();
int result;
if (p1.isPresent()) {
if (p2.isPresent()) {
result = myObject.calculateSomething(p1, p2);
} else {
result = myObject.calculateSomething(p1);
}
} else {
if (p2.isPresent()) {
result = myObject.calculateSomething(p2);
} else {
result = myObject.calculateSomething();
}
}
So my question is: Why is it considered bad practice to use Optionals as method arguments (see solution 1)? It looks like the most readable solution to me and makes it most obvious that the parameters could be empty/null to future maintainers. (I'm aware the designers of Optional intended it to only be used as a return type, but I can't find any logical reasons not to use it in this scenario).
Oh, those coding styles are to be taken with a bit of salt.
(+) Passing an Optional result to another method, without any semantic analysis; leaving that to the method, is quite alright.
(-) Using Optional parameters causing conditional logic inside the methods is literally contra-productive.
(-) Needing to pack an argument in an Optional, is suboptimal for the compiler, and does an unnecessary wrapping.
(-) In comparison to nullable parameters Optional is more costly.
(-) The risk of someone passing the Optional as null in actual parameters.
In general: Optional unifies two states, which have to be unraveled. Hence better suited for result than input, for the complexity of the data flow.
The best post I've seen on the topic was written by Daniel Olszewski:
Although it might be tempting to consider Optional for not mandatory method parameters, such a solution pale in comparison with other possible alternatives. To illustrate the problem, examine the following constructor declaration:
public SystemMessage(String title, String content, Optional<Attachment> attachment) {
// assigning field values
}
At first glance it may look as a right design decision. After all, we
explicitly marked the attachment parameter as optional. However, as
for calling the constructor, client code can become a little bit
clumsy.
SystemMessage withoutAttachment = new SystemMessage("title", "content", Optional.empty());
Attachment attachment = new Attachment();
SystemMessage withAttachment = new SystemMessage("title", "content", Optional.ofNullable(attachment));
Instead of providing clarity, the factory methods of the Optional
class only distract the reader. Note there’s only one optional
parameter, but imagine having two or three. Uncle Bob definitely
wouldn’t be proud of such code 😉
When a method can accept optional parameters, it’s preferable to adopt the well-proven approach and design such case using method
overloading. In the example of the SystemMessage class, declaring
two separate constructors are superior to using Optional.
public SystemMessage(String title, String content) {
this(title, content, null);
}
public SystemMessage(String title, String content, Attachment attachment) {
// assigning field values
}
That change makes client code much simpler and easier to read.
SystemMessage withoutAttachment = new SystemMessage("title", "content");
Attachment attachment = new Attachment();
SystemMessage withAttachment = new SystemMessage("title", "content", attachment);
There are almost no good reasons for not using Optional as parameters. The arguments against this rely on arguments from authority (see Brian Goetz - his argument is we can't enforce non null optionals) or that the Optional arguments may be null (essentially the same argument). Of course, any reference in Java can be null, we need to encourage rules being enforced by the compiler, not programmers memory (which is problematic and does not scale).
Functional programming languages encourage Optional parameters. One of the best ways of using this is to have multiple optional parameters and using liftM2 to use a function assuming the parameters are not empty and returning an optional (see http://www.functionaljava.org/javadoc/4.4/functionaljava/fj/data/Option.html#liftM2-fj.F-). Java 8 has unfortunately implemented a very limited library supporting optional.
As Java programmers we should only be using null to interact with legacy libraries.
Let's make something perfectly clear: in other languages, there is no general recommendation against the use of a Maybe type as a field type, a constructor parameter type, a method parameter type, or a function parameter type.
So if you "shouldn't" use Optional as a parameter type in Java, the reason is specific to Optional, to Java, or to both.
Reasoning that might apply to other Maybe types, or other languages, is probably not valid here.
Per Brian Goetz,
[W]e did have a clear
intention when adding [Optional], and it was not to be a general
purpose Maybe type, as much as many people would have liked us to do
so. Our intention was to provide a limited mechanism for library
method return types where there needed to be a clear way to represent
"no result", and using null for such was overwhelmingly likely to
cause errors.
For example, you probably should never use it for something that
returns an array of results, or a list of results; instead return an
empty array or list. You should almost never use it as a field of
something or a method parameter.
So the answer is specific to Optional: it isn't "a general purpose Maybe type"; as such, it is limited, and it may be limited in ways that limit its usefulness as a field type or a parameter type.
That said, in practice, I've rarely found using Optional as a field type or a parameter type to be an issue. If Optional, despite its limitations, works as a parameter type or a field type for your use case, use it.
The pattern with Optional is for one to avoid returning null. It's still perfectly possible to pass in null to a method.
While these aren't really official yet, you can use JSR-308 style annotations to indicate whether or not you accept null values into the function. Note that you'd have to have the right tooling to actually identify it, and it'd provide more of a static check than an enforceable runtime policy, but it would help.
public int calculateSomething(#NotNull final String p1, #NotNull final String p2) {}
This advice is a variant of the "be as unspecific as possible regarding inputs and as specific as possible regarding outputs" rule of thumb.
Usually if you have a method that takes a plain non-null value, you can map it over the Optional, so the plain version is strictly more unspecific regarding inputs. However there are a bunch of possible reasons why you would want to require an Optional argument nonetheless:
you want your function to be used in conjunction with another API that returns an Optional
Your function should return something other than an empty Optional if the given value is empty
You think Optional is so awesome that whoever uses your API should be required to learn about it ;-)
Check out the JavaDoc in JDK10, https://docs.oracle.com/javase/10/docs/api/java/util/Optional.html, an API note is added:
API Note:
Optional is primarily intended for use as a method return type where there is a clear need to represent "no result," and where using null is likely to cause errors.
Maybe I will provoke a bunch of down-votes and negative comments, but... I cannot stand.
Disclaimer: what I write below is not really an answer to the original question, but rather my thoughts on the topic. And the only source for it is my thoughts and my experience (with Java and other languages).
First let's check, why would anyone like to use Optional at all?
For me the reason is simple: unlike other languages java does not have built-in capability to define variable (or type) as nullable or not. All "object"-variables are nullable and all primitive-types are not. For the sake of simplicity let't not consider primitive types in further discussion, so I will claim simply that all variables are nullable.
Why would one need to declare variables as nullable/non-nullable? Well, the reason for me is: explicit is always better, than implicit. Besides having explicit decoration (e.g. annotation or type) could help static analyzer (or compiler) to catch some null-pointer related issues.
Many people argue in the comments above, that functions do not need to have nullable arguments. Instead overloads should be used. But such statement is only good in a school-book. In real life there are different situations. Consider class, which represents settings of some system, or personal data of some user, or in fact any composite data-structure, which contains lots of fields - many of those with repeated types, and some of the fields are mandatory while others are optional. In such cases inheritance/constructor overloads do not really help.
Random example: Let's say, we need to collect data about people. But some people don't want to provide all the data. And of course this is POD, so basically type with value-semantics, so I want it to be more or less immutable (no setters).
class PersonalData {
private final String name; // mandatory
private final int age; // mandatory
private final Address homeAddress; // optional
private final PhoneNumber phoneNumber; // optional. Dedicated class to handle constraints
private final BigDecimal income; // optional.
// ... further fields
// How many constructor- (or factory-) overloads do we need to handle all cases
// without nullable arguments? If I am not mistaken, 8. And what if we have more optional
// fields?
// ...
}
So, IMO discussion above shows, that even though mostly we can survive without nullable arguments, but sometimes it is not really feasible.
Now we come to the problem: if some of the arguments are nullable and others are not, how do we know, which one?
Approach 1: All arguments are nullable (according to java standrd, except primitive types). So we check all of them.
Result: code explodes with checks, which are mostly unneeded, because as we discussed above almost all of the time we can go ahead with nullable variables, and only in some rare cases "nullables" are needed.
Approach 2: Use documentation and/or comments to describe, which arguments/fields are nullable and which not.
Result: It does not really work. People are lazy to write and read the docs. Besides lately the trend is, that we should avoid writing documentation in favor of making the code itself self-describing. Besides all the reasoning about modifying the code and forgeting to modify the documentation is still valid.
Approach 3: #Nullable #NonNull etc... I personally find them to be nice. But there are certain disadvantages : (e.g. they are only respected by external tools, not the compiler), the worst of which is that they are not standard, which means, that 1. I would need to add external dependency to my project to benefit from them, and 2. The way they are treated by different systems are not uniform. As far as I know, they were voted out of official Java standard (and I don't know if there are any plans to try again).
Approach 4: Optional<>. The disadvantages are already mentioned in other comments, the worst of which is (IMO) performance penalty. Also it adds a bit of boilerplate, even thoough I personally find, use of Optional.empty() and Optional.of() to be not so bad. The advantages are obvious:
It is part of the Java standard.
It makes obvious to the reader of the code (or to the user of API), that these arguments may be null. Moreover, it forces both: user of the API and developer of the method to aknolage this fact by explicitly wrapping/unwrapping the values (which is not the case, when annotations like #Nullable etc. are used).
So in my point, there is no black-and-white in regard of any methodology including this one. I personally ended up with the following guidelines and conventions (which are still not strict rules):
Inside my own code all the variables must be not-null (but probably Optional<>).
If I have a method with one or two optional arguments I try to redesign it using overloads, inheritance etc.
If I cannot find the solution in reasonable time, I start thinking, if the performance is critical (i.e. if there are millions of the objects to be processed). Usually it is not the case.
If not, I use Optional as argument types and/or field types.
There are still grey areas, where these conventions do not work:
We need high performance (e.g. processing of huge amounts of data, so that total execution time is very large, or situations when throughput is critical). In this cases performance penalty introduced by Optional may be really unwanted.
We are on the boundary of the code, which we write ourselves, e.g.: we read from the DB, Rest Endpoint, parse file etc.
Or we just use some external libraries, which do not follow our conventions, so again, we should be careful...
By the way, the last two cases can also be the source of need in the optional fields/arguments. I.e. when the structure of the data is not developed by ourselves, but is imposed by some external interfaces, db-schemas etc...
At the end, I think, that one should think about the problem, which is being solved, and try to find the appropriate tools. If Optional<> is appropriate, then I see no reason not to use it.
Edit: Approach 5: I used this one recently, when I could not use Optional. The idea is simply to use naming convention for method arguments and class variables. I used "maybe"-prefix, so that if e.g. "url" argument is nullable, then it becomes maybeUrl. The advantage is that it slightly improves understandability of the intent (and does not have disadvantages of other approaches, like external dependencies or performance penalty). But there are also drawbacks, like: there is no tooling to support this convention (your IDE will not show you any warning, if you access "maybe"-variable without first checking it). Another problem is that it only helps, when applied consistently by all people working on the project.
This seems a bit silly to me, but the only reason I can think of is that object arguments in method parameters already are optional in a way - they can be null. Therefore forcing someone to take an existing object and wrap it in an optional is sort of pointless.
That being said, chaining methods together that take/return optionals is a reasonable thing to do, e.g. Maybe monad.
Accepting Optional as parameters causes unnecessary wrapping at caller level.
For example in the case of:
public int calculateSomething(Optional<String> p1, Optional<BigDecimal> p2 {}
Suppose you have two not-null strings (ie. returned from some other method):
String p1 = "p1";
String p2 = "p2";
You're forced to wrap them in Optional even if you know they are not Empty.
This get even worse when you have to compose with other "mappable" structures, ie. Eithers:
Either<Error, String> value = compute().right().map((s) -> calculateSomething(
< here you have to wrap the parameter in a Optional even if you know it's a
string >));
ref:
methods shouldn't expect Option as parameters, this is almost always a
code smell that indicated a leakage of control flow from the caller to
the callee, it should be responsibility of the caller to check the
content of an Option
ref. https://github.com/teamdigitale/digital-citizenship-functions/pull/148#discussion_r170862749
My take is that Optional should be a Monad and these are not conceivable in Java.
In functional programming you deal with pure and higher order functions that take and compose their arguments only based on their "business domain type". Composing functions that feed on, or whose computation should be reported to, the real-world (so called side effects) requires the application of functions that take care of automatically unpacking the values out of the monads representing the outside world (State, Configuration, Futures, Maybe, Either, Writer, etc...); this is called lifting. You can think of it as a kind of separation of concerns.
Mixing these two levels of abstraction doesn't facilitate legibility so you're better off just avoiding it.
Another reason to be carefully when pass an Optional as parameter is that a method should do one thing... If you pass an Optional param you could favor do more than one thing, it could be similar to pass a boolean param.
public void method(Optional<MyClass> param) {
if(param.isPresent()) {
//do something
} else {
//do some other
}
}
So, if you would permit the pun, Oracle issued an oracle:
Thou shalt not use Optional but for function return values.
I love it how most of the answers so far are going along with the narrative of Oracle's oracle, which is re-iterated unquestioned all over the interwebz, in the "many Web sites" mentioned in the question. This is very typical of stack overflow: if something is allegedly supposed to be a certain way, and you ask why it is supposed to be that way, almost everyone will offer reasons why; almost nobody will question whether it should in fact be that way.
So, here is a dissenting opinion:
You can use Optional to completely eliminate null from your code base.
I have done it in a 100k-lines-of-code project. It worked.
If you decide to go along this path, then you will need to be thorough, so you will have a lot of work to do. The example mentioned in the accepted answer with Optional.ofNulable() should never occur, because if you are thorough, then you should never have anything returning null, and therefore no need for Optional.ofNullable(). In that 100k-lines-of-code project that I mentioned above, I have only used Optional.ofNullable() a couple of times when receiving results from external methods that I have no control over.
Also, if you decide to go along this path, your solution will not be the most performant solution possible, because you will be allocating lots of optionals. However:
That's nothing but a runtime performance overhead disadvantage.
That's not a severe disadvantage.
That's Java's problem, not your problem.
Let me explain that last part.
Java does not offer explicit nullability of reference types as C# does (since version 8.0) so it is inferior in this regard. (I said "in this regard"; in other regards, Java is better; but that's off-topic right now.)
The only proper alternative to explicit nullability of reference types is the Optional type.
(And it is arguably even slightly better, because with Optional you can indicate optional-of-optional, if you must, whereas with explicit nullability you cannot have ReferenceType??, or at least you cannot in C# as it is currently implemented.)
Optional does not have to add overhead, it only does so in Java. That's because Java also does not support true value types, as C# and Scala do. In this regard, Java is severely inferior to those languages. (Again, I said "in this regard"; in other regards, Java is better; but that's off-topic right now.) If Java did support true value types, then Optional would have been implemented as a single machine word, which would mean that the runtime overhead of using it would be zero.
So, the question that it boils down to is: do you want perfect clarity and type safety in your code, or do you prefer maximum performance? I believe that for high-level languages, (of which Java certainly aims to be one,) this question was settled a long time ago.
I think that is because you usually write your functions to manipulate data, and then lift it to Optional using map and similar functions. This adds the default Optional behavior to it.
Of course, there might be cases, when it is necessary to write your own auxilary function that works on Optional.
I believe the reson of being is you have to first check whether or not Optional is null itself and then try to evaluate value it wraps. Too many unnecessary validations.
I know that this question is more about opinion rather than hard facts. But I recently moved from being a .net developer to a java one, so I have only recently joined the Optional party. Also, I'd prefer to state this as a comment, but since my point level does not allow me to comment, I am forced to put this as an answer instead.
What I have been doing, which has served me well as a rule of thumb. Is to use Optionals for return types, and only use Optionals as parameters, if I require both the value of the Optional, and weather or not the Optional had a value within the method.
If I only care about the value, I check isPresent before calling the method, if I have some kind of logging or different logic within the method that depends on if the value exists, then I will happily pass in the Optional.
Using Optional as parameters might be useful in some use cases which involves protobufs or setting fields in a configuration object.
public void setParameters(Optional<A> op1, Optional<B> op2) {
ProtoRequest.Builder builder = ProtoRequest.newBuilder();
op1.ifPresent(builder::setOp1);
op2.ifPresent(builder::setOp2);
...
}
I think in such cases it might be useful to have optional as parameters. API receiving the proto request would handle the different fields.
If a function is not doing additional computations on these parameters then using Optional might be simpler.
public void setParameters(A op1, B op2) {
ProtoRequest.Builder builder = ProtoRequest.newBuilder();
if (op1 != null) {
builder.setOp1(op1);
}
if (op2 != null) {
builder.setOp2(op2);
}
...
}
Optionals aren't designed for this purpose, as explained nicely by Brian Goetz.
You can always use #Nullable to denote that a method argument can be null. Using an optional does not really enable you to write your method logic more neatly.
One more approach, what you can do is
// get your optionals first
Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();
// bind values to a function
Supplier<Integer> calculatedValueSupplier = () -> { // your logic here using both optional as state}
Once you have built a function(supplier in this case) you will be able to pass this around as any other variable and would be able to call it using
calculatedValueSupplier.apply();
The idea here being whether you have got optional value or not will be internal detail of your function and will not be in parameter. Thinking functions when thinking about optional as parameter is actually very useful technique that I have found.
As to your question whether you should actually do it or not is based on your preference, but as others said it makes your API ugly to say the least.
At first, I also preferred to pass Optionals as parameter, but if you switch from an API-Designer perspective to a API-User perspective, you see the disadvantages.
For your example, where each parameter is optional, I would suggest to change the calculation method into an own class like follows:
Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();
MyCalculator mc = new MyCalculator();
p1.map(mc::setP1);
p2.map(mc::setP2);
int result = mc.calculate();
This is because we have different requirements to an API user and an API developer.
A developer is responsible for providing a precise specification and a correct implementation. Therefore if the developer is already aware that an argument is optional the implementation must deal with it correctly, whether it being a null or an Optional. The API should be as simple as possible to the user, and null is the simplest.
On the other hand, the result is passed from the API developer to the user. However the specification is complete and verbose, there is still a chance that the user is either unaware of it or just lazy to deal with it. In this case, the Optional result forces the user to write some extra code to deal with a possible empty result.
First of all, if you're using method 3, you can replace those last 14 lines of code with this:
int result = myObject.calculateSomething(p1.orElse(null), p2.orElse(null));
The four variations you wrote are convenience methods. You should only use them when they're more convenient. That's also the best approach. That way, the API is very clear which members are necessary and which aren't. If you don't want to write four methods, you can clarify things by how you name your parameters:
public int calculateSomething(String p1OrNull, BigDecimal p2OrNull)
This way, it's clear that null values are allowed.
Your use of p1.orElse(null) illustrates how verbose our code gets when using Optional, which is part of why I avoid it. Optional was written for functional programming. Streams need it. Your methods should probably never return Optional unless it's necessary to use them in functional programming. There are methods, like Optional.flatMap() method, that requires a reference to a function that returns Optional. Here's its signature:
public <U> Optional<U> flatMap(Function<? super T, ? extends Optional<? extends U>> mapper)
So that's usually the only good reason for writing a method that returns Optional. But even there, it can be avoided. You can pass a getter that doesn't return Optional to a method like flatMap(), by wrapping it in a another method that converts the function to the right type. The wrapper method looks like this:
public static <T, U> Function<? super T, Optional<U>> optFun(Function<T, U> function) {
return t -> Optional.ofNullable(function.apply(t));
}
So suppose you have a getter like this: String getName()
You can't pass it to flatMap like this:
opt.flatMap(Widget::getName) // Won't work!
But you can pass it like this:
opt.flatMap(optFun(Widget::getName)) // Works great!
Outside of functional programming, Optionals should be avoided.
Brian Goetz said it best when he said this:
The reason Optional was added to Java is because this:
return Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods())
.stream()
.filter(m -> Objects.equals(m.getName(), enclosingInfo.getName())
.filter(m -> Arrays.equals(m.getParameterTypes(), parameterClasses))
.filter(m -> Objects.equals(m.getReturnType(), returnType))
.findFirst()
.getOrThrow(() -> new InternalError(...));
is cleaner than this:
Method matching =
Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods())
.stream()
.filter(m -> Objects.equals(m.getName(), enclosingInfo.getName())
.filter(m -> Arrays.equals(m.getParameterTypes(), parameterClasses))
.filter(m -> Objects.equals(m.getReturnType(), returnType))
.getFirst();
if (matching == null)
throw new InternalError("Enclosing method not found");
return matching;
Irrespective of Java 8, Use old school method overloading technique to bring clarity and flexibility, suppose you have following method with two args
public void doSomething(arg1,arg2);
in case you want to add additional optional parameter then overload the method
public void doSomething(arg1,arg2,arg3) {
Result result = doSomething(arg1,arg2);
// do additional working
}
A good example were Optional as arguments would be nice is JPA Repositories. Id love to do something like findByNameAndSurname(Optional,Optional). That way, if the Optional is empty, no WHERE param=y is performed
I've read on many Web sites Optional should be used as a return type only, and not used in method arguments. I'm struggling to find a logical reason why. For example I have a piece of logic which has 2 optional parameters. Therefore I think it would make sense to write my method signature like this (solution 1):
public int calculateSomething(Optional<String> p1, Optional<BigDecimal> p2) {
// my logic
}
Many web pages specify Optional should not be used as method arguments. With this in mind, I could use the following method signature and add a clear Javadoc comment to specify that the arguments may be null, hoping future maintainers will read the Javadoc and therefore always carry out null checks prior to using the arguments (solution 2):
public int calculateSomething(String p1, BigDecimal p2) {
// my logic
}
Alternatively I could replace my method with four public methods to provide a nicer interface and make it more obvious p1 and p2 are optional (solution 3):
public int calculateSomething() {
calculateSomething(null, null);
}
public int calculateSomething(String p1) {
calculateSomething(p1, null);
}
public int calculateSomething(BigDecimal p2) {
calculateSomething(null, p2);
}
public int calculateSomething(String p1, BigDecimal p2) {
// my logic
}
Now I try writing the code of the class which invokes this piece of logic for each approach. I first retrieve the two input parameters from another object which returns Optionals and then, I invoke calculateSomething. Therefore, if solution 1 is used the calling code would look like this:
Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();
int result = myObject.calculateSomething(p1, p2);
if solution 2 is used, the calling code would look like this:
Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();
int result = myObject.calculateSomething(p1.orElse(null), p2.orElse(null));
if solution 3 is applied, I could use the code above or I could use the following (but it's significantly more code):
Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();
int result;
if (p1.isPresent()) {
if (p2.isPresent()) {
result = myObject.calculateSomething(p1, p2);
} else {
result = myObject.calculateSomething(p1);
}
} else {
if (p2.isPresent()) {
result = myObject.calculateSomething(p2);
} else {
result = myObject.calculateSomething();
}
}
So my question is: Why is it considered bad practice to use Optionals as method arguments (see solution 1)? It looks like the most readable solution to me and makes it most obvious that the parameters could be empty/null to future maintainers. (I'm aware the designers of Optional intended it to only be used as a return type, but I can't find any logical reasons not to use it in this scenario).
Oh, those coding styles are to be taken with a bit of salt.
(+) Passing an Optional result to another method, without any semantic analysis; leaving that to the method, is quite alright.
(-) Using Optional parameters causing conditional logic inside the methods is literally contra-productive.
(-) Needing to pack an argument in an Optional, is suboptimal for the compiler, and does an unnecessary wrapping.
(-) In comparison to nullable parameters Optional is more costly.
(-) The risk of someone passing the Optional as null in actual parameters.
In general: Optional unifies two states, which have to be unraveled. Hence better suited for result than input, for the complexity of the data flow.
The best post I've seen on the topic was written by Daniel Olszewski:
Although it might be tempting to consider Optional for not mandatory method parameters, such a solution pale in comparison with other possible alternatives. To illustrate the problem, examine the following constructor declaration:
public SystemMessage(String title, String content, Optional<Attachment> attachment) {
// assigning field values
}
At first glance it may look as a right design decision. After all, we
explicitly marked the attachment parameter as optional. However, as
for calling the constructor, client code can become a little bit
clumsy.
SystemMessage withoutAttachment = new SystemMessage("title", "content", Optional.empty());
Attachment attachment = new Attachment();
SystemMessage withAttachment = new SystemMessage("title", "content", Optional.ofNullable(attachment));
Instead of providing clarity, the factory methods of the Optional
class only distract the reader. Note there’s only one optional
parameter, but imagine having two or three. Uncle Bob definitely
wouldn’t be proud of such code 😉
When a method can accept optional parameters, it’s preferable to adopt the well-proven approach and design such case using method
overloading. In the example of the SystemMessage class, declaring
two separate constructors are superior to using Optional.
public SystemMessage(String title, String content) {
this(title, content, null);
}
public SystemMessage(String title, String content, Attachment attachment) {
// assigning field values
}
That change makes client code much simpler and easier to read.
SystemMessage withoutAttachment = new SystemMessage("title", "content");
Attachment attachment = new Attachment();
SystemMessage withAttachment = new SystemMessage("title", "content", attachment);
There are almost no good reasons for not using Optional as parameters. The arguments against this rely on arguments from authority (see Brian Goetz - his argument is we can't enforce non null optionals) or that the Optional arguments may be null (essentially the same argument). Of course, any reference in Java can be null, we need to encourage rules being enforced by the compiler, not programmers memory (which is problematic and does not scale).
Functional programming languages encourage Optional parameters. One of the best ways of using this is to have multiple optional parameters and using liftM2 to use a function assuming the parameters are not empty and returning an optional (see http://www.functionaljava.org/javadoc/4.4/functionaljava/fj/data/Option.html#liftM2-fj.F-). Java 8 has unfortunately implemented a very limited library supporting optional.
As Java programmers we should only be using null to interact with legacy libraries.
Let's make something perfectly clear: in other languages, there is no general recommendation against the use of a Maybe type as a field type, a constructor parameter type, a method parameter type, or a function parameter type.
So if you "shouldn't" use Optional as a parameter type in Java, the reason is specific to Optional, to Java, or to both.
Reasoning that might apply to other Maybe types, or other languages, is probably not valid here.
Per Brian Goetz,
[W]e did have a clear
intention when adding [Optional], and it was not to be a general
purpose Maybe type, as much as many people would have liked us to do
so. Our intention was to provide a limited mechanism for library
method return types where there needed to be a clear way to represent
"no result", and using null for such was overwhelmingly likely to
cause errors.
For example, you probably should never use it for something that
returns an array of results, or a list of results; instead return an
empty array or list. You should almost never use it as a field of
something or a method parameter.
So the answer is specific to Optional: it isn't "a general purpose Maybe type"; as such, it is limited, and it may be limited in ways that limit its usefulness as a field type or a parameter type.
That said, in practice, I've rarely found using Optional as a field type or a parameter type to be an issue. If Optional, despite its limitations, works as a parameter type or a field type for your use case, use it.
The pattern with Optional is for one to avoid returning null. It's still perfectly possible to pass in null to a method.
While these aren't really official yet, you can use JSR-308 style annotations to indicate whether or not you accept null values into the function. Note that you'd have to have the right tooling to actually identify it, and it'd provide more of a static check than an enforceable runtime policy, but it would help.
public int calculateSomething(#NotNull final String p1, #NotNull final String p2) {}
This advice is a variant of the "be as unspecific as possible regarding inputs and as specific as possible regarding outputs" rule of thumb.
Usually if you have a method that takes a plain non-null value, you can map it over the Optional, so the plain version is strictly more unspecific regarding inputs. However there are a bunch of possible reasons why you would want to require an Optional argument nonetheless:
you want your function to be used in conjunction with another API that returns an Optional
Your function should return something other than an empty Optional if the given value is empty
You think Optional is so awesome that whoever uses your API should be required to learn about it ;-)
Check out the JavaDoc in JDK10, https://docs.oracle.com/javase/10/docs/api/java/util/Optional.html, an API note is added:
API Note:
Optional is primarily intended for use as a method return type where there is a clear need to represent "no result," and where using null is likely to cause errors.
Maybe I will provoke a bunch of down-votes and negative comments, but... I cannot stand.
Disclaimer: what I write below is not really an answer to the original question, but rather my thoughts on the topic. And the only source for it is my thoughts and my experience (with Java and other languages).
First let's check, why would anyone like to use Optional at all?
For me the reason is simple: unlike other languages java does not have built-in capability to define variable (or type) as nullable or not. All "object"-variables are nullable and all primitive-types are not. For the sake of simplicity let't not consider primitive types in further discussion, so I will claim simply that all variables are nullable.
Why would one need to declare variables as nullable/non-nullable? Well, the reason for me is: explicit is always better, than implicit. Besides having explicit decoration (e.g. annotation or type) could help static analyzer (or compiler) to catch some null-pointer related issues.
Many people argue in the comments above, that functions do not need to have nullable arguments. Instead overloads should be used. But such statement is only good in a school-book. In real life there are different situations. Consider class, which represents settings of some system, or personal data of some user, or in fact any composite data-structure, which contains lots of fields - many of those with repeated types, and some of the fields are mandatory while others are optional. In such cases inheritance/constructor overloads do not really help.
Random example: Let's say, we need to collect data about people. But some people don't want to provide all the data. And of course this is POD, so basically type with value-semantics, so I want it to be more or less immutable (no setters).
class PersonalData {
private final String name; // mandatory
private final int age; // mandatory
private final Address homeAddress; // optional
private final PhoneNumber phoneNumber; // optional. Dedicated class to handle constraints
private final BigDecimal income; // optional.
// ... further fields
// How many constructor- (or factory-) overloads do we need to handle all cases
// without nullable arguments? If I am not mistaken, 8. And what if we have more optional
// fields?
// ...
}
So, IMO discussion above shows, that even though mostly we can survive without nullable arguments, but sometimes it is not really feasible.
Now we come to the problem: if some of the arguments are nullable and others are not, how do we know, which one?
Approach 1: All arguments are nullable (according to java standrd, except primitive types). So we check all of them.
Result: code explodes with checks, which are mostly unneeded, because as we discussed above almost all of the time we can go ahead with nullable variables, and only in some rare cases "nullables" are needed.
Approach 2: Use documentation and/or comments to describe, which arguments/fields are nullable and which not.
Result: It does not really work. People are lazy to write and read the docs. Besides lately the trend is, that we should avoid writing documentation in favor of making the code itself self-describing. Besides all the reasoning about modifying the code and forgeting to modify the documentation is still valid.
Approach 3: #Nullable #NonNull etc... I personally find them to be nice. But there are certain disadvantages : (e.g. they are only respected by external tools, not the compiler), the worst of which is that they are not standard, which means, that 1. I would need to add external dependency to my project to benefit from them, and 2. The way they are treated by different systems are not uniform. As far as I know, they were voted out of official Java standard (and I don't know if there are any plans to try again).
Approach 4: Optional<>. The disadvantages are already mentioned in other comments, the worst of which is (IMO) performance penalty. Also it adds a bit of boilerplate, even thoough I personally find, use of Optional.empty() and Optional.of() to be not so bad. The advantages are obvious:
It is part of the Java standard.
It makes obvious to the reader of the code (or to the user of API), that these arguments may be null. Moreover, it forces both: user of the API and developer of the method to aknolage this fact by explicitly wrapping/unwrapping the values (which is not the case, when annotations like #Nullable etc. are used).
So in my point, there is no black-and-white in regard of any methodology including this one. I personally ended up with the following guidelines and conventions (which are still not strict rules):
Inside my own code all the variables must be not-null (but probably Optional<>).
If I have a method with one or two optional arguments I try to redesign it using overloads, inheritance etc.
If I cannot find the solution in reasonable time, I start thinking, if the performance is critical (i.e. if there are millions of the objects to be processed). Usually it is not the case.
If not, I use Optional as argument types and/or field types.
There are still grey areas, where these conventions do not work:
We need high performance (e.g. processing of huge amounts of data, so that total execution time is very large, or situations when throughput is critical). In this cases performance penalty introduced by Optional may be really unwanted.
We are on the boundary of the code, which we write ourselves, e.g.: we read from the DB, Rest Endpoint, parse file etc.
Or we just use some external libraries, which do not follow our conventions, so again, we should be careful...
By the way, the last two cases can also be the source of need in the optional fields/arguments. I.e. when the structure of the data is not developed by ourselves, but is imposed by some external interfaces, db-schemas etc...
At the end, I think, that one should think about the problem, which is being solved, and try to find the appropriate tools. If Optional<> is appropriate, then I see no reason not to use it.
Edit: Approach 5: I used this one recently, when I could not use Optional. The idea is simply to use naming convention for method arguments and class variables. I used "maybe"-prefix, so that if e.g. "url" argument is nullable, then it becomes maybeUrl. The advantage is that it slightly improves understandability of the intent (and does not have disadvantages of other approaches, like external dependencies or performance penalty). But there are also drawbacks, like: there is no tooling to support this convention (your IDE will not show you any warning, if you access "maybe"-variable without first checking it). Another problem is that it only helps, when applied consistently by all people working on the project.
This seems a bit silly to me, but the only reason I can think of is that object arguments in method parameters already are optional in a way - they can be null. Therefore forcing someone to take an existing object and wrap it in an optional is sort of pointless.
That being said, chaining methods together that take/return optionals is a reasonable thing to do, e.g. Maybe monad.
Accepting Optional as parameters causes unnecessary wrapping at caller level.
For example in the case of:
public int calculateSomething(Optional<String> p1, Optional<BigDecimal> p2 {}
Suppose you have two not-null strings (ie. returned from some other method):
String p1 = "p1";
String p2 = "p2";
You're forced to wrap them in Optional even if you know they are not Empty.
This get even worse when you have to compose with other "mappable" structures, ie. Eithers:
Either<Error, String> value = compute().right().map((s) -> calculateSomething(
< here you have to wrap the parameter in a Optional even if you know it's a
string >));
ref:
methods shouldn't expect Option as parameters, this is almost always a
code smell that indicated a leakage of control flow from the caller to
the callee, it should be responsibility of the caller to check the
content of an Option
ref. https://github.com/teamdigitale/digital-citizenship-functions/pull/148#discussion_r170862749
My take is that Optional should be a Monad and these are not conceivable in Java.
In functional programming you deal with pure and higher order functions that take and compose their arguments only based on their "business domain type". Composing functions that feed on, or whose computation should be reported to, the real-world (so called side effects) requires the application of functions that take care of automatically unpacking the values out of the monads representing the outside world (State, Configuration, Futures, Maybe, Either, Writer, etc...); this is called lifting. You can think of it as a kind of separation of concerns.
Mixing these two levels of abstraction doesn't facilitate legibility so you're better off just avoiding it.
Another reason to be carefully when pass an Optional as parameter is that a method should do one thing... If you pass an Optional param you could favor do more than one thing, it could be similar to pass a boolean param.
public void method(Optional<MyClass> param) {
if(param.isPresent()) {
//do something
} else {
//do some other
}
}
So, if you would permit the pun, Oracle issued an oracle:
Thou shalt not use Optional but for function return values.
I love it how most of the answers so far are going along with the narrative of Oracle's oracle, which is re-iterated unquestioned all over the interwebz, in the "many Web sites" mentioned in the question. This is very typical of stack overflow: if something is allegedly supposed to be a certain way, and you ask why it is supposed to be that way, almost everyone will offer reasons why; almost nobody will question whether it should in fact be that way.
So, here is a dissenting opinion:
You can use Optional to completely eliminate null from your code base.
I have done it in a 100k-lines-of-code project. It worked.
If you decide to go along this path, then you will need to be thorough, so you will have a lot of work to do. The example mentioned in the accepted answer with Optional.ofNulable() should never occur, because if you are thorough, then you should never have anything returning null, and therefore no need for Optional.ofNullable(). In that 100k-lines-of-code project that I mentioned above, I have only used Optional.ofNullable() a couple of times when receiving results from external methods that I have no control over.
Also, if you decide to go along this path, your solution will not be the most performant solution possible, because you will be allocating lots of optionals. However:
That's nothing but a runtime performance overhead disadvantage.
That's not a severe disadvantage.
That's Java's problem, not your problem.
Let me explain that last part.
Java does not offer explicit nullability of reference types as C# does (since version 8.0) so it is inferior in this regard. (I said "in this regard"; in other regards, Java is better; but that's off-topic right now.)
The only proper alternative to explicit nullability of reference types is the Optional type.
(And it is arguably even slightly better, because with Optional you can indicate optional-of-optional, if you must, whereas with explicit nullability you cannot have ReferenceType??, or at least you cannot in C# as it is currently implemented.)
Optional does not have to add overhead, it only does so in Java. That's because Java also does not support true value types, as C# and Scala do. In this regard, Java is severely inferior to those languages. (Again, I said "in this regard"; in other regards, Java is better; but that's off-topic right now.) If Java did support true value types, then Optional would have been implemented as a single machine word, which would mean that the runtime overhead of using it would be zero.
So, the question that it boils down to is: do you want perfect clarity and type safety in your code, or do you prefer maximum performance? I believe that for high-level languages, (of which Java certainly aims to be one,) this question was settled a long time ago.
I think that is because you usually write your functions to manipulate data, and then lift it to Optional using map and similar functions. This adds the default Optional behavior to it.
Of course, there might be cases, when it is necessary to write your own auxilary function that works on Optional.
I believe the reson of being is you have to first check whether or not Optional is null itself and then try to evaluate value it wraps. Too many unnecessary validations.
I know that this question is more about opinion rather than hard facts. But I recently moved from being a .net developer to a java one, so I have only recently joined the Optional party. Also, I'd prefer to state this as a comment, but since my point level does not allow me to comment, I am forced to put this as an answer instead.
What I have been doing, which has served me well as a rule of thumb. Is to use Optionals for return types, and only use Optionals as parameters, if I require both the value of the Optional, and weather or not the Optional had a value within the method.
If I only care about the value, I check isPresent before calling the method, if I have some kind of logging or different logic within the method that depends on if the value exists, then I will happily pass in the Optional.
Using Optional as parameters might be useful in some use cases which involves protobufs or setting fields in a configuration object.
public void setParameters(Optional<A> op1, Optional<B> op2) {
ProtoRequest.Builder builder = ProtoRequest.newBuilder();
op1.ifPresent(builder::setOp1);
op2.ifPresent(builder::setOp2);
...
}
I think in such cases it might be useful to have optional as parameters. API receiving the proto request would handle the different fields.
If a function is not doing additional computations on these parameters then using Optional might be simpler.
public void setParameters(A op1, B op2) {
ProtoRequest.Builder builder = ProtoRequest.newBuilder();
if (op1 != null) {
builder.setOp1(op1);
}
if (op2 != null) {
builder.setOp2(op2);
}
...
}
Optionals aren't designed for this purpose, as explained nicely by Brian Goetz.
You can always use #Nullable to denote that a method argument can be null. Using an optional does not really enable you to write your method logic more neatly.
One more approach, what you can do is
// get your optionals first
Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();
// bind values to a function
Supplier<Integer> calculatedValueSupplier = () -> { // your logic here using both optional as state}
Once you have built a function(supplier in this case) you will be able to pass this around as any other variable and would be able to call it using
calculatedValueSupplier.apply();
The idea here being whether you have got optional value or not will be internal detail of your function and will not be in parameter. Thinking functions when thinking about optional as parameter is actually very useful technique that I have found.
As to your question whether you should actually do it or not is based on your preference, but as others said it makes your API ugly to say the least.
At first, I also preferred to pass Optionals as parameter, but if you switch from an API-Designer perspective to a API-User perspective, you see the disadvantages.
For your example, where each parameter is optional, I would suggest to change the calculation method into an own class like follows:
Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();
MyCalculator mc = new MyCalculator();
p1.map(mc::setP1);
p2.map(mc::setP2);
int result = mc.calculate();
This is because we have different requirements to an API user and an API developer.
A developer is responsible for providing a precise specification and a correct implementation. Therefore if the developer is already aware that an argument is optional the implementation must deal with it correctly, whether it being a null or an Optional. The API should be as simple as possible to the user, and null is the simplest.
On the other hand, the result is passed from the API developer to the user. However the specification is complete and verbose, there is still a chance that the user is either unaware of it or just lazy to deal with it. In this case, the Optional result forces the user to write some extra code to deal with a possible empty result.
First of all, if you're using method 3, you can replace those last 14 lines of code with this:
int result = myObject.calculateSomething(p1.orElse(null), p2.orElse(null));
The four variations you wrote are convenience methods. You should only use them when they're more convenient. That's also the best approach. That way, the API is very clear which members are necessary and which aren't. If you don't want to write four methods, you can clarify things by how you name your parameters:
public int calculateSomething(String p1OrNull, BigDecimal p2OrNull)
This way, it's clear that null values are allowed.
Your use of p1.orElse(null) illustrates how verbose our code gets when using Optional, which is part of why I avoid it. Optional was written for functional programming. Streams need it. Your methods should probably never return Optional unless it's necessary to use them in functional programming. There are methods, like Optional.flatMap() method, that requires a reference to a function that returns Optional. Here's its signature:
public <U> Optional<U> flatMap(Function<? super T, ? extends Optional<? extends U>> mapper)
So that's usually the only good reason for writing a method that returns Optional. But even there, it can be avoided. You can pass a getter that doesn't return Optional to a method like flatMap(), by wrapping it in a another method that converts the function to the right type. The wrapper method looks like this:
public static <T, U> Function<? super T, Optional<U>> optFun(Function<T, U> function) {
return t -> Optional.ofNullable(function.apply(t));
}
So suppose you have a getter like this: String getName()
You can't pass it to flatMap like this:
opt.flatMap(Widget::getName) // Won't work!
But you can pass it like this:
opt.flatMap(optFun(Widget::getName)) // Works great!
Outside of functional programming, Optionals should be avoided.
Brian Goetz said it best when he said this:
The reason Optional was added to Java is because this:
return Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods())
.stream()
.filter(m -> Objects.equals(m.getName(), enclosingInfo.getName())
.filter(m -> Arrays.equals(m.getParameterTypes(), parameterClasses))
.filter(m -> Objects.equals(m.getReturnType(), returnType))
.findFirst()
.getOrThrow(() -> new InternalError(...));
is cleaner than this:
Method matching =
Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods())
.stream()
.filter(m -> Objects.equals(m.getName(), enclosingInfo.getName())
.filter(m -> Arrays.equals(m.getParameterTypes(), parameterClasses))
.filter(m -> Objects.equals(m.getReturnType(), returnType))
.getFirst();
if (matching == null)
throw new InternalError("Enclosing method not found");
return matching;
Irrespective of Java 8, Use old school method overloading technique to bring clarity and flexibility, suppose you have following method with two args
public void doSomething(arg1,arg2);
in case you want to add additional optional parameter then overload the method
public void doSomething(arg1,arg2,arg3) {
Result result = doSomething(arg1,arg2);
// do additional working
}
A good example were Optional as arguments would be nice is JPA Repositories. Id love to do something like findByNameAndSurname(Optional,Optional). That way, if the Optional is empty, no WHERE param=y is performed
Optional type introduced in Java 8 is a new thing for many developers.
Is a getter method returning Optional<Foo> type in place of the classic Foo a good practice? Assume that the value can be null.
Of course, people will do what they want. But we did have a clear intention when adding this feature, and it was not to be a general purpose Maybe type, as much as many people would have liked us to do so. Our intention was to provide a limited mechanism for library method return types where there needed to be a clear way to represent "no result", and using null for such was overwhelmingly likely to cause errors.
For example, you probably should never use it for something that returns an array of results, or a list of results; instead return an empty array or list. You should almost never use it as a field of something or a method parameter.
I think routinely using it as a return value for getters would definitely be over-use.
There's nothing wrong with Optional that it should be avoided, it's just not what many people wish it were, and accordingly we were fairly concerned about the risk of zealous over-use.
(Public service announcement: NEVER call Optional.get unless you can prove it will never be null; instead use one of the safe methods like orElse or ifPresent. In retrospect, we should have called get something like getOrElseThrowNoSuchElementException or something that made it far clearer that this was a highly dangerous method that undermined the whole purpose of Optional in the first place. Lesson learned. (UPDATE: Java 10 has Optional.orElseThrow(), which is semantically equivalent to get(), but whose name is more appropriate.))
After doing a bit of research of my own, I've come across a number of things that might suggest when this is appropriate. The most authoritative being the following quote from an Oracle article:
"It is important to note that the intention of the Optional class is not to replace every single null reference. Instead, its purpose is to help design more-comprehensible APIs so that by just reading the signature of a method, you can tell whether you can expect an optional value. This forces you to actively unwrap an Optional to deal with the absence of a value." - Tired of Null Pointer Exceptions? Consider Using Java SE 8's Optional!
I also found this excerpt from Java 8 Optional: How to use it
"Optional is not meant to be used in these contexts, as it won't buy us anything:
in the domain model layer (not serializable)
in DTOs (same reason)
in input parameters of methods
in constructor parameters"
Which also seems to raise some valid points.
I wasn't able to find any negative connotations or red flags to suggest that Optional should be avoided. I think the general idea is, if it's helpful or improves the usability of your API, use it.
I'd say in general its a good idea to use the optional type for return values that can be nullable. However, w.r.t. to frameworks I assume that replacing classical getters with optional types will cause a lot of trouble when working with frameworks (e.g., Hibernate) that rely on coding conventions for getters and setters.
The reason Optional was added to Java is because this:
return Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods())
.stream()
.filter(m -> Objects.equals(m.getName(), enclosingInfo.getName())
.filter(m -> Arrays.equals(m.getParameterTypes(), parameterClasses))
.filter(m -> Objects.equals(m.getReturnType(), returnType))
.findFirst()
.getOrThrow(() -> new InternalError(...));
is cleaner than this:
Method matching =
Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods())
.stream()
.filter(m -> Objects.equals(m.getName(), enclosingInfo.getName())
.filter(m -> Arrays.equals(m.getParameterTypes(), parameterClasses))
.filter(m -> Objects.equals(m.getReturnType(), returnType))
.getFirst();
if (matching == null)
throw new InternalError("Enclosing method not found");
return matching;
My point is that Optional was written to support functional programming, which was added to Java at the same time. (The example comes courtesy of a blog by Brian Goetz. A better example might use the orElse() method, since this code will throw an exception anyway, but you get the picture.)
But now, people are using Optional for a very different reason. They're using it to address a flaw in the language design. The flaw is this: There's no way to specify which of an API's parameters and return values are allowed to be null. It may be mentioned in the javadocs, but most developers don't even write javadocs for their code, and not many will check the javadocs as they write. So this leads to a lot of code that always checks for null values before using them, even though they often can't possibly be null because they were already validated repeatedly nine or ten times up the call stack.
I think there was a real thirst to solve this flaw, because so many people who saw the new Optional class assumed its purpose was to add clarity to APIs. Which is why people ask questions like "should getters return Optionals?" No, they probably shouldn't, unless you expect the getter to be used in functional programming, which is very unlikely. In fact, if you look at where Optional is used in the Java API, it's mainly in the Stream classes, which are the core of functional programming. (I haven't checked very thoroughly, but the Stream classes might be the only place they're used.)
If you do plan to use a getter in a bit of functional code, it might be a good idea to have a standard getter and a second one that returns Optional.
Oh, and if you need your class to be serializable, you should absolutely not use Optional.
Optionals are a very bad solution to the API flaw because a) they're very verbose, and b) They were never intended to solve that problem in the first place.
A much better solution to the API flaw is the Nullness Checker. This is an annotation processor that lets you specify which parameters and return values are allowed to be null by annotating them with #Nullable. This way, the compiler can scan the code and figure out if a value that can actually be null is being passed to a value where null is not allowed. By default, it assumes nothing is allowed to be null unless it's annotated so. This way, you don't have to worry about null values. Passing a null value to a parameter will result in a compiler error. Testing an object for null that can't be null produces a compiler warning. The effect of this is to change NullPointerException from a runtime error to a compile-time error.
This changes everything.
As for your getters, don't use Optional. And try to design your classes so none of the members can possibly be null. And maybe try adding the Nullness Checker to your project and declaring your getters and setter parameters #Nullable if they need it. I've only done this with new projects. It probably produces a lot of warnings in existing projects written with lots of superfluous tests for null, so it might be tough to retrofit. But it will also catch a lot of bugs. I love it. My code is much cleaner and more reliable because of it.
(There is also a new language that addresses this. Kotlin, which compiles to Java byte code, allows you to specify if an object may be null when you declare it. It's a cleaner approach.)
Addendum to Original Post (version 2)
After giving it a lot of thought, I have reluctantly come to the conclusion that it's acceptable to return Optional on one condition: That the value retrieved might actually be null. I have seen a lot of code where people routinely return Optional from getters that can't possibly return null. I see this as a very bad coding practice that only adds complexity to the code, which makes bugs more likely. But when the returned value might actually be null, go ahead and wrap it inside an Optional.
Keep in mind that methods that are designed for functional programming, and that require a function reference, will (and should) be written in two forms, one of which uses Optional. For example, Optional.map() and Optional.flatMap() both take function references. The first takes a reference to an ordinary getter, and the second takes one that returns Optional. So you're not doing anyone a favor by return an Optional where the value can't be null.
Having said all that, I still see the approach used by the Nullness Checker is the best way to deal with nulls, since they turn NullPointerExceptions from runtime bugs to compile time errors.
If you are using modern serializers and other frameworks that understand Optional then I have found these guidelines work well when writing Entity beans and domain layers:
If the serialization layer (usually a DB) allows a null value for a cell in column BAR in table FOO, then the getter Foo.getBar() can return Optional indicating to the developer that this value may reasonably be expected to be null and they should handle this. If the DB guarantees the value will not be null then the getter should not wrap this in an Optional.
Foo.bar should be private and not be Optional. There's really no reason for it to be Optional if it is private.
The setter Foo.setBar(String bar) should take the type of bar and not Optional. If it's OK to use a null argument then state this in the JavaDoc comment. If it's not OK to use null an IllegalArgumentException or some appropriate business logic is, IMHO, more appropriate.
Constructors don't need Optional arguments (for reasons similar to point 3). Generally I only include arguments in the constructor that must be non-null in the serialization database.
To make the above more efficient, you might want to edit your IDE templates for generating getters and corresponding templates for toString(), equals(Obj o) etc. or use fields directly for those (most IDE generators already deal with nulls).
You have to keep in mind that the often-cited advice came from people who had little experience outside Java, with option types, or with functional programming.
So take it with a grain of salt. Instead, let's look at it from the "good practice" perspective:
Good practice not only means asking "how do we write new code?", but also "what happens to existing code?".
In the case of Optional, my environment found a good and easy to follow answer:
Optional is mandatory to indicate optional values in records:
record Pet(String name, Optional<Breed> breed,
Optional<ZonedDateTime> dateOfBirth)
This means that existing code is good as-is, but code that makes use of record (that is, "new code") causes widespread adoption of Optional around it.
The result has been a complete success in terms of readability and reliability. Just stop using null.
After posting this question and reading that one I realized that it is very important to know if a method is supposed to return null, or if this is considered an error condition and an exceptions should be thrown. There also is a nice discussion when to return ‘null’ or throw exception .
I'm writing a method and I already know if I want to return null or throw an exception, what is the best way to express my decision, in other words, to document my contract?
Some ways I can think of:
Write it down in the specs / the documentation (will anyone read it?)
Make it part of the method name (as I suggested here)
assume that every method that throws an exception will not return null, and every one that does 'not' throw might return null.
I'm mainly talking about java, but it might apply to other languages, too: Why is there a formal way to express if exceptions will be thrown (the throws keywords) but no formal way to express if null might be returned?
Why isn't there something like that:
public notnull Object methodWhichCannotReturnNull(int i) throws Exception
{
return null; // this would lead to a compiler error!
}
Summary and Conclusion
There are many ways to express the contract:
If your IDE supports it (as IntelliJ), it's best to use an annotation like #NotNull because it is visible to the programmer and can be used for automated compile time checking. There's a plugin for Eclipse to add support for these, but it didn't work for me.
If these are not an option, use custom Types like Option<T> or NotNull<T>, which add clarity and at least runtime checking.
In any way, documenting the contract in the JavaDoc never hurts and sometimes even helps.
Using method names to document the nullability of the return value was not proposed by anyone but me, and though it might be very verbose und not always useful, I still believe sometimes it has its advantages, too.
A very good follow up question. I consider null a truly special value, and if a method may return null it must clearly document in the Javadoc when it does (#return some value ..., or null if ...). When coding I'm defensive, and assume a method may return null unless I'm convinced it can't (e.g., because the Javadoc said so.)
People realized that this is an issue, and a proposed solution is to use annotations to state the intention in a way it can be checked automatically. See JSR 305: Annotations for Software Defect Detection, JSR 308: Annotations on Java Types and JetBrain's Nullable How-To.
Your example might look like this, and refused by the IDE, the compiler or other code analysis tools.
#NotNull
public Object methodWhichCannotReturnNull(int i) throws Exception
{
return null; // this would lead to a compiler error!
}
You can use the Option type, which is very much like a list that has zero or one element. A return type of Option<Object> indicates that the method may return an Object, or it may return a special value of type None. This type is a replacement for the use of null with better type checks.
Example:
public Option<Integer> parseInt(String s) {
try {
return Option.some(Integer.parseInt(s));
}
catch (Exception e) {
return Option.none();
}
}
If you use this consistently, you can turn on IDE null-warnings, or just use grep for null which should not appear in your code at all if you use Option.none() everywhere you would normaly use a null literal.
Option comes standard with Scala, and it is called Maybe in Haskell. The link above is to a library called Functional Java that includes it. That version implements the Iterable interface, and has monadic methods that let you compose things nicely. For example, to provide a default value of 0 in case of None:
int x = optionalInt.orSome(0);
And you can replace this...
if (myString != null && !"".equals(myString))
...with this, if you have an Option<String>...
for (String s : myOptionString)
There's some support for a #Nullable and #NotNull annotation in IntelliJ IDEA. There's also some talk about adding those annotations (or a similar feature) to Java 7. Unfortunately I don't know how far that got or if it's still on track at all.
Indeed: in our framework we have a 'non-null' pointer type, which may be returned to indicate that the method will always return a value.
I see three options:
wait for language support to express it (e.g. the C# ?! thing)
use Aspect Orientation to build your own language extensions to express it
use a custom type to express it
(but builds on developer cooperation) use a naming scheme to indicate it
For Java, one can use the Javadoc description of a method to document the meaning of the returned value, including whether it can be null. As has been mentioned, annotations may also provide assistance here.
On the other hand, I admit that I don't see null as something to be feared. There are situations in which "nobody's home" is a meaningful condition (although the Null Object technique also has real value here).
It is certainly true that attempting a method invocation on a null value will cause an exception. But so will attempting to divide by zero. That doesn't mean that we need to go on a campaign to eliminate zeroes! It just means that we need to understand the contract on a method and do the right thing with the values that it returns.
Have you had a look at Spec#?
You could write your own annotation (Java) or attribute (C#) to indicate that the return value might be null. Nothing will automatically check it (although .NET 4.0 will have code contracts for this sort of thing) but it would at least act as documentation.
Maybe you could define a generic class named "NotNull", so that your method might be like:
public NotNull<Object> methodWhichCannotReturnNull(int i) throws Exception
{
// the following would lead to a run-time error thown by the
// NotNull constructor, if it's constructed with a null value
return new NotNull<Object>(null);
}
This is still a run-time (not a compile-time) check, but:
It's thrown in the implementation of the method (it's not a fault in the calling code)
It's self-documenting (the caller knows he's geting NotNull<T> as a return type)
At all costs, avoid relying on the JavaDocs. People only read them if the signature doesn't appear trivial and self-explanatory (Which is bad to begin with), and these who actually bother to read them are less likely to make a mistake with the nulls since they are currently being more careful.
If you're using Java 5+, you can use a custom Annotation, e.g. #MayReturnNull
UPDATE
All coding philosophy aside (returning null, using exceptions, assertions, yada yada), I hope the above answers your question. Apart from primitives having default values, complex types may or may not be null, and your code needs to deal with it.
Generally speaking, I would assume that a null return value is against the contract of the API by default. It is almost always possible to design your code such that a null value is never returned from your APIs during "normal" flow of execution. (For example, check foo.contains(obj) rather then calling foo.get(obj) and having a separate branch for null. Or, use the Null object pattern.
If you cannot design your API in such a way, I would clearly document when and why a null could be thrown--at least in the Javadoc, and possibly also using a custom #annotation such as several of the other answers have suggested.