Consider the following example where the classes TextFile, XmlFile, HtmlFile, ShellScriptFile, et cetera, are all subclasses of the class SimpleFile. I am writing a class FileOperations, which has a method that searches the contents of a generic file depending on its type.
Following is a code sample:
public searchFile(SimpleFile targetFile, String searchStr) {
if (targetPage instanceof HtmlFile) {
// search html file
}
else if (targetPage instanceof TextFile) {
// search text file
}
else if (targetPage instanceof XmlFile) {
// search xml file
}
else if (targetPage instanceof ShellScriptFile) {
// search shell file
}
...
}
This structure smells bad to me. I am aware that this is the best case for polymorphism. But I do not have control over the File class or its subclasses.I cannot write to them.
Is there another way to go about cleaning this mess? Because the if-else structure is going to keep increasing as I add support for different file types.
Else, if I am stuck with this structure, then is instanceof the fastest operator in Java? What are its implications on performance?
Would it be better to use getClass() or isAssignableFrom() for the above case?
I appreciate your comments or suggestions!
First I would say that your example doesn't seem bad at all. It's a little verbose, and arguable not as cohesive as separating them into different methods but it looks fairly normal to me. I think a neater approach might be to use overloading instead. I can't speak for the difference in speed but from a maintenance and extensibility stance it will be easier to deal with in future.
public void searchFile(SimpleFile targetFile , String searchStr) {
// SimpleFile generalized behavior.
if (targetPage instanceof HtmlFile) searchFile((HtmlFile)targetFile, searchStr);
else if (targetPage instanceof TextFile) searchFile((TextFile)targetFile, searchStr);
else if (targetPage instanceof XmlFile) searchFile((XmlFile)targetFile, searchStr);
else if (targetPage instanceof ShellScriptFile) searchFile((ShellScriptFile)targetFile, searchStr);
else System.out.println("Subtype not recognised");
}
public void searchFile(HtmlFile targetFile , String searchStr) {
// HtmlFile specific behavior
}
public void searchFile(TextFile targetFile , String searchStr) {
// TextFile specific behavior
}
public void searchFile(XmlFile targetFile , String searchStr) {
// XmlFile specific behavior
}
public void searchFile(ShellScriptFile targetFile , String searchStr) {
// ShellScript specific behavior
}
In the event of a new subclass of SimpleFile, it will default to the SimpleFile version of the method. In the event that the type is not known at compile time (as brought up in the comments) the most general searchFile() method can be used to check and redistribute the object accordingly.
Edit: As a note on the performance impact of multiple use of instanceof, the consensus appears to be that it's irrelevant, and that the use of modern instanceof is pretty fast anyway.
If you could modify File and its subclasses, you could try using the Visitor pattern. Since you cannot, I recommend that you consolidate your type testing switch statement into a single method so that you will only need to modify one switch.
public Enum FileHandler {
HTML(){
public search(File file, String searchstr){ /* ... */}
public prettyPrint(File file){ /* ... */}
},
XML(){ /* ... */};
// ... end list of enum implementations
public static FileHander get(File file){
// Put your master switch statement here
if (targetPage instanceof HtmlFile) {
return HTML;
}
else if (targetPage instanceof XmlFile) {
return XML;
}
// ...
}
}
And your code to use the enum class will look something like this, avoiding the dreaded switch statement:
public searchFile(SimpleFile targetFile, String searchStr) {
FileHandler.get(targetFile).search(targetFile, searchStr);
}
My approach would be to create an interface FileSearcher with a single method that performs the business logic. Create one implementation of this interface per file type. Then, create a registry which maps subclasses of SimpleFile to their corresponding implementation of FileSearcher. In your search file method, rather than doing the instanceof checks, look up the matching FileSeacher implementation at runtime and delegate to it.
With this implementation you may run into trouble when there are subclasses of HtmlFile etc., because you would have to map HtmlFileSearcher to all subclasses of HtmlFile. In that case, add another method to FileSearcher, named canHandle(Class<SimpleFile> runtimeClass) that allows FileSearcher implementations to signal what file class they understand. In the registry, rather than looking it up in the map, walk over all registered FileSearchers.
you could use interpreter-design-pattern or chain-of-responsibility-design-pattern to solve this problem. these patterns seem just the perfect fix for this problem.
an example for interpreter-design-pattern, comment if you need an example for chain-of-responsibility-design-pattern
Client:
public Integer wordCountOnPage (Page samplePage)
{
ArrayList list = new ArrayList<Page>();
list.add(new XmlPage());
list.add(new HtmlPage());
list.add(new JsonPage());
for (int index = 0 ; index < list.size(); index ++)
{
Page eachPage = (Page) list.get(index);
if (eachPage.intercept(samplePage)){
Integer i = eachPage.wordCountOnPage(samplePage);
}
}
return 1;
}
public class XmlPage implements Page {
#Override
public Boolean intercept(Page page) {
// TODO Auto-generated method stub
return page instanceof XmlPage;
}
#Override
public Integer wordCountOnPage(Page page) {
// TODO Auto-generated method stub
return null;
}
}
public interface Page {
Boolean intercept(Page page);
Integer wordCountOnPage(Page page);
}
Related
I am building a HTTP server for my android device.
I am using a lot of IF-ELSE statements to handle differnt requests.
As I will be sharing my code with other people for later use, I will have to make it as legible as possible. Right now, I can't even read my code with ease.
I think the problem comes from using a lot of IF-ELSE statements in one class.
For example.
if(purpose.equals("readProfile"){
.....
}
else if(purpose.equals("writeProfile"){
.....
}
....
I tried classifying them in category and ordered the conditions according to their category. But not a lot of legebility was improved.
Then I tried writing short comments infront of each conditions. But this made even more mess.
What can be done to increase legibility for conditional statements?
As Luiggi Mendoza stated, this is a follow up of a previous question...
If you are using Java 7, you can use a switch-case statement for strings
//month is a String
switch (month.toLowerCase()) {
case "january":
monthNumber = 1;
break;
//partsleft out for sake of brevity ..
default:
monthNumber = 0;
break;
}
(excerpt from the Oracle Java Tutorials, referenced above.)
Refactoring
However, this huge if-else is just part of the problem. As this seems to be a structure growing over time, I'd recommend a thorough refactoring, and using what seems to me is a Strategy pattern. You should:
Formulate an interface which covers the boundaries for all the use cases:
interface MyStrategy {
void execute(MyInputContext input, MyOutputContext output);
}
(using a void method with MyInputContext and MyOutputContext are just one approach, this is just an example, but to handle requests that have responses, this makes sense, just like how Servlets work)
Refactor the content of the big IF-ELSE statement into instances of this interface (these will be the strategies):
//VERY simplified...
class ReadProfileStrategy implements MyStrategy {
void execute(MyInputContext input, MyOutputContext output) {
//do the stuff that was in the if-else block in the "readProfile" part
}
}
//... at the branching part:
MyInputContext input; //build this here
MyOutputContext output; //build this here
switch (purpose) {
case "readProfile":
// no need to always instantiate this, it should be stateless...
new ReadProfileStrategy().execute();
break;
//... left out for sake of brevity
}
Refactoring step 2
If this is done, you can add the string IDs to the interface, and the instances themselves, and get rid of the if-else or switch statement altogether, you could create a Map populated even through an IOC container (like), to be up to date, and completely flexible.
class ReadProfileStrategy implements MyStrategy {
String getID() {
return "readProfile";
}
void execute(MyInputContext input, MyOutputContext output) {
//do the stuff that was in the if-else block in the "readProfile" part
}
}
In the class when requests are processed
private final Map<String, MyStrategy> strategyMap; //fill the map using your favorite approach, like using Spring application context, using the getCode() to provide the key of the map
In the processing logic:
MyStrategy strategy = strategyMap.get(purpose);
if(strategy!=null) {
strategy.execute();
}
else {
//handle error here
}
This may be out of scope, but just an observation
try using
if("readProfile".equals(purpose){} instead of
if(purpose.equals("readProfile"){}.
It will help to avoid null pinter exception
Enums can help - you can also add functionality to them.
public void test(String purpose) {
if (purpose.equals("readProfile")) {
// Read.
} else if (purpose.equals("writeProfile")) {
// Write.
}
}
enum Purpose {
readProfile {
#Override
void doIt() {
// Read.
}
},
writeProfile {
#Override
void doIt() {
// Write.
}
};
abstract void doIt();
}
public void test2(String purpose) {
Purpose.valueOf(purpose).doIt();
}
You can try using some kind of Action-Interface with implementations for each block and preload a map with concrete Implementations of this action.
interface Action {
void execute();
}
Map<String, Action> actions = new HashMap<>();
actions.put("readProfile", new Action() { ... });
actions.put("writeProfile", new Action() { ... });
actionMap.get(purpose).execute();
That will lower your cyclomatic complexity as well. Of course you should preload the map only once.
Well, If it makes sense to separate code inside if-else condition to another class, perhaps use Factory pattern. Also make all separated classes implement common interface (eg: MyActivity.class) with a method such as execute().
Factory decides what object (ReadProfile.class, WriteProfile.class etc.) has to be created based on the string you pass and then call execute() method.
MyActivity obj = MyFactory.createMyActivity(String)
obj.execute(...);
I have one class, let's call it ClassA, and a bunch of subclasses of it, and subsequent subclasses of those classes. ClassA, and every class below it takes a String at an argument in their constructor. I have a bunch of String objects that I need to 'convert' into subclasses of ClassA.
The current way I am doing it is with is isType(String) method that checks if the String is an instance of that subclass, but it seems like very bad programming technique to use a huge if-else or switch-case statement to find the correct type of ClassA that the String is. It there a common way to go down a sub-class structure, or is the way that I have been doing it okay?
The purpose of this is that I am making a scripting language (for a fun project) and I need to be able identify what something is. (Data type that is)
Example code:
public static boolean isType(String data) {
data = data.trim();
return edu.ata.script.data.Boolean.isType(data)
|| edu.ata.script.data.Integer.isType(data)
|| edu.ata.script.data.Double.isType(data)
|| DATA_STORAGE.contains(data)
|| ReturningMethod.isType(data)
|| edu.ata.script.data.String.isType(data);
}
public static Data get(String data) {
data = data.trim();
/*:)*/ if (edu.ata.script.data.Boolean.isType(data)) {
return edu.ata.script.data.Boolean.get(data);
} else if (edu.ata.script.data.Integer.isType(data)) {
return edu.ata.script.data.Integer.get(data);
} else if (edu.ata.script.data.Double.isType(data)) {
return edu.ata.script.data.Double.get(data);
} else if (DATA_STORAGE.contains(data)) {
return (Data) DATA_STORAGE.get(data);
} else if (ReturningMethod.isType(data)) {
return ReturningMethods.getMethodValue(data);
} else if (edu.ata.script.data.String.isType(data)) {
// Last option because everything is accepted.
return edu.ata.script.data.String.get(data);
} else {
throw new RuntimeException("Could not parse data - " + data);
}
}
I was indeed understanding something totally different, so I'm re-editing this answer.
I suspect that you're working in some sort of importation script or something and that the edu.ata.script.data.* are the ClassB, ClassC, etc that you were writing and they know how to convert stuff from one format to another... (This is just guessing)
My suggestion to get rid of all the if then else in the get(String data) method is that you implement a chain of responsability. That way you can have a chain that registers the several edu.ata.script.data.* in a List and then you iterate through that list until one of them returns true for the isType(string) knowing which subclass you want to use to process the string.
To remove the list of ORs in the isType(String data) method is a bit trickier and probably this is a bit over enginnering, but you can do the following:
Look in your classpath for classes that are assignableFrom your class
Then when you would retrieve all the classes that were assignable by your own you would have to invoke via reflection the isType of each one to know the result
I know you might find yourself a bit lost regarding the 1st point, best way is to look into ResolverUtil class from Stripes Framework where they do that in the method loadImplementationsFromContextClassloader
It looks like you are trying to parse a string into an instance of the correct subclass, by passing it to each subclass's isType method until one says it can handle it. I would have each subclass register a parser object which can inspect the string and produce an initialised instance of the corresponding subclass if possible.
Interface for the Parsers:
package edu.ata.script.data;
interface ScriptParser {
public boolean isType(String data);
public Data get(String data) throws UnparsableException;
}
An example Data subclass:
package edu.ata.script.data;
public class Boolean extends Data {
// Empty constructor for reflection purposes
public Boolean() {};
public Boolean(String data) {
// Initialise from string
}
public ScriptParser getParser() {
return new ScriptParser() {
public boolean isType(String data) {
return "true".equals(data) || "false".equals(data);
}
public Data get(String data) throws UnparsableException {
if (isType(data)) {
return new edu.ata.script.data.Boolean(data);
} else {
throw new UnparsableException(data);
}
}
};
}
}
Then you can just build a list of classes into a collection before parsing:
List<ScriptParser> parsers = new LinkedList<>();
parsers.add(new edu.ata.script.data.Boolean().getParser());
parsers.add(new edu.ata.script.data.Integer().getParser());
parsers.add(new edu.ata.script.data.Double().getParser());
...
The above could also be achieved via reflection.
Then you can parse the data with a simple loop, no matter how many data types you end up supporting:
public Data get(String data) throws SyntaxErrorException {
for (ScriptParser sp:parsers) {
if (sp.isType(data)) {
try {
return sp.get(data);
} catch (UnparsableException e) {
// This shouldn't happen, but better safe than sorry!
e.printStackTrace();
}
}
}
throw new SyntaxErrorException(data);
}
I'm using JQuery to call a Java Servlet from multiple places to call multiple different methods within the servlet. At the moment, I pass a string (called methodName) and then using an ever increasing IF ELSE block to see which function to call:
public String methodCaller(String methodName) throws SQLException, IOException
{
if(methodName.equals("method1"))
{
return method1(attr("permit"));
}
else if(methodName.equals("method2"))
{
return method2(attr("ring"));
}
else if(methodName.equals("method3"))
{
return method3(attr("gridRef"));
}
else if(methodName.equals("method4"))
{
return method4(attr("ring"));
}
else if(methodName.equals("method6"))
{
return method6(attr("ring"), Integer.parseInt(attr("quantity")));
}
However, this seems awfully clunky and inefficient to me, especially as the amount of methods will increase in future. Is there a more efficient way to compare the strings? Or should I simply make a separate servlet for each method (and simply do the processing in the processRequest?
I would recommend, you should consider restful webservice.. REST defines a set of architectural principles by which you can design Web services that focus on a system's resources, including how resource states are addressed and transferred over HTTP by a wide range of clients written in different languages.
There are many open source which helps you to implement restful servlet very easily... One of them is Apache Wink http://incubator.apache.org/wink/
There is good article on the same in IBM Developerworks
http://www.ibm.com/developerworks/web/library/wa-apachewink1/
http://www.ibm.com/developerworks/web/library/wa-apachewink2/index.html
http://www.ibm.com/developerworks/web/library/wa-apachewink3/index.html
Other alternatives :
Spring MVC
Apache CXF http://cxf.apache.org/docs/jax-rs.html
I would recommend making each one of your methods an object that implements a simple interface. In your class, create a HashMap linking each implementation of the interface to its respective key.
Interface
public interface MyMethod {
public String call();
}
Implementation
public class MethodOne implements MyMethod{
}
Mapping & Call
private Map<String, MyMethod> mappings = new HashMap<String,MyMethod>();
static{
mappings.put("method1", new MethodOne());
//.. other mappings
}
public String methodCaller(String methodName) throws SQLException, IOException
{
MyMethod myMethod = mappings.get(methodName);
return myMethod.call();
}
I would simply start using an integer.
in your javascript have a function like this
function convertmethod(methodname)
{
thereturn = -1;
switch(methodname) {
case "Method1" : thereturn = 1;break;
case "Method2" : thereturn = 2;break;
case "Method3" : thereturn = 3;break;
case "Method4" : thereturn = 4;break;
}
return thereturn;
}
Then in your java code you can also use a switch
public String methodCaller(int methodName) throws SQLException, IOException
{
switch(methodName)
{
case 1: return method1(attr("permit"));break;
case 2: return method2(attr("permit"));break;
case 3: return method3(attr("ring"));break;
case 4: return method4(attr("gridRed"));break;
}
}
This is the second time I found myself writing this kind of code, and decided that there must be a more readable way to accomplish this:
My code tries to figure something out, that's not exactly well defined, or there are many ways to accomplish it. I want my code to try out several ways to figure it out, until it succeeds, or it runs out of strategies. But I haven't found a way to make this neat and readable.
My particular case: I need to find a particular type of method from an interface. It can be annotated for explicitness, but it can also be the only suitable method around (per its arguments).
So, my code currently reads like so:
Method candidateMethod = getMethodByAnnotation(clazz);
if (candidateMethod == null) {
candidateMethod = getMethodByBeingOnlyMethod(clazz);
}
if (candidateMethod == null) {
candidateMethod = getMethodByBeingOnlySuitableMethod(clazz);
}
if (candidateMethod == null) {
throw new NoSuitableMethodFoundException(clazz);
}
There must be a better way…
Edit: The methods return a method if found, null otherwise. I could switch that to try/catch logic, but that hardly makes it more readable.
Edit2: Unfortunately, I can accept only one answer :(
To me it is readable and understandable. I'd simply extract the ugly part of the code to a separate method (following some basic principles from "Robert C.Martin: Clean Code") and add some javadoc (and apologies, if necessary) like that:
//...
try {
Method method = MethodFinder.findMethodIn(clazz);
catch (NoSuitableMethodException oops) {
// handle exception
}
and later on in MethodFinder.java
/**
* Will find the most suitable method in the given class or throw an exception if
* no such method exists (...)
*/
public static Method findMethodIn(Class<?> clazz) throws NoSuitableMethodException {
// all your effort to get a method is hidden here,
// protected with unit tests and no need for anyone to read it
// in order to understand the 'main' part of the algorithm.
}
I think for a small set of methods what you're doing is fine.
For a larger set, I might be inclined to build a Chain of Responsibility, which captures the base concept of trying a sequence of things until one works.
I don't think that this is such a bad way of doing it. It is a bit verbose, but it clearly conveys what you are doing, and is easy to change.
Still, if you want to make it more concise, you can wrap the methods getMethod* into a class which implements an interface ("IMethodFinder") or similar:
public interface IMethodFinder{
public Method findMethod(...);
}
Then you can create instances of you class, put them into a collection and loop over it:
...
Method candidateMethod;
findLoop:
for (IMethodFinder mf: myMethodFinders){
candidateMethod = mf.findMethod(clazz);
if (candidateMethod!=null){
break findLoop;
}
}
if (candidateMethod!=null){
// method found
} else {
// not found :-(
}
While arguably somewhat more complicated, this will be easier to handle if you e.g. need to do more work between calling the findMethods* methods (such as more verification that the method is appropriate), or if the list of ways to find methods is configurable at runtime...
Still, your approach is probably OK as well.
I'm sorry to say, but the method you use seems to be the widely accepted one. I see a lot of code like that in the code base of large libraries like Spring, Maven etc.
However, an alternative would be to introduce a helper interface that can convert from a given input to a given output. Something like this:
public interface Converter<I, O> {
boolean canConvert(I input);
O convert(I input);
}
and a helper method
public static <I, O> O getDataFromConverters(
final I input,
final Converter<I, O>... converters
){
O result = null;
for(final Converter<I, O> converter : converters){
if(converter.canConvert(input)){
result = converter.convert(input);
break;
}
}
return result;
}
So then you could write reusable converters that implement your logic. Each of the converters would have to implement the canConvert(input) method to decide whether it's conversion routines will be used.
Actually: what your request reminds me of is the Try.these(a,b,c) method in Prototype (Javascript).
Usage example for your case:
Let's say you have some beans that have validation methods. There are several strategies to find these validation methods. First we'll check whether this annotation is present on the type:
// retention, target etc. stripped
public #interface ValidationMethod {
String value();
}
Then we'll check whether there's a method called "validate". To make things easier I assume, that all methods define a single parameter of type Object. You may choose a different pattern. Anyway, here's sample code:
// converter using the annotation
public static final class ValidationMethodAnnotationConverter implements
Converter<Class<?>, Method>{
#Override
public boolean canConvert(final Class<?> input){
return input.isAnnotationPresent(ValidationMethod.class);
}
#Override
public Method convert(final Class<?> input){
final String methodName =
input.getAnnotation(ValidationMethod.class).value();
try{
return input.getDeclaredMethod(methodName, Object.class);
} catch(final Exception e){
throw new IllegalStateException(e);
}
}
}
// converter using the method name convention
public static class MethodNameConventionConverter implements
Converter<Class<?>, Method>{
private static final String METHOD_NAME = "validate";
#Override
public boolean canConvert(final Class<?> input){
return findMethod(input) != null;
}
private Method findMethod(final Class<?> input){
try{
return input.getDeclaredMethod(METHOD_NAME, Object.class);
} catch(final SecurityException e){
throw new IllegalStateException(e);
} catch(final NoSuchMethodException e){
return null;
}
}
#Override
public Method convert(final Class<?> input){
return findMethod(input);
}
}
// find the validation method on a class using the two above converters
public static Method findValidationMethod(final Class<?> beanClass){
return getDataFromConverters(beanClass,
new ValidationMethodAnnotationConverter(),
new MethodNameConventionConverter()
);
}
// example bean class with validation method found by annotation
#ValidationMethod("doValidate")
public class BeanA{
public void doValidate(final Object input){
}
}
// example bean class with validation method found by convention
public class BeanB{
public void validate(final Object input){
}
}
You may use Decorator Design Pattern to accomplish different ways of finding out how to find something.
public interface FindMethod
{
public Method get(Class clazz);
}
public class FindMethodByAnnotation implements FindMethod
{
private final FindMethod findMethod;
public FindMethodByAnnotation(FindMethod findMethod)
{
this.findMethod = findMethod;
}
private Method findByAnnotation(Class clazz)
{
return getMethodByAnnotation(clazz);
}
public Method get(Class clazz)
{
Method r = null == findMethod ? null : findMethod.get(clazz);
return r == null ? findByAnnotation(clazz) : r;
}
}
public class FindMethodByOnlyMethod implements FindMethod
{
private final FindMethod findMethod;
public FindMethodByOnlyMethod(FindMethod findMethod)
{
this.findMethod = findMethod;
}
private Method findByOnlyMethod(Class clazz)
{
return getMethodOnlyMethod(clazz);
}
public Method get(Class clazz)
{
Method r = null == findMethod ? null : findMethod.get(clazz);
return r == null ? findByOnlyMethod(clazz) : r;
}
}
Usage is quite simple
FindMethod finder = new FindMethodByOnlyMethod(new FindMethodByAnnotation(null));
finder.get(clazz);
... I could switch that to try/catch logic, but that hardly makes it more readable.
Changing the signature of the get... methods so you can use try / catch would be a really bad idea. Exceptions are expensive and should only be used for "exceptional" conditions. And as you say, the code would be less readable.
What is bothering you is the repeating pattern used for flow control--and it should bother you--but there isn't too much to be done about it in Java.
I get really annoyed at repeated code & patterns like this, so for me it would probably be worth it to extract the repeated copy & paste control code and put it in it's own method:
public Method findMethod(Class clazz)
int i=0;
Method candidateMethod = null;
while(candidateMethod == null) {
switch(i++) {
case 0:
candidateMethod = getMethodByAnnotation(clazz);
break;
case 1:
candidateMethod = getMethodByBeingOnlyMethod(clazz);
break;
case 2:
candidateMethod = getMethodByBeingOnlySuitableMethod(clazz);
break;
default:
throw new NoSuitableMethodFoundException(clazz);
}
return clazz;
}
Which has the disadvantage of being unconventional and possibly more verbose, but the advantage of not having as much repeated code (less typos) and reads easier because of there being a little less clutter in the "Meat".
Besides, once the logic has been extracted into it's own class, verbose doesn't matter at all, it's clarity for reading/editing and for me this gives that (once you understand what the while loop is doing)
I do have this nasty desire to do this:
case 0: candidateMethod = getMethodByAnnotation(clazz); break;
case 1: candidateMethod = getMethodByBeingOnlyMethod(clazz); break;
case 2: candidateMethod = getMethodByBeingOnlySuitableMethod(clazz); break;
default: throw new NoSuitableMethodFoundException(clazz);
To highlight what's actually being done (in order), but in Java this is completely unacceptable--you'd actually find it common or preferred in some other languages.
PS. This would be downright elegant (damn I hate that word) in groovy:
actualMethod = getMethodByAnnotation(clazz) ?:
getMethodByBeingOnlyMethod(clazz) ?:
getMethodByBeingOnlySuitableMethod(clazz) ?:
throw new NoSuitableMethodFoundException(clazz) ;
The elvis operator rules. Note, the last line may not actually work, but it would be a trivial patch if it doesn't.
Let's say I'd like to perform the following command:
house.getFloor(0).getWall(WEST).getDoor().getDoorknob();
To avoid a NullPointerException, I'd have to do the following if:
if (house != null && house.getFloor(0) && house.getFloor(0).getWall(WEST) != null
&& house.getFloor(0).getWall(WEST).getDoor() != null) ...
Is there a way or an already existing Utils class that does this more elegantly, let's say something like the following?
checkForNull(house.getFloor(0).getWall(WEST).getDoor().getDoorknob());
In case you can't avoid breaking Law of Demeter (LoD) as stated in the chosen answer, and with Java 8 introducing Optional, it would be probably the best practice to handle nulls in chains of gets such as yours.
The Optional type will enable you to pipe multiple map operations (which contain get calls) in a row. Null checks are automatically handled under the hood.
For example, when the objects aren't initialized, no print() will be made and no Exceptions will be thrown. It all we be handled gently under the hood. When objects are initialized, a print will be made.
System.out.println("----- Not Initialized! -----");
Optional.ofNullable(new Outer())
.map(out -> out.getNested())
.map(nest -> nest.getInner())
.map(in -> in.getFoo())
.ifPresent(foo -> System.out.println("foo: " + foo)); //no print
System.out.println("----- Let's Initialize! -----");
Optional.ofNullable(new OuterInit())
.map(out -> out.getNestedInit())
.map(nest -> nest.getInnerInit())
.map(in -> in.getFoo())
.ifPresent(foo -> System.out.println("foo: " + foo)); //will print!
class Outer {
Nested nested;
Nested getNested() {
return nested;
}
}
class Nested {
Inner inner;
Inner getInner() {
return inner;
}
}
class Inner {
String foo = "yeah!";
String getFoo() {
return foo;
}
}
class OuterInit {
NestedInit nested = new NestedInit();
NestedInit getNestedInit() {
return nested;
}
}
class NestedInit {
InnerInit inner = new InnerInit();
InnerInit getInnerInit() {
return inner;
}
}
class InnerInit {
String foo = "yeah!";
String getFoo() {
return foo;
}
}
So, with your getters chain it will look like this:
Optional.ofNullable(house)
.map(house -> house.getFloor(0))
.map(floorZero -> floorZero.getWall(WEST))
.map(wallWest -> wallWest.getDoor())
.map(door -> wallWest.getDoor())
The return of it will be something like Optional<Door> which will allow you much safer work without worrying of null exceptions.
In order to check a chain of gets for null you may need to call your code from a closure. The closure call code will look like this:
public static <T> T opt(Supplier<T> statement) {
try {
return statement.get();
} catch (NullPointerException exc) {
return null;
}
}
And you call it using the following syntax:
Doorknob knob = opt(() -> house.getFloor(0).getWall(WEST).getDoor().getDoorknob());
This code is also type safe and in general works as intended:
Returns an actual value of the specified type if all the objects in the chain are not null.
Returns null if any of the objects in the chain are null.
You may place opt method into shared util class and use it everywhere in your application.
The best way would be to avoid the chain. If you aren't familiar with the Law of Demeter (LoD), in my opinion you should. You've given a perfect example of a message chain that is overly intimate with classes that it has no business knowing anything about.
Law of Demeter: http://en.wikipedia.org/wiki/Law_of_Demeter
You could of course simply wrap the whole expression up in a try-catch block, but that's a bad idea. Something cleaner is the Null object pattern. With that, if your house doesn't have floor 0, it just returns a Floor that acts like a regular Floor, but has no real content; Floors, when asked for Walls they don't have, return similar "Null" Walls, etc, down the line.
Make sure things that can't logically be null are not. For example - a house always has a West wall. In order to avoid such exceptions in state, you can have methods to check whether the state you expect is present:
if (wall.hasDoor()) {
wall.getDoor().etc();
}
This is essentially a null-check, but might not always be.
The point is that you should do something in case you have a null. For example - return or throw an IllegalStateException
And what you shouldn't do - don't catch NullPointerException. Runtime exceptions are not for catching - it is not expected that you can recover from them, nor it is a good practice to rely on exceptions for the logic flow. Imagine that you actually don't expect something to be null, and you catch (and log) a NullPointerException. This will not be very useful information, since many things can be null at that point.
Better solution for me is to use java.util.Optional.map(..) to chain these checks : https://stackoverflow.com/a/67216752/1796826
There is no checkForNull method that you can write that will facilitate this (that's simply not how method invokation and argument evaluation works in Java).
You can break down the chained statements into multiple statements, checking at every step. However, perhaps a better solution is to not have these methods return null in the first place. There is something called the Null Object Pattern that you may want to use instead.
Related questions
How to avoid != null statements in Java?
You could potentially have a generic method like below:
public static <T> void ifPresentThen(final Supplier<T> supplier, final Consumer<T> consumer) {
T value;
try {
value = supplier.get();
} catch (NullPointerException e) {
// Don't consume "then"
return;
}
consumer.accept(value);
}
So now you would be able to do
ifPresentThen(
() -> house.getFloor(0).getWall(WEST).getDoor().getDoorknob(),
doorKnob -> doSomething());
implementing nullPointer try/catch with a Supplier you can send it all chain of get
public static <T> T getValue(Supplier<T> getFunction, T defaultValue) {
try {
return getFunction.get();
} catch (NullPointerException ex) {
return defaultValue;
}
}
and then call it in this way.
ObjectHelper.getValue(() -> object1.getObject2().getObject3().getObject4()));
Very old question, but still adding my suggestion:
I would suggest instead of getting the DoorKnob from deep within the House in one method call chain, you should try to let the DoorKnob be provided to this class from the calling code, or by creating a central lookup facility specifically for this purpose (e.g. a DoorKnob service)
Simplified example of design with loose coupling:
class Architect {
FloorContractor floorContractor;
void build(House house) {
for(Floor floor: house.getFloors()) {
floorContractor.build(floor);
}
}
}
class FloorContractor {
DoorMaker doorMaker;
void build(Floor floor) {
for(Wall wall: floor.getWalls()) {
if (wall.hasDoor()) {
doorMaker.build(wall.getDoor());
}
}
}
}
class DoorMaker {
Tool tool;
void build(Door door) {
tool.build(door.getFrame());
tool.build(door.getHinges());
tool.build(door.getDoorKnob());
}
}
// Example
LazyObject.from(curr).apply(A.class, A::getB).apply(B.class, B::getC).apply(C.class, C::getD).to(String.class);
// LazyObject.java
public class LazyObject {
private Object value;
private LazyObject(Object object) {
this.value = object;
}
public <F, T> LazyObject apply(Class<F> type, Function<F, T> func) {
Object v = value;
if (type.isInstance(v)) {
value = func.apply(type.cast(v));
} else {
value = null; // dead here
}
return this;
}
public <T> void accept(Class<T> type, Consumer<T> consumer) {
Object v = value;
if (type.isInstance(v)) {
consumer.accept(type.cast(v));
}
}
public <T> T to(Class<T> type) {
Object v = value;
if (type.isInstance(v)) {
return type.cast(v);
}
return null;
}
public static LazyObject from(Object object) {
return new LazyObject(object);
}
}