4

I have the following simple code to simulate cat hunting:

import java.util.Arrays;
import java.util.LinkedList;

public class HuntigSaeson {
    int hunger = 4;
    int level = 3;
    LinkedList<String> cats = new LinkedList<String>(Arrays.asList(
        "1.Ginger",
        "3.Porkchops",
        "2.Muffin",
        "2.Max",
        "1.Carrot",
        "2.Puffy",
        "1.Fatty"
    ));

    void hunt() {
        Integer catLevel = null;
        do {
            if (catLevel != null)
              rest();
            catLevel = new Integer(findCat().split("\\.")[0]);
            huntCat(catLevel);
            if (hunger > 5) throw new RuntimeException("x_x");
        } while (hunger > 0);
        System.out.println("^_^");
    }

    void rest() { hunger += 1; }

    String findCat() {
        hunger += 1;
        String c = cats.pop();
        System.out.println("found " + c);
        return c;
    }

    private void huntCat(int catLevel) {
        hunger += 1;
        if (catLevel < level) {
            System.out.println("chomp chomp chomp");
            hunger -= 4;
        }
    }

    public static void main(String[] args) { new HuntigSaeson().hunt(); }
}

It produces this output:

found 1.Ginger
chomp chomp chomp
found 3.Porkchops
found 2.Muffin
chomp chomp chomp
found 2.Max
chomp chomp chomp
found 1.Carrot
chomp chomp chomp
found 2.Puffy
chomp chomp chomp
found 1.Fatty
chomp chomp chomp
^_^

The intent of the null comparison line is that I don't want to rest before hunting the first cat. Netbeans highlights the line, saying I should remove it.

netbeans highlighting

So I do, by changing

            if (catLevel != null)
              rest();

to

          rest();

But now I die:

found 1.Ginger
chomp chomp chomp
found 3.Porkchops
Exception in thread "main" java.lang.RuntimeException: x_x
    at HuntigSaeson.hunt(HuntigSaeson.java:24)
    at HuntigSaeson.main(HuntigSaeson.java:46)

Why? How can I fix this?

Charles
  • 50,943
  • 13
  • 104
  • 142
Dog
  • 7,707
  • 8
  • 40
  • 74

5 Answers5

4

Why does my application break when I remove the null check?

The first thing to note is this: The Netbeans warning is wrong.

By removing the null check around rest(); you are changing the flow of the first run of your do while loop. Importantly, you are allowing rest() to be called. The net effect of this is that hunger is now larger than it normally would be had you left the null check in place.

What's now happening is this:

  • First loop iteration begins: hunger = 4, level = 3
  • rest() is called: hunger increments to 5.
  • findCat() is called: hunger increments to 6, "1.Ginger" is returned.
  • huntCat(1) is called: hunger increments to 7.
  • 1 < 3 (catLevel < level) evaluates to true, causing hunger to be decremented by 4 (so we're now at 3).
  • hunger is not greater than 5, so continue to the next iteration.
  • Second loop iteration begins: hunger = 3, level = 3
  • rest() is called, hunger increments to 4.
  • findCat() is called, hunger increments to 5, "3.Porkchops" is returned.
  • huntCat(3) is called, hunger increments to 6
  • 3 < 3 (catLevel < level) evaluates to false, hunger does not get decremented.
  • hunger is greater than 5, so RuntimeException("x_x") is thrown.

How can I fix this?

Well, given that the Netbeans warning is wrong (because catLevel definitely is null in the first iteration), the simplest solution is just to reinstate your null check and ignore the warning.

If you wish, you can disable the warning by clicking the lightbulb next to the warning on the left side, browsing the menus, and choosing "Disable warning". Though personally I would rather put up with one aggravating yellow underline if it lead to better quality code in the long run.

Alternatively, increase level to 4, or decrease hunger to 3, or change your if statement to check if hunger > 6 instead.

Community
  • 1
  • 1
JonK
  • 2,097
  • 2
  • 25
  • 36
1

For what it's worth, I did not see that warning when I tried your code with:

Product Version: NetBeans IDE 8.0 (Build 201403101706)
Java: 1.8.0; Java HotSpot(TM) 64-Bit Server VM 25.0-b70
Runtime: Java(TM) SE Runtime Environment 1.8.0-b132
System: Windows 8 version 6.2 running on amd64; Cp1252; en_US (nb)

So I suspect it was a false-positive warning in NetBeans that has since been fixed.

That said, you can achieve the same output without the null check by changing the initial value of hunger to 3, e.g.

public class HuntigSaeson {
    int hunger = 3;

    ...
    void hunt() {
        Integer catLevel;
        do {
            rest();
            catLevel = new Integer(findCat().split("\\.")[0]);
            huntCat(catLevel);
            if (hunger > 5) throw new RuntimeException("x_x");
        } while (hunger > 0);
        System.out.println("^_^");
    }
    ...
}
Nathan
  • 10,593
  • 10
  • 63
  • 87
0

As a simple answer : the Netbeans warning is wrong. Netbeans says the expression is never null, although it is null in first iteration. Simply ignore the Warning. Not all warnings are intended to be treated. That's why they are configurable in Netbeans itself to be off/on.

I don't recommend to disable it as :

  • It should have been resolved now with earlier versions of Netbeans.

  • It will not disable other real "never null expressions"

javadev
  • 1,639
  • 2
  • 17
  • 35
0

Try the following:

    void hunt() {
    try {
        while (hunger > 0) {
            huntCat(new Integer(findCat().split("\\.")[0]));
            if (hunger > 5)
                throw new RuntimeException("x_x");
            rest();
        }
    } catch (NoSuchElementException e) {
    }
    System.out.println("^_^");
}
phn
  • 1,720
  • 1
  • 14
  • 10
-2

Error message NetBeans is reporting is actually reverse of what its intended for :)

