This week's book giveaway is in the Reactive Progamming forum. We're giving away four copies of Reactive Streams in Java: Concurrency with RxJava, Reactor, and Akka Streams and have Adam Davis on-line! See this thread for details.
This page is for all those newbies who are overwhelmed by the prospect of writing a new class, maybe one that's a bit more complex than those you've tackled up to now. You've read those instructions and you just want to shout "Mummy!!".
It won't tell you what to write, but it will (hopefully) give you an easy way to avoid errors and get to a good starting point.
It's quite long, but that's mostly because we'll be taking you through the process step-by-step; there's nothing wildly complicated about it.
Hopefully, you'll also pick up some useful tips along the way.
Have at least seen a few Java classes, probably from your textbooks or tutorials. Specifically, you must know what a Java array declaration looks like and what a main() method looks like. This is simply so that the code you see here isn't complete gibberish.
Know how to use a basic editor (like Notepad).
Know where (ie, in what directory) you're going to put your class. In general your tutor, or the book or tutorial you're following, will have given you this information.
Know how to use javac (the Java compiler) to compile your code. Again, this should normally be part of your course or tutorial.
Chances are that if you're working from a book or course material, you will have been given explicit instructions about what they want you to do. And it's here where newbies often start throwing their hands up.
An example might look something like this, and it's the one we'll be using:
"1. Create a class called Dice to represent a pair of dice and the totals of their rolls. It should have two integers to hold the results of rolling each die. It should also have an array of integers to represent the possible totals of rolling two dice. This array will be used to count the number of times each total comes up.
The class should also have the following methods:
initCounts() - to initialize all "total" counts to zero.
roll() - to roll each die once, and add one to the correct totals element.
printCounts() to "print" - ie, display to the console - the number of times each total has come up over a number of rolls.
2. Add a main() method that creates a Dice object, initializes its totals, rolls the dice a number of times (say, 10,000), and then prints out the results."
Ooof. Does it look daunting?
Almost certainly that's because you're already thinking about how you're going to code it:
How to I initilaize an array?
How do I roll a dice?
How to I update counts?
How do I display an array?
And my advice is (and it's a really hard habit to get into):
Remember what I said at the start? This tutorial is NOT going to tell you what to code, it's going to show you how to get to a point where you can start coding; but there's quite a bit to do before you can get there.
Right, so you've got your instructions and you've read the first lesson. Now it's time to create your class. I don't propose to go into great detail about the nuts and bolts, since these will probably be in your book or tutorial, but you're creating a Dice class, so it needs to go into a file called Dice.java.
Not dice.java or DICE.java or Dice.JAVA, but: Dice.java.
Java is case-sensitive. Remember that, because it's very important.
OK, so you've created your file, now let's add the class declaration:
Why final? Because you don't know if you're going to subclass it or not. It's a tip you won't find in too many books, but it's a very good one to remember:
Make your classes 'final' unless you know you're going to subclass them.
You can always remove it later on if you do decide to subclass, but you can't add it.
The only other thing that's probably worth doing, since your requirements said you will need to create a Dice, is to add a constructor for it, viz:
The super() call isn't strictly necessary, since the compiler will add it for you if you forget. Indeed, that entire constructor (called a "no-args" constructor) isn't actually required either, since the compiler will add it too - in fact, it will add precisely the code we just wrote - but I always like to put it in myself so I can see what's going on.
Just one final thing: You might assume from that declaration that your Dice class exists in a vaccuum - well it doesn't. It extends Object. All Java classes do, unless they extend something else.
And again, the compiler will put it in for you if you forget; but I like to put it in explicitly, just to remind myself what's going on:
And there you have it: one Dice class declaration. And for the moment that's it. You may need to add other stuff to it later on, but right now you don't know what that is.
And what should you do now? COMPILE. Hopefully, you shouldn't have any errors, but just in case you're a bad typist...
The next thing the requirements asked you to do was to add some fields, so let's do that.
The first thing it asked for was two integers to hold the dice results, so:
And here we have another important point:
Always, always, always make your fields 'private', unless you've been specifically told not to.
And if you have, you might want to think about getting another book (or tutor).
Allowing others access to the internals of your class is a bit like walking around with your flies undone - not something you want to do too often.
Another point to remember: Use meaningful names.
We could have called those fields d1 and d2, or just x and y, if we wanted, but it would be bad programming.
Programs are meant to be read by human beings, and if you ever run into problems and need someone else to look over your code, they're going to have a hard time deciphering it if you constantly use cryptic names.
You don't need to go overboard:
is definitely overkill - but still MUCH better than d1.
Remember: You know what you were thinking when you wrote your code, but other people don't; and the surest way to get it consigned to the garbage bin is to make it hard to follow.
And one last point: Follow standard naming practises.
Field and method names should start with a lowercase letter; class names with an uppercase letter. It's only a convention, but it's almost universally accepted, so start using it NOW.
The instructions also told you to add an array of integers to hold counts of each total for your two dice.
Now here you do have to do a bit of thinking: What are the possible totals you can get from two dice? Well, the lowest is obviously 2 (each dice showing a 1) and the highest is 12 (each dice showing a 6), so there are 11 possible totals.
So, in the spirit of derring-do, you simply bash out:
(I'm presuming that you're familiar with how to create an array)
Now there's absolutely nothing wrong with this, and it will work just fine; but what you now have is an array with elements numbered from 0 to 10 (Java array indexes start from 0).
That means that every time you come up with a total, you'll have to subtract 2 from it to get it into the right element, and every time you display your totals, you'll have to add 2 to the element index to show the total it's for. A bit pointless don't you think? It's just one more thing to go wrong, and it doesn't really add any value.
What about an array where we could just plug the total directly into an element? So, for a total of 7 it goes into element 7. Much nicer. But now that means that you have to have an "element 12". And this is where beginners often slip up.
The beauty of it is that your class will never work (or will keep throwing Exceptions) until you've replaced ALL of them with real code.
Furthermore, you can throw an Exception from ANY method, providing it's the only thing you do. And lastly: UOE is defined in java.lang, so it's always available to you.
Let's have a look at our first method: initCounts()
Although we're not going to be writing any code for it (yet), we do need to think about what it will look like, and for that we need a method signature; and in Java that means 5 things:
Its arguments (or parameters) - ie, the things we're going to need to pass to it.
What it's going to return.
That last one is a thing that a lot of people (not just beginners) forget. Well don't, because it's important (more on that later).
So: What does this method need to do? Note: what, not how - we're not writing any real code yet, remember?
Happily, our requirements told us precisely: "initialize all total counts to zero".
So taking each point in turn:
We already have its name: initCounts.
Does it need any arguments? Well, since it's just going to be initializing our totalCount array to 0's - probably not.
What should it return? Again, since it's only initializing our totalCount array - probably nothing.
Visibility: A very important (and neglected) thing. Does anything outside our class need to be able to call it? I'd say the answer is: we don't know.
Finality: Are we likely to want anything overriding it? Well, since it's initializing our totalCount array, which is private - answer: No.
and from that we get:
Why private? - because we don't know if anyone else needs to call it; and in that case we shouldn't let them. As with final on our class, we can always change to something less restrictive later if we choose, but we can't make it more restrictive. And making it private doesn't stop our class from calling it.
We don't want it to be overridden, so it should be final.
It doesn't need to return anything, so we specify void as the return type.
It doesn't take any arguments, so we write empty brackets.
And to turn it into a "stub"?
Remember that 'new'; otherwise you'll get a compiler error (and I still miss it out, even after 12 years
I thought I'd run through this one as well, because it's slightly different from the previous one. Remember, we want a method signature, and for that, we need to think about those 5 points.
We know the name: roll.
Does it need any arguments? Well, since it's just rolling our "dice" - No.
What should it return? This is a judgement call. It will work perfectly well if it doesn't return anything, but I personally prefer methods that return something. Call it the mathematician in me (although I'm not one), or maybe just that I'm too lazy to write two calls - one to "do it", a second to get the result - but I generally find it helps to return something if you can. In this case, why not simply have it return the total of our two dice? It's no skin off our nose, and it might be useful to somebody.
Visibility: Now here we have something that other classes are likely to want to call, so - public.
Finality: Are we likely to want anything overriding it? Again, since it's simply rolling our (private) dice - answer: No.
And from that we get (as a stub):
(Again: remember that new)
And adding it to our class:
And what do we do? COMPILE. Sorry if it sounds like a broken record, but it's really important.
And just in case you're worried that you absolutely have to get that method signature right first time - don't sweat it too much. You can always go back and change it if you need to (at least until you have a class that other people are using). But do think about it. It's important that you get a sense of what these methods are supposed to do before you start bashing out code for them.
And it's quite possible that some ideas for that code might occur to you while you're going through this process, so it's usually not a bad idea to have a notepad beside you to scribble down notes. Just make sure that none of them end up in your class ... YET.
It may seem as though we've just gone through a lot of effort for nothing. After all, what we've written won't actually do anything. On the other hand, what we DO have is a skeleton class that:
WON'T work until you replace all those UOE's with proper code.
And what's more, there is hardly any wasted effort. We would eventually have had to write every single line in it except for the UOE ones - and we plan on replacing them anyway.
And just in case you don't follow how useful that is, let's have a crack at writing that main() method. What did our requirements say?
"Add a main() method that creates a Dice object, initializes its totals, rolls the dice a number of times (say, 10,000), and then prints out the results."
OK, let's do it:
And plug it into our class:
And what do we do now? Broken record time: COMPILE.
And you know what? Unless you typed something wrong, it WILL compile. Without errors.
It won't run of course - or rather, it will run, but it'll just throw a UOE for the time being. But that main() method sure looks right to me. We've followed our instructions to the letter, so it's highly unlikely that we'll have to change it once we get those other methods coded.
Do you see what's happened? Because we have an error-free skeleton with all our methods coded as stubs, we're free to tackle the actual code any way we see fit. I bet you thought you'd have to code all those other methods before you even thought about coding main().
Furthermore, The process we've been through has:
Allowed you to do write a lot of useful stuff without worrying about how you're going to code a single method.
Forced you to think about what each method will look like BEFORE you start bashing out code for them.
Allowed you to deal with one thing at a time - in this case: Creating an error-free skeleton class.
And that last point is very important. Part of the art of programming is something called problem isolation - breaking down a problem (or process) into discrete chunks so that you can concentrate on each one individually.
Hopefully, it's also taught you one other very important lesson:
You don't need to know HOW you're going to do everything when you start.
If you don't know how to do something, put it off - and the easiest way to do that is to write a stub. Procrastination may be the thief of time, but it's no bad thing when you're writing programs.
You now have a skeleton class that (as you've seen) you can start to "fill out" with real code. And you can do it incrementally, sure in the knowledge that the rest of it will compile. So, if you get any errors, they're from what you typed in since your last compile.