1

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!

Apahdos
  • 97
  • 7
  • Instead of returning `null` you should throw a (runtime) exception. Returning `null` forces you to clutter your code with *`null` checks* which is even more ugly. – Timothy Truckle May 05 '17 at 15:42
  • Maybe calling an abstract method in a constructor is an unfortunate choice. See also [this](http://stackoverflow.com/questions/15327417/is-it-ok-to-call-abstract-method-from-constructor-in-java) SO question. – Jeroen Heier May 05 '17 at 19:58
  • @Timothy Using exceptions would force me to clutter my code with try/catches, which in my opinion looks even worse. I don't want to have all variables skipped, when the first one gets the nullpointer. – Apahdos May 05 '17 at 20:20
  • @Jeroen I see your point and I see the point from the post. I can't quite remember why I made the abstract method be called from the constructor right now, not seeing my code, but it had some reason when I startet writing the program. I also had a similar problem to the posts anti-example where I had my variables initialized with "null" where I declared them. It turned out, that the variables, that were set to something other than null in the child class, still printed null, because the same variables were initialized again (with null) in the super class. But that was easily fixed by removing – Apahdos May 05 '17 at 20:27
  • said outer-constructor initializations. So they weren't overriden anymore. So as I said, making that abstract method had some reason, I just can't remember it rn. But I will definitly watch out for that in my next program/update of this one, and try to prevent it. Thank you very much for the advise! But how my code is written now, it's very easy to add new datastructures for the coder and there is not much that can be done wrong. In my opinion it's anyway better to initialize variables inside and not outside of the constructor/methods inside the constructor. But still. Thanks! – Apahdos May 05 '17 at 20:32
  • *"Using exceptions would force me to clutter my code with try/catches"* No, it would not. You only place `try`/`catch` where you can do something meaningful which usually is way up in the call stack, not after each and every method call that might return a `null` or at the beginning of every method having Parameters potentially being `null`. – Timothy Truckle May 05 '17 at 21:07
  • Yes, but when having the null-catch way up in the call stack (which, I agree, is the usual usage of try/catches, letting it bubble up to for example the main method). But I want to have each variable skipped individually when the getChild(..) returns null. Using try/catch the "usual" way, would make the rest of the variables to not be initialized anymore. Amd that would end up in lack of information, which should have been read from the xml file. Since the variables would get initialized untill null is found. But I need them to be initialized even after null has been found. But still thanks! – Apahdos May 06 '17 at 21:16

2 Answers2

1

An alternative to constructors returning null is factory methods returning null.

Although you cannot write

class SomeClass {
    public SomeClass(Node node) {
        if (node.isEmpty()) return null; // Does not compile
        ...
    }
}

you can certainly write this:

class SomeClass {
    private SomeClass(Node node) {
        // Self-check: this should never happen
        if (node.isEmpty()) {
            throw new IllegalArgumentException("node");
        }
        ...
    }
    public static SomeClass makeFromNode(Node node) {
        if (node.isEmpty()) {
            return null;
        }
        return new SomeClass(node);
    }
}

Replacing constructor calls with calls to makeFromNode will let you process situations when the node is null in a simple and uniform way.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • 1
    Ah this actually is a nice way of doing it. It will be quite an effort to change all of my calls, but it will actually change nothing regarding performance, and seems to need (at least I think so) the least amount of effort changing the calls, since I have a top-class where I can add the static function. Thank you very much! Learned something new again ^^ – Apahdos May 05 '17 at 15:39
  • Ah...wait. It might not be that easy. I have a lot of different Datastructures, which are called by this. They all have different getter. So I would need to create the method for every single class manually, since (in my example of the original post) Superclass has no functions, but Bar would have a getValue() method for example...Am I missing something here, or won't I be able to have your method written into a super-class, so I won't need to make it for every class manually? – Apahdos May 05 '17 at 15:47
  • @Apahdos Static methods are not overridable, so the method in the base class would end up calling the constructor from the base class, which is not what you want. If you do not want to go through all classes and make this modification, you could make a separate `MyClassFactory` class with static methods for each subclass that you wish to create. However, you do need one method per class. – Sergey Kalinichenko May 05 '17 at 15:50
  • Creating a factory for every Class is probably code pollution, since it doesn't introduce any real benefit. – manf May 05 '17 at 15:55
  • Hmm. But static methods are still inherited, aren't they? So my problem would now be, that the return value of the static method needs to be changed for each class, it would be used in. So for Foo, it would return an Object of type Foo. In Bar it would return an Object of type Bar etc. So shouldn't I be able to make an generic method out of it and have it return an new Object of type ? Or would there be something else interfering with this idea? My brain is kinda exhausted by now. But it seems as an solution for me right now, doesn't it? – Apahdos May 05 '17 at 16:03
0

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);
}
manf
  • 328
  • 4
  • 14
  • hmm. I've never worked with such a wrap method so far. What exactly is the Function<> class doing? Won't I end up writing a new Function for every time I'm using wrap(...) by passing a new local class of Function<..>?. Because Function<...> seems to be an interface. Also (not quite knowing what you mean with the hasElement() function) I haven't added such a thing, because I thought it might cost too much performance and programming effort to have the null check every time I initialize ... – Apahdos May 05 '17 at 16:13
  • ...a variable. As I said, having over 50 plus different datastructures with each having up to 10 different variables (some of them beeing Lists), it'd become quite exhausting to to use "if(hasElement(...){...}" every time. – Apahdos May 05 '17 at 16:13
  • I named the method wrap due to it's functionality. Wrapping the given Element in any other Type (T). You are not writing any new function due to the fact, that you can pass the constructor of the Class (Bar::new). And hasElement should have been implemented within jdom so you could've simplified the assignment with element.hasChild("foo") ? new Baz(element.getChild("foo")) : null. This is nothing you could've done. – manf May 05 '17 at 16:21
  • Well. I'm off from work now. I will check your answer out the next time I'm going to work. Thank you anyway! Already helped me a lot! – Apahdos May 05 '17 at 17:52
  • And regarding the hasElement(). jdom might have something like that. But probably it would not be better in performance as if I'd save the returned Element from element.getChild(...) locally and check if it's null. If jdom has a hasChild function, it would probably use it itself in the getChild(..) function already. But will check it out aswell, as soon as I go to work – Apahdos May 05 '17 at 17:56