Your if condition will always be null, so rest() will never be executed and hence hunger will stay at 4.

However when you remove the if condition reset() is called and the hunger value increments to 5 and so later on your code crashes as you just throw the exception if it's value is greater than 5 which will now be more than 5 due to calls to other methods in lines above.

What NetBeans is saying could be wrong (expression is never null), it should say (expression is always null) instead.

Fix the code logic ..

ask-dev
  • 606
  • 2
  • 13
  • 30
  • No, please re-examine the code as hunger is not always null. It's only initially null (kind of kludgy code). – Hovercraft Full Of Eels Mar 30 '14 at 22:28
  • 2
    if (catLevel != null) that's always null because of the initialization 2 rows above like Integer catLevel = null; – ask-dev Mar 30 '14 at 22:31
  • 2
    But it's in a do-while loop. catLevel is set on the next line, the line below the if block. If what you're saying is true, why does rest get called when you run the program? I agree that catLevel is ***initially*** null, but only when the while loop runs the first time. After that it is always non-null. Again, re-read the code, or even better, put a SOP in the rest method and see that it in fact prints out. – Hovercraft Full Of Eels Mar 30 '14 at 22:41
  • My comment above is based on the warning Netbeans is showing and whether Netbeans algorithm to show such warning can't pick this up, the very reason to show this at first place is because of the first iteration and in this case if condition will always be false and null check is needless. A better way to code this would be to put the rest() method at the end of the loop construct and still you won't need an if condition. You just want to run rest() after the first iteration that's it. – ask-dev Mar 30 '14 at 22:52
  • When he puts it at the end, the behavior changes since now the exception is thrown. This is why I want the OP to post his actual requirements and desired code behaviors. Without this, I don't think that we really know what he needs. But again, your answer is still wrong as the expression is not always null. Again, it is only null when the do-while loop starts. – Hovercraft Full Of Eels Mar 30 '14 at 22:54
  • He needs to fix the code logic (Last line in my answer). Warning shown is because of the Netbeans algorithm as it just can't identify the do while loop construct in this context. Putting rest() at the end of the loop will not cause the app to crash (poster posted an output that with this 'if condition' code works that means on next iteration rest() will always be executed). So to remove warning, remove the if and put the rest() method at the end of the loop. That fixes the code logic in hand as reported. – ask-dev Mar 30 '14 at 23:05
  • Just add more cats to the list, I didn't get around to handling end of list. – Dog Mar 30 '14 at 23:14
  • @Dog can you please put the reset() at the end of the loop and remove the if condition altogether. See your code works now as expected without a warning? – ask-dev Mar 30 '14 at 23:17
  • The idea is to hunt cats until no longer hungry (`hunger <= 0`). If `hunger` goes above 5, game over. If the hunger reaches equilibrium (infinite loop), so be it, the dog is stuck in hell instead of dying. – Dog Mar 30 '14 at 23:18
  • @Dog I would suggest to do as I suggested and run the code. Report if you see any other issue with code logic afterwards. For the question you posted originally the current suggestion is good enough. – ask-dev Mar 31 '14 at 08:04
  • @Dog Just checked your code in NetBeans 8 and it doesn't show any warning for the null check any more. Seems like they've fixed this. On the other hand as per your requirements you don't want to call rest() unless hunt has started. A possible implementation (if you want to change your current implementation) would be to declare a state variable in your class private boolean huntStarted = false; and then use in the if condition if(huntStarted) rest(); else huntStarted = true; – ask-dev Apr 15 '14 at 07:31