Search code examples
javaperformancejdom

Alternative to constructor returning null


I'm creating a big project for my company at the moment, with a lot of datastructures and shizle. And I am looking for a good solution for my following problem:

Since Java has no possibility to have a constructor return null (at least my research said that) I need a good alternative to it.

Let's say I have the following code (Just an example. The actual project is more complex):

public abstract class SuperClass
{
    public SuperClass(Element element)
    {
        if(element != null)
            readElement(element);
    }

    public abstract void readElement(Element element);
}

public class Foo extends SuperClass
{
    private Bar bar1;
    private Bar bar2;
    private Bar bar3;
    //...

    public Foo(Element element)
    {
        super(element);
    }

    @Override
    public void readElement(Element element)
    {
        this.bar1 = new Bar(element.getChild("bar1"));
        this.bar2 = new Bar(element.getChild("bar2"));
        this.bar3 = new Bar(element.getChild("bar3"));
        //...
    }
}

public class Bar extends SuperClass
{
    private String value;

    public Bar(Element element)
    {
        super(element);
    }

    @Override
    public void readElement(Element element)
    {
        this.value = element.getChildText("value");
    }
}

the Element.getChild(String name) function is from jdom2 (XML-Parser), used for reading through xml Files. It can and will return null, if a child with given name was not found. I've written my project on basis of this example, stupidly thinking, that if named function returns null, the variable (here bar1 for example) would be null aswell. But since named function is wrapped with a "new Bar(...)" it won't be null, instead it will be an empty object. But I want and need the "empty" variables to be null, so I can skip those easily when iterating through all Datastructures in my Project. I would save the returned Object from the "getChild(...)" function into a local variable "lElement" and then have something like:

if(lElement != null)
    bar1 = lElement;

but I have over 50 different Datastructures like those in my example and more than enough variables in them, that are initialized by the "readElement(...)" function. This idea would take far too much editing and probably even a fair amount of performance. Also it seems somewhat... "ugly" for me. At least for this amount of variables. So I need something, which has no effect on the performance whatsoever and is as easy, as having the constructor return null. I'd prefer not to change too much of the code in these functions. I also had the idea of letting the Datastructure set itself to null if "Element element" equals null, but after a quick research, this idea was erased right away ^^. An object deleting himself won't work and is not logical anyway.

So basicly I could fix this problem myself. But probably it would not be the most efficient way. Both in effort of editing the code and in code-performance. Therefore I am asking you guys, how you would solve this problem. Having the backthought of not just two simple Datastructures like in my example, but rather 50 classes+ using this system.

I hope you can help me, and I apologize for any bad english. I'm from Germany ^^. I've been coding in Java for over 5 years by now ("professionally" since last year), so it's a bit embarassing for me, having not thought of this problem earlier. But now it is too late to get back to something totally different.

Thank you in advance!


Solution

  • Constructors define the initialization of an arbitrary object. Thus they could never return values.

    I would argue that the lack of a hasElement method is a major design flaw, but nevertheless if you insist on returning null, you can.

    In any case you should leverage generics and Method references (>= Java 8).

    You could use the wrap method in the code example for your given requirements (Using inheritance to allow sub classes to read children easier).

    public void readElement(Element element) {
        this.bar1 = wrap(element.getChild("bar1"), Bar::new);
        this.bar2 = wrap(element.getChild("bar1"), Bar::new);
        this.bar3 = wrap(element.getChild("bar1"), Bar::new);
    }
    
    protected <T> T wrap(Element element, Function<Element, T> elem) {
        if (element == null) {
            return null; // Not a good value
        }
        return elem.apply(element);
    }