-1

A program creates a JDialog panel with multiple tabs. One of the tabs has several tables. A JTable has adjustable column width. This tab is generated under different conditions. Sometimes from the state tab is null, sometimes tab exists, but the table is null. Sometimes user haven't resized the column yet.

I am looking for a method to save the columnWidth value if user resized the column. Checking for null seems bulky in this situation:

jpanel.tab.table.width

the best method I can find is:

if( jpanel!=null && 
    jpanel.jtab!=null &&
    jpanel.jtab.jtable!=null && ...

Is there a better way to do this null check?


I saw this question:
is there a Java equivalent to null coalescing operator (??) in C#?

It doesn't list a solution and is quite old (Java 6-7 time). I was hoping this feature was added in later releases.

Community
  • 1
  • 1
sixtytrees
  • 978
  • 1
  • 9
  • 21
  • I mean that if my `item` is burred 6-10 levels deep this check doesn't look right. Feels like repeating same code many times, when you should use a `for` loop – sixtytrees Aug 05 '16 at 20:16
  • http://stackoverflow.com/questions/5223044/is-there-a-java-equivalent-to-null-coalescing-operator-in-c http://stackoverflow.com/questions/2768054/how-to-get-the-first-non-null-value-in-java http://stackoverflow.com/questions/271526/avoiding-null-statements etc. tl;dr either leave it at that, or fix your logic, not implementation (use `Optional` etc.) –  Aug 05 '16 at 20:17
  • Are you sure you need to check all the levels for null? If null is not a valid value for many of those fields, instead of checking, just let it throw a NRP exception. – sstan Aug 05 '16 at 20:23
  • One more question: what does your code do if any of the fields is null? Can the code continue running correctly? Or is that considered an unexpected situation (a bug in the code)? – sstan Aug 05 '16 at 20:48
  • @sstan I've just edited the question. It creates a JTable. I try to see if user resized a column. I know about `columnMarginChanged(ChangeEvent e)` but I wanted to know what one should do in such situation. – sixtytrees Aug 05 '16 at 20:52
  • 1
    I know I won't be able to convince you otherwise, but for what it's worth, I would stick with the "bulky" syntax until Java provides syntactic sugar to shorten it. Catching exceptions as part of a "normal" null-check to save a few keystrokes is not a good trade off as it's potentially very inefficient at run time. It also makes for a very annoying debugging experience in an IDE because the code will constantly break on the exception throw. And using reflection is also bad, because it's not efficient, and your code can easily break if you ever rename/refactor your fields. – sstan Aug 05 '16 at 20:58
  • 1
    @sstan Actually, you convinced me now. Earlier answers say "you can't do it", while your comment is "you can, but this is not safe and is a bad practice - it is better to write a long check then get in a habit of throwing away exceptions". This should be an accepted answer... – sixtytrees Aug 05 '16 at 21:07

3 Answers3

0

There's no way to do exactly what you want. However, you can just throw everything into a try statement:

try { 
    myItem = bundle.category.subcategory.item;
} 
catch(NullpointerException ignored) {}

Note that this looks very hacked, and it's rather poor coding practice. Your current solution is probably the best approach in terms of clarity.


Edit: I tried posting another Anwser but the button is greyed out, so I'll put it here:

Feels like repeating same code many times, when you should use a for loop

You can indeed use a for loop, but that will invovle Reflection and much boilerplate code. Imagine something like this:

static boolean checkDeepNull(Object root, String... attributes) throws NoSuchFieldException, IllegalAccessException {
    Object currentAttribute = root;
    for(int attr = 0; currentAttribute != null && attr < attributes.length; attr++){
        Field nextField = currentAttribute.getClass().getField(attributes[attr]);
        Object nextAttribute = nextField.get(current);
        if(nextAttribute == null) return false;
        currentAttribute = nextAttribute;
    }
    return true;
}

How to use it: if(checkDeepNull(bundle, "category", "subcategory", "item"))

Johannes
  • 577
  • 7
  • 13
  • Your solution didn't match the question requirements – FallAndLearn Aug 05 '16 at 20:17
  • 2
    No, OP, don't do this. :( – sstan Aug 05 '16 at 20:25
  • This solution appeared earlier and I don't see any problem with it. Silent downvotes are nasty. – sixtytrees Aug 05 '16 at 20:26
  • 1
    [Why not use exceptions as regular flow of control?](http://stackoverflow.com/questions/729379/why-not-use-exceptions-as-regular-flow-of-control) – sstan Aug 05 '16 at 20:27
  • @sstan As I understand Johannes was downvoted for having too small of a reputation, right? – sixtytrees Aug 05 '16 at 20:28
  • Nothing todo with reputation. It just doesn't do a lot of useful stuff and is very bad practice. You gonna make your life hell if you need to debug this. Ignoring an exception is handy in school or a small programm that you haven't finished building yet, but after that it's a pain in the ass for debugging the real exceptions. – HopefullyHelpful Aug 05 '16 at 20:29
  • I actually said that it's rather hacked. It's not a bad answer per se. – Johannes Aug 05 '16 at 20:35
  • Also it's expensive as hell. Constructing exceptions for control flow might be smooth looking on the outside but is slow as hell. It's not a pattern you should adapt if you care about performance at all. – HopefullyHelpful Aug 05 '16 at 20:35
  • 1
    I understand that and we all appreciate the effort. Downvotes are about what we want future people to adapt as a practice or see as an answer, not about your effort or a per se bad answer. No answer here is a good practice so none really got upvoted. – HopefullyHelpful Aug 05 '16 at 20:37
  • I've edited my answer. – Johannes Aug 05 '16 at 20:37
  • I can afford an exception in code that creates a JPanel. Good call about reflection. – sixtytrees Aug 05 '16 at 20:47
0

You could have an interface which determines nullability:

public interface Nullability {
    public boolean hasNulls();
}

And then simply have the parent call any children like so:

public boolean hasNulls() {
    return this.bundle == null || bundle.hasNulls();
}

//in bundle
public boolean hasNulls() {
    return this.category == null || category.hasNulls();
}

Regardless, if you have to nullcheck everything, you're going to be doing a lot of boilerplate code if you don't provide a means of iteration. That's what you should really focus on.

On a personal level, I disagree heavily with exposing fields like that. It's a very easy way to lead to more headaches and errors in design.

Rogue
  • 9,871
  • 4
  • 37
  • 66
  • How would this idea work if category had *two* fields, a valid non-null subcategory, and a null foo? – user949300 Aug 05 '16 at 20:42
  • you would check #hasNulls on multiple nullables. Again, this isn't an ideal solution, merely an answer to OP's question. In reality there's more of a need for a design change – Rogue Aug 06 '16 at 01:06
0

The short answer is no.

Can you redesign bundle so that it is always fully constructed? I.e., if bundle != null, then category, subcategory and item always exist? This could also help with concurrency issues. Basically, if nulls give you problems, where possible, don't allow these fields to be null.

Another option is the Null Object Pattern. Basically, you have a "default" implementation of Bundle which always return getCategory() that always returns a value for getSubcategory(), but ultimately the call to getItem() returns null or something to indicate "nothing". This is a great pattern but requires some work.

I hesitate to suggest it, but it is rare for any of the items to be null, at some point it may be faster and clearer to just catch the NPE, but this style should really be avoided. And it is a definite code smell that your design is poor. Avoid it if at all possible.

try {
  return foo.bar.bap.zaz.blah.blah;
}
catch (NullPointerException ignored) {
  return null;
}
user949300
  • 14,622
  • 6
  • 30
  • 61