Java Forum / General / January 2006
NullPointerException
elingtse@gmail.com - 27 Dec 2005 03:43 GMT Hi all,
I am a newbie of Java and am working on my homework. I got an error message "NullPointerException" after compilation. I know this means values cannot be passed to array but it seems not my case because it can generate a correct output on screen. The program terminate abnormally after this error message. Could anyone help to point out what I did wrong, thanks a lot.
et
Compilation Output : ------------------------------ Accounts of Amy 1234 : $1000.0 1122 : $5000.0 Exception in thread "main" java.lang.NullPointerException at Person.displayAccount(Person.java:29) at TestPerson.main(TestPerson.java:23)
Person Class -------------------- public class Person {
//attributes private String name; private Account[] account = new Account[10];
//constructor public Person(String name, Account[] account){ this.name = name; this.account = account; }
//create getter for name public String getName(){ return name; }
//create setter for name public void setName(String setName){ name = setName; }
//create displayAccount method public void displayAccount(){ System.out.println("Accounts of " + name); for(int i=0; i<account.length; i++){ System.out.println(account[i].getNumber() +" : $"+ account[i].getBalance()); } }
//create lowBalanceAccounts method public String lowBalanceAccounts(double lowBalance){ String msg = "No account's balance is lower than Low balance"; for(int i=0; i<account.length; i++){ if(account[i].getBalance() < lowBalance) return account[i].getNumber(); } return msg; }
//create highestBalanceAccount Method public String highestBalanceAccount(){ double hBal = 0; String acNo = null; for(int i=0; i<account.length; i++){ if(account[i].getBalance() > hBal){ hBal = account[i].getBalance(); acNo = account[i].getNumber(); } } return acNo; }
}
TestPerson Class --------------------------
//The class of TestPerson creates an environment //for testing Person object
public class TestPerson {
public static void main(String Arg[]) {
//Attribute int accountCount = 0; Account[] account = new Account[10];
//create account and person objects for Amy Account account1 = new Account("1234", 1000); Account account2 = new Account("1122", 5000); account[0] = account1; account[1] = account2; Person amy = new Person("Amy", account);
//System.exit(-1);
//call displayAccounts method amy.displayAccount();
//call lowBalance accounts System.out.println("Low balance account(s) : "+amy.lowBalanceAccounts(2000));
//call highestBalanceAccount System.out.println("The highest account is : "+amy.highestBalanceAccount()); } }
Andrew Thompson - 27 Dec 2005 04:14 GMT > Hi all, > > I am a newbie of Java and am working on my homework. The best group for people learning Java is <http://www.physci.org/codes/javafaq.jsp#cljh>
>..I got an error > message "NullPointerException" after compilation. That would be 'at Runtime'.
>..I know this means > values cannot be passed to array but it seems not my case because it [quoted text clipped - 5 lines] > > Compilation Output : This is 'Runtime Output:'
> ------------------------------ > Accounts of Amy > 1234 : $1000.0 > 1122 : $5000.0 Yes, you created (instantiated) two accounts in the TestPerson main..
> Exception in thread "main" java.lang.NullPointerException > at Person.displayAccount(Person.java:29) ..but your array has a size of 10 and 8 of those array references point to nothing, or 'null', so if you iterate them all, you should expect 8 NPE's (unless you check each for null).
> at TestPerson.main(TestPerson.java:23) > > Person Class > -------------------- > public class Person { ...
And as an aside, this is not compilable code (it is missing 'Account' class, for example, and I had to correct problems caused by line wrap before I discovered that), and you will generally get more help if you post the miminal example that displays the problem. More tips here.. <http://www.physci.org/codes/sscce.jsp>
HTH
 Signature Andrew Thompson physci, javasaver, 1point1c, lensescapes - athompson.info/andrew
elingtse@gmail.com - 27 Dec 2005 04:38 GMT Hi Andrew,
Thanks for your help. I got the problem now though I still don't know how to fix it. I guess I may use if(account[i] != null) to check it first.
Noted the sscce and will try to display example better next time. Sorry for missing Account class, I thought the NPE is not from Account class so no need to display. (I should stand at the position of reader).
et
David Wahler - 27 Dec 2005 04:48 GMT > Hi all, > [quoted text clipped - 4 lines] > abnormally after this error message. Could anyone help to point out > what I did wrong, thanks a lot. [snip]
> Exception in thread "main" java.lang.NullPointerException > at Person.displayAccount(Person.java:29) > at TestPerson.main(TestPerson.java:23) [snip]
> public class TestPerson { > [quoted text clipped - 3 lines] > int accountCount = 0; > Account[] account = new Account[10]; OK -- account is an array of 10 references to Account, all of which are null.
> //create account and person objects for Amy > Account account1 = new Account("1234", 1000); > Account account2 = new Account("1122", 5000); > account[0] = account1; > account[1] = account2; > Person amy = new Person("Amy", account); [snip]
account is now equal to {account1,account2,null,null,null,null,null,null,null,null}. As soon as you try to call a method of one of those null references, you'll get an exception. Try using "Account[] account = new Account[2]" instead.
-- David
elingtse@gmail.com - 27 Dec 2005 05:43 GMT Thanks, David. It is fixed now.
ricky.clarkson@gmail.com - 29 Dec 2005 14:29 GMT For the reasons David Wahler showed, it might be better in general to avoid the new Type[int] syntax, where Type is non-primitive, to prevent NullPointerExceptions, as per:
http://en.wikibooks.org/wiki/Java_Programming/Preventing_NullPointerException
Googmeister - 29 Dec 2005 14:52 GMT Also, as a style issue, note that it is pointness to initialize the instance variable account
private Account[] account = new Account[10];
since you reassign its value in the only constructor.
Chris Smith - 29 Dec 2005 16:50 GMT > For the reasons David Wahler showed, it might be better in general to > avoid the new Type[int] syntax, where Type is non-primitive, to prevent > NullPointerExceptions, as per: Okay, this is silly. You seem to be here on a mission to post links to that that ill-conceived article as many times as you can find excuses for it.
So tell me: how do you create an array, then, if you don't know the length at compile-time?
 Signature www.designacourse.com The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer MindIQ Corporation
Roedy Green - 29 Dec 2005 17:57 GMT On 29 Dec 2005 06:29:19 -0800, "ricky.clarkson@gmail.com" <ricky.clarkson@gmail.com> wrote, quoted or indirectly quoted someone who said :
>http://en.wikibooks.org/wiki/Java_Programming/Preventing_NullPointerException The cure sounds worse than the disease.
Do not use the keyword 'null'
Make all fields final to force compile error for non-initialisation.
Do not use the new Type[int] syntax for creating arrays of objects use Object[] x = { thing, thing2 };
Do not use reflection (thus cheating to create an array full of null pointers)
I don't know what you are supposed to use in place of null, say "" for strings? You may just be sweeping problems under the rug.
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching.
Andrew McDonagh - 29 Dec 2005 18:06 GMT > On 29 Dec 2005 06:29:19 -0800, "ricky.clarkson@gmail.com" > <ricky.clarkson@gmail.com> wrote, quoted or indirectly quoted someone [quoted text clipped - 16 lines] > I don't know what you are supposed to use in place of null, say "" for > strings? You may just be sweeping problems under the rug. I kind of agree and disagree...
There's nothing wrong with these techniques themselves, though the site touts them as being the whole story - which they are not.
Essentially what the page is trying to show, is that its certainly possible to create exception safe code that substantially reduces the problems encountered by null pointer exceptions.
This is not a new technique.
There's plenty of ways of achieving this too, NullObject Pattern, return zero sized collections or arrays instead of nulls, etc.
The reflection one is too weird for me to figure out what the supposed benefit is though....
ricky.clarkson@gmail.com - 29 Dec 2005 19:42 GMT > So tell me: how do you create an array, then, if you don't know the > length at compile-time? final List<String> strings=new ArrayList<String>();
int total=(int)(Math.random()*100+100);
for (int i=0;i<total;i++) strings.add("number "+i);
final String[] array=(String[])strings.toArray(new String[0]);
Ok, the concession there is that I have used new String[int value], but the value is 0, so there are no null pointers there.
> I don't know what you are supposed to use in place of null, say "" for > strings? You may just be sweeping problems under the rug. Roedy, the point is that you don't need these default values. If you find you need a default value, you might be creating an object before you're ready for it.
So it doesn't really matter whether it's null, "" or "unknown", you're better off with real data, if possible. Direct from TFA:
"You might also consider replacing null with "" in the first example, but default values bring about bugs caused by default values being left in place. A NullPointerException is actually better, as it allows the runtime to tell you about the bug, rather than just continue with a default value."
Andrew McDonagh,
Specifically, what I am against is the NullObject pattern. I want real data. Except in the case of mocking for automated tests, I'd rather have no object than an object populated with dummy data.
Wrt the reflection bit, I added a phrase just now to the article, to clarify:
"This is not a ban on reflection, it is just to warn that circumventing the rule on new Object[10] by using Arrays.newInstance has the same problem."
Roedy Green - 29 Dec 2005 20:00 GMT On 29 Dec 2005 11:42:07 -0800, "ricky.clarkson@gmail.com" <ricky.clarkson@gmail.com> wrote, quoted or indirectly quoted someone who said :
>final List<String> strings=new ArrayList<String>(); > [quoted text clipped - 4 lines] > >final String[] array=(String[])strings.toArray(new String[0]); That code is more complicated, and much slower than:
int size = ...; final String[] strings = new String[size]; for (int i=0; i<size; i++) { strings[i] = "number" + i; }
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching.
Andrew McDonagh - 29 Dec 2005 21:29 GMT > On 29 Dec 2005 11:42:07 -0800, "ricky.clarkson@gmail.com" > <ricky.clarkson@gmail.com> wrote, quoted or indirectly quoted someone [quoted text clipped - 17 lines] > strings[i] = "number" + i; > } We don't care about speed until a profiler tells us there is a problem with the speed - premature optimisation (a google-able term) sucks for many good reasons.
The code is no more complicated in my books..ymmv
Andrew McDonagh - 29 Dec 2005 21:54 GMT snip
>>I don't know what you are supposed to use in place of null, say "" for >>strings? You may just be sweeping problems under the rug. [quoted text clipped - 5 lines] > So it doesn't really matter whether it's null, "" or "unknown", you're > better off with real data, if possible. Direct from TFA: TFA?
> "You might also consider replacing null with "" in the first example, > but default values bring about bugs caused by default values being left [quoted text clipped - 7 lines] > data. Except in the case of mocking for automated tests, I'd rather > have no object than an object populated with dummy data. Thats not my understanding of NullObject - its a simple implementation that returns false/true, 0, "", empty Collections, etc. Its specifically so that we don't have to test for nulls everywhere, but in a safe manner. We wouldn't use it to return data that c/would cause us problems.
Sometimes (rarely) its useful to throw specific exceptions e.g. (NoInformListenersToInformOfStateChangeException). As it puts context information into what would have originally been a null pointer exception.
Andrew
ricky.clarkson@gmail.com - 30 Dec 2005 20:25 GMT > TFA? Sorry, slashdot slang - the f**king article. I don't even use slashdot (other than reading the headlines sometimes), but that one stuck in my head.
> Thats not my understanding of NullObject - its a simple implementation > that returns false/true, 0, "", empty Collections, etc. Its specifically > so that we don't have to test for nulls everywhere, but in a safe > manner. We wouldn't use it to return data that c/would cause us problems. Except that last sentence, I agree. However, I think NullObjects can cause problems, because they are providing a way of not testing for null. It is better to not have a value than to have either a NullObject or null.
For example:
interface BananaGiver { /** @return a banana or null if there is no banana */ Banana getBanana(); }
I'd rather have:
interface BananaGiver { boolean hasBanana();
/** @throws IllegalStateException if there is no banana. */ Banana getBanana(); }
Of course, there is the difficulty that a banana might appear between calling hasBanana and calling getBanana, but that can be included in a documentation contract.
I'd even prefer the one method, getBanana(), that throws an IllegalStateException, over something that might return null.
> Sometimes (rarely) its useful to throw specific exceptions e.g. > (NoInformListenersToInformOfStateChangeException). As it puts context > information into what would have originally been a null pointer exception. Agreed, but unless it's a checked exception that you throw, there's rarely a case where that would make a real difference. The NPE at least tells you where to look.
In the case of NoInformListenersToInformOfStateChangeException, that looks like it should be on the bad end of an if statement:
if (informListeners.isEmpty()) throw new NoInformListenersToInformOfStateChangeException();
for (final InformListener....
I don't see a NPE to handle there, unless informListeners is null, which is undesirable.
Chris Smith - 31 Dec 2005 02:29 GMT > final List<String> strings=new ArrayList<String>(); > [quoted text clipped - 4 lines] > > final String[] array=(String[])strings.toArray(new String[0]); Okay, so you can do that, but it's definitely more complicated.
More importantly, the only reason that the Collections API can implement toArray is that it doesn't follow your rules. You are setting things up so that a programmer needs to hope that there's some API to do stuff for him, because he's not allowed to write code to do so himself. That seems short-sighted.
> Roedy, the point is that you don't need these default values. If you > find you need a default value, you might be creating an object before > you're ready for it. I don't think you have a single shred of evidence that you don't need default values.
For one thing, it's exceedingly difficult to create a programming language in which it's not possible to observe a null value. Java is certainly not that language, and it's trivial to write code that observes the default (null) values of reference fields, even if you never assign values of null to the fields, declare them final, and follow all of your recommendations.
Considerably more relevant is the simple fact that problems domains often contain objects that either are or aren't there. You don't have a good answer to that problem. Sometimes the null object pattern can suffice for potentially non-existent objects that need to be modelled in software, but you seem opposed to that, as well. The only possibility that you've left open is to keep a list or array and just document a constraint that it must have either zero or one elements at all times; which is ludicrously convoluted as a solution to a simple task.
To Andrew, Ricky Clarkson wrote:
> I'd rather have: > [quoted text clipped - 7 lines] > Banana getBanana(); > } And this makes the point. Please provide an implementation of that interface that either can or cannot have a banana, depending on the object's state.
You seem to have serious problems with null or NullPointerException. I don't know where they come from... but I have to agree with John, that it would be better to educate people about the null value and the problem with dereferencing it. Adding complexity to the use of the language is no solution.
 Signature www.designacourse.com The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer MindIQ Corporation
ricky.clarkson@gmail.com - 31 Dec 2005 12:42 GMT Chris Smith,
> Okay, so you can do that, but it's definitely more complicated. The only line that's more complicated is the toArray line, which is just a sad artefact of the limitations of generics. If generics existed at runtime, we would have:
String[] array=strings.toArray();
In fact, a slight change to Collection could yield this:
String[] array=strings.toArray(String.class);
without any real language change.
> More importantly, the only reason that the Collections API can implement > toArray is that it doesn't follow your rules. Yes, this is definitely true. But, if an API exists to do something, why not use it? Plus, if you know HOW to avoid NullPointerExceptions, absolutely, then you can CHOOSE when to break the rules. E.g., you may allocate a 100 element array, but you trust yourself enough to fill each item before you give it away to any other code that is not expecting null.
Null might be required in certain circumstances, but it shouldn't be everywhere in your code if you don't want NullPointerExceptions. It should be isolated.
> For one thing, it's exceedingly difficult to create a programming > language in which it's not possible to observe a null value. Probably. I haven't written a programming language for ages. Does the reference system in C++ count? I never used it extensively, the compiler error messages foxed me, so I stuck with pointers.
> Java is > certainly not that language, and it's trivial to write code that > observes the default (null) values of reference fields, even if you > never assign values of null to the fields, declare them final, and > follow all of your recommendations. Yes, I think this exhibits the issue:
final class X { private final Object y=x; private final Object x=new Object(); }
I'm sure there are other ways too. I do think that making fields readable before they have been assigned (especially final fields) is a mistake in the language. Note that 'they' don't assign default values to local variables.
> Considerably more relevant is the simple fact that problems domains > often contain objects that either are or aren't there. Very true, but even then there is no reason for the *interface* to expose null.
interface Student { String getName(); String getAddress(); }
If we don't know where the Student lives, we might return null, which could cause problems for calling code.
interface Student { String getName(); //we always know the name! boolean hasAddress(); String getAddress() throws IllegalStateException; }
So yes, the simplest implementation would be a possibly-null reference to a String, but that 'null' is isolated. Having a zero-length collection is pretty pointless there - I don't really know where that came from.
> Adding complexity to the use of the > language is no solution. Passing null to methods that don't expect it is also no solution.
My point of view is of someone who wants to reduce bugs. Like it or not, testing is not comprehensive. This doesn't mean the program should be able to recover from all bugs, but it does mean that the program should be written in such a way that bugs are less likely, where it is practical.
Default values, except where they are present in a problem domain, seem only to serve to mask bugs.
I think these constraints are practicable, for more problems than you might expect.
> You seem to have serious problems with null or NullPointerException. I have serious problems with bugs. I don't like them. A NullPointerException seems like a beginner's bug, but people who seem to know what they're doing still cause them (myself included - I haven't applied these rules very far yet). So I just think that instead of becoming very fast at fixing the bug we should become better at preventing the bug. Ask a doctor whether this makes sense.
Chris Smith - 31 Dec 2005 23:39 GMT Paring this down to what's important...
> Null might be required in certain circumstances, but it shouldn't be > everywhere in your code if you don't want NullPointerExceptions. It > should be isolated. NullPointerException is a runtime error that indicates a failure of an assumption made about a variable... that it points to an object. This is exactly analogous to other bad values of variables. I often declare int variables in Java that I expect to remain non-negative, or less than one hundred, or whatever. Context constrains the possible values of a data type, no matter what you do. With integer types, I might code assertions to check these constraints. With null values, the compiler provides NullPointerException to do it. The fact that my code can throw a NullPointerException is a GOOD THING. It helps to diagnose problems.
And therein lies the problems with your article. Null values are not bugs. NullPointerException is not even a bug; rather, it's a deterministic way to find and report a bug. By avoiding the symptom, the problem can be buried and harder to find... or at best, still there. There's no reason to believe that your rules lead to better code. They just lead to fewer references with a value of null, and more time wasted writing code to work around the rules.
> A NullPointerException seems like a beginner's bug No, it doesn't. It's no more a beginner's bug than any other. It indicates a flawed assumption about an API. The immediate solution is to identify that assumption and fix it. The long-term solution is to understand the API and problem space better.
The problem appears to be that you assume a NullPointerException is an error that comes from making a mistake with the null value. In reality, NullPointerException comes from things like:
* I thought we could safely assume this request attribute was set in the previous HTTP request, but someone found a different path to this code.
* I thought this path name was guaranteed to be a directory, but it's a file instead and therefore doesn't have children.
* I thought the username had already been authenticated and always exists on the LDAP server, but someone passed in a synthetic username instead.
In all cases, a NullPointerException doesn't come from a poor understanding or treatment of the null value; it comes from a failed assumption about the software. It's not a mechanical thing to fix, but rather involves evaluating what's been newly learned about the software. Your rules cannot possibly help with that.
My fear is that you're peddling a magic pill, claiming that we don't need to really understand the language because we need only follow your simple rules and be safe. But that's not true. Following your rules only turns one bug into another, while making certain tasks impossible and others more complex and therefore more likely to contain bugs.
 Signature www.designacourse.com The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer MindIQ Corporation
Roedy Green - 02 Jan 2006 16:33 GMT >> A NullPointerException seems like a beginner's bug > >No, it doesn't. It's no more a beginner's bug than any other. It >indicates a flawed assumption about an API. The immediate solution is >to identify that assumption and fix it. The long-term solution is to >understand the API and problem space better. It is a beginner's bug in that beginners generate a lot of them being careless about initialising objects.
Using local variables wherever possible turns on initialisation checking you don't get with static or instance variables.
I think the reason Gosling decided to make all instance and static variables autoinitialising to null is that if he did not, there would be no way at compile time to detect the error.
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching.
Thomas Hawtin - 02 Jan 2006 16:45 GMT > It is a beginner's bug in that beginners generate a lot of them being > careless about initialising objects. NPEs are hardly the exclusive domain of the newbie. Search the bug parade for NullPointerException:
9425 Results Returned,
> Using local variables wherever possible turns on initialisation > checking you don't get with static or instance variables. Unless they are final.
> I think the reason Gosling decided to make all instance and static > variables autoinitialising to null is that if he did not, there would > be no way at compile time to detect the error. The error could be detected at compile time, the same as with finals. However, the values of final member variables are observable even before the constructor returns from calling super. That makes things tricky.
Tom Hawtin
 Signature Unemployed English Java programmer http://jroller.com/page/tackline/
Roedy Green - 03 Jan 2006 22:31 GMT On Mon, 02 Jan 2006 16:55:43 +0000, Thomas Hawtin <usenet@tackline.plus.com> wrote, quoted or indirectly quoted someone who said :
>NPEs are hardly the exclusive domain of the newbie. Search the bug >parade for NullPointerException: that is not what I am saying. I am just saying that newbies tend to make a lot of NullPointerExceptions. They are less likely to generate the more esoteric errors because their code is not as adventurous.
That's why I have a link to it under http://mindprod.com/jgloss/caq.html
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching.
ricky.clarkson@gmail.com - 02 Jan 2006 18:41 GMT > NullPointerException is a runtime error that indicates a failure of an > assumption made about a variable... that it points to an object. That's fair. However, in most cases, the assumption is also fair. An API user, unless they are paying close attention, will expect an object, not null. And no, I don't mean some NullObject, I mean a real object.
I would rather write APIs that actually allow the API user to make that assumption without being incorrect. It's quite similar to the old idea of reporting error messages via return values. People ignore them, mainly because of the large boilerplate required.
If you want to solve the problem of users assuming a reference is non-null, you can do one of two things:
1. Force the API user to compare every reference to null at 'some point' before using it. This is not possible in the Java language, but conceivable in some other language.
2. Don't write APIs that give API users null. Throw exceptions instead, or simply don't provide the method at a time when it won't return normally.
Either way would make the problem that users assume things cease to cause problems.
> I often declare > int variables in Java that I expect to remain non-negative You could easily constrain a value with a wrapper class, but it would have to check at runtime.
> The fact that my code can throw > a NullPointerException is a GOOD THING. It helps to diagnose problems. That is true, if you consider the alternative as being unprotected memory. For example, a mobile phone that I worked on in C didn't have memory protection. Many race conditions were caused by coders accidentally (I hope) reading and writing from NULL.
However, it is better still to not allow null at all, hence removing even the need to diagnose the problem.
> Null values are not > bugs Agreed, but in the context of real programmers making real mistakes, they are bugs waiting to happen.
> By avoiding the symptom, > the problem can be buried and harder to find... or at best, still there. That depends on how you prevent the symptom. If you prevent it using the NullObject pattern, then yes, you are burying the bug. If you prevent it by assigning useful non-null data to variables as soon as possible within the problem domain, then you have prevented the bug.
> It > indicates a flawed assumption about an API. In the context of newbie programmers, NPEs can come from their own code, no assumptions really:
class Thing { JFrame frame;
public void doSomething() { frame.setVisible(true); } }
Following 'my' rules will make this kind of bug harder to come across (the compiler would complain that frame might not have been initialised).
> * I thought we could safely assume this request attribute was set in the > previous HTTP request, but someone found a different path to this code. I'm not ignoring this, I just don't know enough about servlets, etc., to discuss it.
* I thought this path name was guaranteed to be a directory, but it's a file instead and therefore doesn't have children.
The API for java.io.File.listFiles() specifies that it returns null if the file is not a directory. In my opinion this is a mistake. It should throw an exception. I am, however, undecided as to whether it should be a checked or unchecked exception.
If I used listFiles() enough I would wrap it in a method that threw an exception if listFiles() returned null, and returned the value that listFiles() returned otherwise.
> * I thought the username had already been authenticated and always > exists on the LDAP server, but someone passed in a synthetic username > instead. Again, I'm not ignoring this, I just don't know enough to discuss it.
> It's not a mechanical thing to fix My experience with new programmers suggests that it often is a mechanical thing to fix. Null comes from their own code more than it comes from Java's APIs (thankfully!).
> Following your rules > only turns one bug into another Only if you use the NullObject pattern.
> while making certain tasks impossible > and others more complex and therefore more likely to contain bugs. I've already said that this isn't appropriate for all code. Especially when the problem domain dictates non-final fields, i.e., state. Yes, if you use this on code it isn't suitable for, you may get more bugs, because it ends up being more complex.
Chris Smith - 03 Jan 2006 18:57 GMT > That's fair. However, in most cases, the assumption is also fair. NO IT'S NOT! Java is a language in which references may have a value of null. Unless a programmer has a reason to believe otherwise, that making that assumption is wrong. If you don't like a language in which that's true, go find yourself another language. Or if you don't write any code that I have to deal with, feel free to pretend it's not the case. But don't go telling the public at large that the best way to write Java is to follow your dumb rules and pretend that references can't be null. It is not true, and it leads to bad code.
Your rules are wrong. It's become rather obvious by now. They are so wrong, in fact, that you can't even write a simple non-trivial application without breaking them or going to ridiculous pains. I have asked you twice now to implement a simple interface -- one that you proposed -- with the two methods hasAddress and getAddress, and you haven't done it BECAUSE YOU CAN'T DO IT without breaking your rules.
So stop telling people to follow them!
> In the context of newbie programmers, NPEs can come from their own > code, no assumptions really: [quoted text clipped - 8 lines] > } > } At this point, the programmer discovers that their code doesn't run. So let's tell that programmer about the difference between references and objects... something that they obviously don't understand.
You think that telling them to make that field final is going to solve the problem? What happens the first time that programmer needs a reference variable that isn't a constant, such as a pointer to the most recently opened JFrame? They are just screwed, I guess, because instead of actually TEACHING THE LANGUAGE, you chose to tell them your dumb rules, which don't allow them to write that particular code.
> The API for java.io.File.listFiles() specifies that it returns null if > the file is not a directory. In my opinion this is a mistake. It turns out that I agree. There are many cases where File ought to throw an exception, but doesn't.
> If I used listFiles() enough I would wrap it in a method that threw an > exception if listFiles() returned null, and returned the value that > listFiles() returned otherwise. That's just ludicrous, though. Unless you're just writing code in your basement for your personal amusement, someone else is going to have to deal with what you write. Every time you abandon a standard Java answer for a specialized answer just to satisfy your aesthetic sense, you make it harder for someone else to use and modify your code. If you do this every time something so trivial comes along as a method that returns null when you wish it had thrown an exception, you will quickly reach the point where the amount of project-specific knowledge needed to work with your code is overwhelming.
This is THE DOMINANT reason why software projects are frequently rewritten from scratch when they come under new management, leading to billions of wasted dollars. It is selfish programming, and does not become someone who claims to be a professional.
> > Following your rules > > only turns one bug into another > > Only if you use the NullObject pattern. No, not only if you use the NullObject pattern. You just finished telling me how Sun should have turn a NullPointerException into a different exception with uses of File.listFiles. Unless you fix someone's probably domain-specific assumption that caused the bug in the first place, you do not fix the bug. You just change it.
> I've already said that this isn't appropriate for all code. Then why do you tell people to do it? Do you want to prevent them from learning the language and cause problems whenever they try to do anything non-trivial?
It's not just some weird isolated class of code that your rules prevent. If you disagree, please implement that interface of yours. You know, the one I've asked for several times and that you've ignored? The one with methods called hasAddress and getAddress?
 Signature www.designacourse.com The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer MindIQ Corporation
Torkel Franzen - 03 Jan 2006 19:34 GMT > Java is a language in which references may have a value of > null. References don't have values, they are values. A variable of reference type may have as value either a reference or null.
Chris Smith - 03 Jan 2006 23:01 GMT > References don't have values, they are values. A variable of > reference type may have as value either a reference or null. The word reference has shades of meaning. If you want to be specific, you can say "reference value" or "reference variable". For example, you might point out that the JLS says (section 4.3.1) "The reference values (often just /references/) ...", which suggests your usage. I would then respond by pointing to another sentence in the same section: "There may be many references to the same object", which is ridiculous and false unless reference means something more like "reference variable" in that context. There are simply not multiple reference values that point to the same object.
In either case, it doesn't actually matter. You could equally well replace my sentence with either of the following in yor ter:
Java is a language in which there exists a reference "null".
or
Java is a language in which reference variables may have a value of null.
Neither one changes my meaning.
 Signature www.designacourse.com The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer MindIQ Corporation
ricky.clarkson@gmail.com - 04 Jan 2006 01:15 GMT > Java is a language in which references may have a value of > null. Unless a programmer has a reason to believe otherwise, that > making that assumption is wrong. A reason to believe otherwise is that they have followed these rules in their own code, and are currently calling another method from their own code.
Or they are calling code from another library that follows these rules, or the method call explicitly. So I don't disagree with what you say, but I do say that it would be better if the programmer could correctly make that assumption about more code, because realistically, programmers do make that assumption. This is the principle of least astonishment. If many people assume something, then you should either stop them from assuming it or make their assumption correct. Or ignore it and let them continue writing buggy software (unless their test plans are 100% perfect).
> If you don't like a language in which > that's true, go find yourself another language. Unfortunately, most language innovation seems to be happening in dynamically-typed languages these days. I'm not interested in these, because I think there is still a lot of mileage in statically-typed languages, in predetermined checking of contracts. I am mildly involved in developing a new language, but I'm more along for the ride really.
> But don't go telling the public at large that the best way to > write Java is to follow your dumb rules and pretend that references > can't be null. It is not true, and it leads to bad code. I don't. I told them how they can prevent NullPointerExceptions. I didn't say it was the best way to write Java. It is better, where applicable, though, to not add any extra null references into your application. Except where they are mandated by the problem domain.
The interface you asked for is fairly trivial to implement:
interface MightHaveAddress { boolean hasAddress(); String getAddress() throws IllegalStateException; }
final class DoesntHaveAddress implements MightHaveAddress { public boolean hasAddress() { return false; }
public String getAddress() { throw new IllegalStateException(); } }
final class HasAddress { private final String address;
public HasAddress(final String address) { this.address=address; }
public boolean hasAddress() { return true; }
public String getAddress() { return address; } }
I don't think I broke any of 'my rules' there.
> At this point, the programmer discovers that their code doesn't run. So > let's tell that programmer about the difference between references and > objects... something that they obviously don't understand. Agreed, and that is exactly what I do, and the people I teach learn how to solve NullPointerExceptions. But then they make the same mistake again, and they get to learn how to solve NullPointerExceptions very quickly. They are making a systematic error, i.e., one that is predictable and repeated. It would be better if they didn't make this error.
> You think that telling them to make that field final is going to solve > the problem? If the field is only intended to be assigned to once, then yes. Many fields are.
> What happens the first time that programmer needs a > reference variable that isn't a constant, such as a pointer to the most > recently opened JFrame? Not a problem, because they know both techniques. Or maybe you take objection to my teaching newbies techniques that let them write working code.
>> Some stuff about me wrapping File.listFiles() > That's just ludicrous, though. Not at all. The wrapping method is so tiny, probably 6 lines of code, 4 of which are braces, that it can't really confuse anybody who knows Java.
Call it a convenience method. People write them, because they're convenient. I write this one because it gives me a different interface to an implementation, an interface I prefer. I don't see this as a problem at all. It's better than lots of repeated code that does null checking.
> Every time you abandon a standard Java answer > for a specialized answer just to satisfy your aesthetic sense, you make > it harder for someone else to use and modify your code. Very slightly harder, in the order of less than a minute per maintainer, for the amount of time it takes to look at the documentation/implementation and realise what it does. I don't see this as a problem. If I was using concepts that would take a maintainer weeks to understand, I would see your point.
> you do not fix the bug. You just change it. I'm not sure I understand you at this point, but a compiler can pick up an uncaught exception.
> Then why do you tell people to do it? Do you want to prevent them from > learning the language and cause problems whenever they try to do > anything non-trivial? I think knowing these rules could be useful, but they are not the whole story. I'd like to encourage programmers to be 'considerate' about giving null to API users, and even to other APIs.
> It's not just some weird isolated class of code that your rules prevent. > If you disagree, please implement that interface of yours. You know, > the one I've asked for several times and that you've ignored? The one > with methods called hasAddress and getAddress? Yeah, I just did that. Thanks for reminding me.
Chris Smith - 04 Jan 2006 03:04 GMT > > Java is a language in which references may have a value of > > null. Unless a programmer has a reason to believe otherwise, that [quoted text clipped - 5 lines] > > Or they are calling code from another library that follows these rules, I said that in response to the concept that it's somehow implicitly more reasonable to assume that a reference is non-null than to make any of gazillions of other assumptions (such as that an integer in non-negative or less than 100, or that an object represents a valid key in some Map, or contains a valid social security number, etc.) If that were true, then that might justify going to extreme lengths to avoid having reference variables with a value of null.
> but I do say that it would be better if the programmer could correctly > make that assumption about more code, because realistically, > programmers do make that assumption. What programmers are you talking to? Assuming they aren't confused about more basic concepts (such as with the JFrame example you posted earlier), perhaps they need to be taught to read documentation or learn the language better. In any case, I don't want them working on my project.
I know quite a few bad programmers, but I don't notice that they have a tendency to assume non-null values for references, any more than to make any other flawed assumptions.
> > But don't go telling the public at large that the best way to > > write Java is to follow your dumb rules and pretend that references > > can't be null. It is not true, and it leads to bad code. > > I don't. I told them how they can prevent NullPointerExceptions. You're telling me that you AREN'T advocating these techniques? You're just interested in the abstract thought that following them would prevent NullPointerExceptions, for the same reasons that people study non-Euclidean geometries that have no useful applications in science or engineering? If that's true, I think you are confusing other people. It sure sounded like you were implying not only that your techniques prevented NullPointerExceptions, but that you thought that's a good thing.
(Incidentally, it's been demonstrated several times that your techniques are insufficient to prevent NullPointerExceptions. If you are really here for the mathematical buzz, perhaps that satisfies it.)
> It is better, where > applicable, though, to not add any extra null references into your > application. Except where they are mandated by the problem domain. And there, of course, is the crux. You can certainly avoid NEARLY all observable null values (though not all) by introducing arbitrary levels of complexity to the application... but that doesn't necessarily mean it's a good thing. And you were kind enough to demonstrate it...
> interface MightHaveAddress > { [quoted text clipped - 36 lines] > > I don't think I broke any of 'my rules' there. Wow, you sure didn't. What I had in mind was the slightly less complicated and again following your rules (with or without the odd single quotes you keep adding.. they are yours, aren't they? Or did you get them from elsewhere?):
final class AddressHolder { /* constrained to have length 0 or 1 */ private final List<String> address = new ArrayList<String>(1);
...
public boolean hasAddress() { return (address.size() > 0); }
public String getAddress() { if (!hasAddress()) throw new IllegalStateException(); return address.get(0); } }
(This is why I made comments about being forced to keep a List of length zero or one before... I didn't anticipate your even more complex solution to the quandary.)
> Agreed, and that is exactly what I do, and the people I teach learn how > to solve NullPointerExceptions. But then they make the same mistake > again, and they get to learn how to solve NullPointerExceptions very > quickly. They are making a systematic error, i.e., one that is > predictable and repeated. It would be better if they didn't make this > error. Either they basically lack the capacity to be programmers, or they are really being informed of specific assumption that they had made that are false... assumptions that exist at a higher semantic level than "oops, I just didn't think about the possibility that it would be null". They got the null value from somewhere, so one of these must be true:
1. It was returned from some API. They must have misunderstood the purpose of the API, if they didn't anticipate that the value they wanted might not be relevant. The NullPointerException teaches them something at a higher level of abstraction about the API.
2. It was passed in from somewhere as a parameter. Either they designed the API to accept null, in which case they ought to do something with it, or they didn't, in which case a NullPointerException is the right thing to do.
3. There's an uninitialized field. These errors do often occur from sloppiness, and I'd actually agree with you if you had just advised to be careful about initialization.
The remaining possibilities (for example, the programmer fully understands when some APIs might not apply, but persistently uses them anyway and doesn't bother with what happens in that case just because a deep sense of apathy) generally indicate an unsuitable temperament for working on software.
> > You think that telling them to make that field final is going to solve > > the problem? > > If the field is only intended to be assigned to once, then yes. Many > fields are. Some fields are, sure. I agree that they should be declared as final. That's not what you said in the article, though. You said "Make all fields final" -- which is, of course, a rather dumb rule to try to follow in Java.
In either case, whether a field is final or not has NO relationship to whether it should be able to contain a null value or not.
> Not a problem, because they know both techniques. Wasn't the goal to simplify things somehow? If not, then why do the rules exist? The new programmer has to BOTH know how to write code in the normal way AND memorize the rules? But they have accomplished the former, then why the latter?
> >> Some stuff about me wrapping File.listFiles() > > That's just ludicrous, though. > > Not at all. The wrapping method is so tiny, probably 6 lines of code, > 4 of which are braces, that it can't really confuse anybody who knows > Java. The problem isn't the number of lines of code used to implement the method. It's the number of places the method is used, and as a correlation, the number of programmers who have to learn what your method does even though they've known for ages how File.listFiles behaves.
Of course, if this is the only time you do this in a project, it's not a big deal. But this is a REALLY minor thing. You haven't really added any functionality to the original, made any code shorter, prevented any duplication, or accomplished any other objectively positive goal. If you do this every time the standard API grates against you the wrong way, then you're going to have a huge mess by the time your project reaches 100,000 or so lines of code. Anyone you hire for the project will have a tough time until they memorize how you've renamed all those pieces of the standard API that you don't like.
> Call it a convenience method. People write them, because they're > convenient. I write this one because it gives me a different interface > to an implementation, an interface I prefer. I don't see this as a > problem at all. I do. Convenience methods are fine, if they operate at a significantly higher level of abstraction than the code they replace. If not, then they make the code harder to read and understand, and do more harm than good. I figure the test (though mostly applied subconsciously) of whether a convenience method helps or not is twofold: can you think of a name for the method that (a) more or less completely describes the method's unifying purpose? and (b) is shorter and/or more recognizable than the code itself? In this case, I can't think of such a thing. You've got:
MyUtils.listFiles - fails test (a) MyUtils.listFilesButThrowExceptionIfNotDirectory - fails test (b)
Your wish that listFiles worked differently is irrelevant.
> It's better than lots of repeated code that does null > checking. But there's not lots of null checking. If you don't know that a File object represents a directory, you call isDirectory() first. If you do, then you just call listFiles and get the result. If you assume that the object represents a directory when really it doesn't, then the result is null, you've screwed up, and you want your code to crash with a nice, descriptive error message that tells you where the problem occurred... which is exactly what it does the instant you try to get the length or some element of that array.
It's simply a myth that proper use of listFiles involves checking the result against null. You made it up, and it's not true. You aren't saving any code at all by wrapping it in a convenience method. I'd prefer if the method in java.io.File threw an IllegalStateException instead because the resulting error could be made clearer (yes, I agree with you there)... but that's water under the bridge. You don't play standard API designer when you're writing an application.
> Very slightly harder, in the order of less than a minute per > maintainer, for the amount of time it takes to look at the > documentation/implementation and realise what it does. Nope. You're ignoring the second and third and fourth times that the maintainer looks up the method, since I've met few maintainers with perfect memories... and you're ignoring all the extra time and mental effort spent recalling that definition for the next few hundred times, since they'll still know the standard API definition better than your convenience method. That mental effort could have been spent understanding actual stuff about the code and its purpose, not why you don't like the standard API.
> If I was using concepts that would take a > maintainer weeks to understand, I would see your point. Quite the contrary, if you had concepts that would take the maintainer weeks to understand, you'd be very well advised to build abstractions from them. It's at this level, where what essentially amounts to administrative overhead of the memory is the dominant factor and the level of abstraction isn't much raised at all, that building so-called abstractions is ill-advised.
> I'm not sure I understand you at this point, but a compiler can pick up > an uncaught exception. Not an exception that you'd typically use to replace something that would generate a NullPointerException. You don't get to claim the advantages of checked exceptions without incurring substantial cost to the user of the API... something that, while safer, is considerably wore wordy and more of a pain than testing for null. That pain is only justified for things that should actually be handled anyway by application code.
> I think knowing these rules could be useful, but they are not the whole > story. I'd like to encourage programmers to be 'considerate' about > giving null to API users, and even to other APIs. Sure. If you'd said that, I would agree. APIs should be well- documented, and it's uncommonly likely to see the standard API neglect to document when a return value can be null or when a parameter can legally be null. I have even proposed and argued for, in the past, language extensions to provide nullability of references as a part of the reference type in the language (for historical interest only, see http://cdsmith.twu.net/professional/java/pontifications/nonnull.html).
It's not that bit that I disagree with. It's the fact that you proposed a ridiculous twisting of the language into contortions to avoid any possibility of null... a solution that's far out of proportion with the potential problem. You seem quick to back off those ridiculous contortions when someone points them out, yet there they remain in imperative language in your essay.
 Signature www.designacourse.com The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer MindIQ Corporation
ricky.clarkson@gmail.com - 04 Jan 2006 04:28 GMT > I said that in response to the concept that it's somehow implicitly more > reasonable to assume that a reference is non-null than to make any of > gazillions of other assumptions It is only more acceptable because it is more normal. The fact that it is normal is the reason why NullPointerException is not only a beginner's bug.
> You're telling me that you AREN'T advocating these techniques? I am advocating them, alongside other techniques, in my work. As I said in another post, the wikipedia page was just a bin for some ideas. As such, I'll revise it (I already have a little).
> Incidentally, it's been demonstrated several times that your techniques > are insufficient to prevent NullPointerExceptions. Are you referring to the fact that it's possible to read from a final field before it has been assigned to? If so, then hopefully there are static code analysers that can pick that up.
You seem to think that one badly-implemented class is less complex than two well-implemented classes. Numbers of classes and complexity aren't necessarily proportional. The implementation classes could both be package-private, accessed by a static method of some utility class. The API user wouldn't know or care.
>1. It was returned from some API. null returned from an API might be documented, but if it's possible for programmers to forget to check for it, then some of them will. Infinite Monkey Syndrome.
> 2. It was passed in from somewhere as a parameter. That's unlikely if the 'somewhere' either followed these rules or was considerate.
> Some fields are, sure. I agree that they should be declared as final. > That's not what you said in the article, though. And here we come to the crux of the problem. The article was about preventing NullPointerExceptions. It wasn't about rules you should follow absolutely in all your Java code. It was pretty terse, yet tone was read into it.
"People who don't drive cars run people over less" is a perfectly sane, if useless statement.
"You will run less people over if you don't drive a car" is equally sane, but tone will be read into it. It will be taken as an insult, and someone will respond with "but I live 40 miles from work" or something.
The article didn't proclaim to be useful for all Java code, it only gave some rules for preventing NullPointerExceptions. It didn't even purport to prevent ALL NullPointerExceptions, which is another bit of tone you read into it. It didn't say you should use it.
if (file.isDirectory()) { File[] files=file.listFiles(); System.out.println(files.length); }
That is capable of throwing a NullPointerException. This is fairly pedantic, but it is possible. The real directory could be deleted and a file created with the same name between the call to isDirectory() and the call to listFiles(). So you still need a null check.
If you trust your developers to check this possibly null value, then fine. But it's more likely that they'll read the API and believe that the above code sample will work always, which it won't. However, if you force them to catch a checked exception then they can't forget as easily. Is this a significantly higher level of abstraction, now that I've demonstrated a potential bug?
MyUtils.listFiles is a valid name, because the name doesn't have to include the types of exception something throws. The name will be backed up by documentation anyway, so the only requirement is that it is descriptive enough to be useful.
> Quite the contrary, if you had concepts that would take the maintainer > weeks to understand In this case I meant concepts that added very little but were complex. I struggle to think of an example.
Wordiness of exception-handling code is ok, because it is not a potential source of bugs itself, unless the developer gets fed up and just whacks 'throws Exception' everywhere, which is an issue of its own.
I'm undecided on checked exceptions, and hardly ever use them myself, but I think that where the developer might neglect to read documentation, a checked exception will force the issue. That might be good, it might be bad, depending on your preferences, but in terms of bugs, it should result in less, because it at least forces the developer to think about, or notice, the possible exception.
I like the non-null language extension idea. Someone else was discussing it today in terms of annotations (not on Usenet).
> You seem quick to back off those ridiculous > contortions when someone points them out, yet there they remain in > imperative language in your essay. Again, I'll be updating that page at some point, but I feel like I should see where this leads before I do. I have an open mind, much to my annoyance.
Chris Smith - 04 Jan 2006 05:13 GMT > > I said that in response to the concept that it's somehow implicitly more > > reasonable to assume that a reference is non-null than to make any of [quoted text clipped - 3 lines] > is normal is the reason why NullPointerException is not only a > beginner's bug. I'm still not seeing this. It's even *more* normal to have positive integers, by quite a margin. Do you plan to write up something on how to program without negative integers in Java?
> > You're telling me that you AREN'T advocating these techniques? > > I am advocating them, alongside other techniques, in my work. Okay, so far as I never have to interact with your work. But you're also advocating them on USENET and on wikibooks, which are public locations.
> > Incidentally, it's been demonstrated several times that your techniques > > are insufficient to prevent NullPointerExceptions. > > Are you referring to the fact that it's possible to read from a final > field before it has been assigned to? If so, then hopefully there are > static code analysers that can pick that up. That's one way. A far more likely way is to interact with any of thousands of standard API routines, unless you plan to wrap or otherwise isolate them all. Even ignoring reading from an uninitialized final field, your rules are valid only in a vacuum. Java is an established language, with a gigantic standard API and literally tens of thousands of third-party libraries and components.
> You seem to think that one badly-implemented class is less complex than > two well-implemented classes. I think that poor use of private members and method implementations of a class that acts according to a well-defined specification is better than a more complex API that's visible to a much larger set of code. I'd prefer neither, but that's not possible in this case because the rules of the game precluse it.
> The implementation classes could both be > package-private, accessed by a static method of some utility class. > The API user wouldn't know or care. More code would care than if you implemented it all inside of the class where it belongs. You could move your code into private nested classes to solve that problem.
> And here we come to the crux of the problem. The article was about > preventing NullPointerExceptions. It wasn't about rules you should > follow absolutely in all your Java code. If you don't follow them absolutely in all your Java code, then you don't prevent any NullPointerExceptions at all. If you succeed in creating a false sense of confidence that references are not null, you very likely make the problem worse.
> "People who don't drive cars run people over less" is a perfectly sane, > if useless statement. That isn't your statement. Your statement was more like:
"Don't drive cars."
> The article didn't proclaim to be useful for all Java code, it only > gave some rules for preventing NullPointerExceptions. I've yet to see a single example, though, of a place where following these rules might be a good idea. That makes it considerably less relevant than your statement about cars.
> if (file.isDirectory()) > { [quoted text clipped - 3 lines] > > That is capable of throwing a NullPointerException. Yes. And in an almost infintessimal number of situations, it might matter. In more situations, though, NullPointerException will be just fine for describing that problem.
> So you still need a null check. No, you really don't, unless there's some heretofore unmentioned reason that you do. In situations where application failure isn't acceptable, people don't randomly delete directories that are being used by the application at the exact instant that the application runs. In situations where it doesn't matter, the 1:1000000 chance of this occurring in response to a dumb user action is just not worth considering.
So you throw IllegalStateException. Are you going to do something there that's smarter than what you could do with NullPointerException?
> If you trust your developers to check this possibly null value, then > fine. I trust my developers to recognize the tiny fraction of cases in which it matters, yes.
> However, if > you force them to catch a checked exception then they can't forget as > easily. What?!? You want a checked exception for that?
> Is this a significantly higher level of abstraction, now that > I've demonstrated a potential bug? No. I wouldn't use your wrapper if it threw a checked exception, because I don't want to deal with the inane possibility every time I get a list of files in a directory. If it throws an unchecked exception, then you can use it not gain much over NullPointerException.
It IS better working from a clean slate (in the unchecked case), since you'd get a better, more descriptive error message. But it is not significantly better to the extent that it justifies the difficulty of maintenance.
> MyUtils.listFiles is a valid name, because the name doesn't have to > include the types of exception something throws. The point was that you don't have an abstraction, not that you don't have a usable name. You can call it whatever you want, but the the lack of a name meeting those two criteria is a pretty darn good indication that you haven't built an abstraction.
> I like the non-null language extension idea. Someone else was > discussing it today in terms of annotations (not on Usenet). I like the idea as well (obviously, since I write it down five years ago)... but finding an implementation that's consistent with the object initialization sequence is a challenge. The best option I've seen is to do something like final, in which the compiler requires initialization before the end of the constructor... but, of course, that still leaves open the possibility of observing a value of null. Oh, if only Java had restricted constructors to calling final or private methods, then this would actually be possible.
 Signature www.designacourse.com The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer MindIQ Corporation
ricky.clarkson@gmail.com - 04 Jan 2006 05:50 GMT > It's even *more* normal to have positive > integers, by quite a margin. Yes, it is. I neglected to Say What I Mean. I mean that it is more normal to assume non-null than to assume positive. Programmers seem to be more interested in verifying positive numbers, probably because the runtime isn't preventing negative numbers for them (except in the case of the char datatype).
> Okay, so far as I never have to interact with your work. You might have to interact with the products of it. I teach Java (the bulk of my work is still programming though).
> More code would care than if you implemented it all inside of the class > where it belongs. I typically put package-private implementation classes such as these in the same source file as their factory, but I don't like the extra 'features' inner classes have, so I don't actually make the classes inner. Java doesn't have a 'source-file' access level for top-level classes, only a package access level. My solution to this is to make packages more granular, although I'll freely admit I don't do this consistently.
> I've yet to see a single example, though, of a place where following > these rules might be a good idea. The Student example in the article itself, for example. It is a good idea there because the final keyword helps to make sure that the Student has definitely been initialised fully.
> people don't randomly delete directories that are being used by the > application at the exact instant that the application runs. Quite tiresomely, NFS partitions have a habit of disappearing while applications are running. It doesn't always require user misadventure.
> So you throw IllegalStateException. Are you going to do something there > that's smarter than what you could do with NullPointerException? Nope, because I don't care enough to make the exception checked. The IllegalStateException represents reality though, it is more descriptive. This method shouldn't have been called on this object at this time.
> Oh, if only Java had > restricted constructors to calling final or private methods, then this > would actually be possible. You could potentially force this upon your own code by using a tool such as CheckStyle. I'd guess you'd have to write a custom check though (which looks fairly easy from the docs I perused some time ago).
John C. Bollinger - 04 Jan 2006 05:54 GMT >>Java is a language in which references may have a value of >>null. Unless a programmer has a reason to believe otherwise, that [quoted text clipped - 5 lines] > Or they are calling code from another library that follows these rules, > or the method call explicitly. No, your proposed rules are not sufficient to support that assumption. You would need to add: () Never explicitly throw a NullPointerException () *Never* invoke a method that does not follow these rules (i.e. the current context is not enough; the whole program history must be taken into account)
I /think/ that might be sufficient, up to the point where you start dealing with native methods, to which more / different rules would apply. Of course, that last rule makes the ruleset recursive, so you really don't get to defer worrying about native methods. On the other hand, that also means you can't invoke any methods from the platform library anyway (none are guaranteed to follow the rules, and many in fact don't). If you want to be really rigorous then you can't instantiate any objects either (Object's constructor is part of the platform library, and invokes native code to boot), so you'd have to stick to static, procedural code. In the final extreme, you couldn't run any Java code at all because the ClassLoaders are part of the platform library, which we've already established you can't use.
To be sure, a program would have to do some comparatively intricate work to expose a null reference introduced by a ClassLoader, and the VM's Object implementation would probably have to be considered buggy if it somehow made a null reference available. But you can't be *sure*. As Chris said, it simply isn't safe to assume that your program will never handle null references.
As long as I'm taking my turn on the soap box, I'll assert that the first additional rule I suggested is non-trivial. To wit: my own code is simply rife with violations of it. This is because I have acquired the habit of /checking/ arguments against null, or otherwise ensuring that my methods will throw an NPE quickly if passed a null in violation of the method's expectations. This is an alternative partial solution to one of the more annoying problems that newbies have with NPEs -- they have trouble figuring out where a null reference came from in the first place. This comes back around to one of Chris' other assertions. Changing an NPE into some other error really doesn't gain anything, whether in source or at runtime.
> but I do say that it would be better if the programmer could correctly > make that assumption about more code, because realistically, [quoted text clipped - 3 lines] > it and let them continue writing buggy software (unless their test > plans are 100% perfect). Least astonishment is a design principle. The fundamentals of Java's design are long since set in bedrock, so least astonishment doesn't have any play here.
All the same, I think Java programmers very quickly learn that references can be null. That's what NPEs are about, after all, so we wouldn't otherwise be having this discussion. So much for astonishment. If following your rules could in practice alter the fact that references in a program may sometimes be null then I might agree with you, but they can't. According to you, then, the only remaining approach is to stop programmers from making the assumption. This is what I (and Chris) have urged on you from early on. Educate the poor junior programmers about the language instead of saddling them with cumbersome, inadequate rules.
 Signature John Bollinger jobollin@indiana.edu
ricky.clarkson@gmail.com - 04 Jan 2006 12:54 GMT John,
>> A reason to believe otherwise is that they have followed these rules in >> their own code, and are currently calling another method from their own >> code. I should point out the word 'currently' there.
Let me rephrase what I said in such a way that it means what you took it to mean:
< A reason to believe otherwise is that they have followed these rules in < their own code, and are ONLY EVER calling another method from their own < code.
If you call a method which will not return null, then there's no need to check the return value against null.
A more useful rule might be to force the developer to check values for null from methods that aren't known to never return null. This is what someone is looking into - a @NotNull annotation and some heavy static analysis.
> If you want to be really rigorous then you can't > instantiate any objects either new Object() cannot return null. It can only return successfully, or throw some Error or RuntimeException, so I don't see the issue.
> it simply isn't safe to assume that your program will never > handle null references. I never said otherwise.
> Changing an NPE into some other error really doesn't gain anything True, but in the case where Chris thought I was changing an NPE into another error, I quite simply wasn't. I had an IllegalStateException, because a method was called on an object that couldn't handle it successfully. There was no null reference involved, so NPE would be inappropriate.
> Least astonishment is a design principle. The fundamentals of Java's > design are long since set in bedrock, so least astonishment doesn't have > any play here. The age of something unfortunately doesn't stop it from astonishing. The easiest debunking of your argument is to find a newbie programmer and point at them. A whole new astonishee. Even experienced programmers get lazy, they think they remember the contract for a method, and invoke it as if it implements the contract they think it does.
> If following your rules could in practice alter the fact that > references in a program may sometimes be null then I might agree with > you, but they can't. What they can do is to alter that fact locally. References returned FROM THIS BIT OF CODE will not be null, so you don't need to check them against null.
> According to you, then, the only remaining > approach is to stop programmers from making the assumption. I don't think that's possible without enforcement. If goto was usable in Java, some people would use it. If String wasn't final, some people would subclass it. If the language doesn't mandate something then the bulk of programmers won't do it.
You can, and I do, educate programmers about the cause of NPE, and let them learn to solve them. But they still make the broken assumptions. I think that being careful in their own code about creating null values, and thus learning that they can create 'considerate' code, will also help them to differentiate between considerate API methods, and those like File.listFiles().
Chris Smith - 04 Jan 2006 18:35 GMT I just picked a place in the thread for this...
As I've said, I'm engaged with rebuilding JINX in my spare time. I just wrote an article to describe the generall agreed upon points here. Feel free to take a look and make modifications as you feel are appropriate and not overly controversial.
http://riters.com/JINX/index.cgi/Careful_20with_20Null_20Values
(Note that most of the links don't go anywhere. Hopefully that won't last long, but feel free to help fix it.)
 Signature www.designacourse.com The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer MindIQ Corporation
Roedy Green - 27 Dec 2005 09:53 GMT > System.out.println(account[i].getNumber() +" : $"+ >account[i].getBalance()); You did not tell us which line 29 was. I am guessing this one.
You only filled in two accounts and attempted to print ten..
You either need to keep track of how many use filled, or use an ArrayList instead of an array which does that for you.
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching.
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|