Thursday, August 25, 2016

JAVA 6 - Avoiding tangled code with methods

Last time we were looking at operators.  The program I wrote to support it showcased a whole load of operators, which you can see here.  The problem is that the main() method went on a bit ...

Rapunzel, you don't want your main method to end up like your hair ...

Computer programs aren't one single, long listing ... though they used to be (but then, hey you would be lucky to have 1kB of memory to fill).

Methods (previously known in some languages as functions) are a way of taking a piece of behaviour, breaking it into it's own space where its easier to read, but more importantly where it can be called whenever you need it (and reused).

[You might notice because I learned about methods originally in my days of C programming, I'll revert by accident to using the word "function".  Pretty much function and method can be used interchangeably.]

If you've ever manually test scripted, you might have used a similar concept to methods in your scripts.  You probably have a script somewhere for logging in, and ideally it's fleshed out in just one place,


Do you flesh out your script with such detail EVERY time you login?  Of course not - you tend to define it once like this (if you absolutely have to), then you refer to it time and again to save effort.  It saves you time writing out, and if there's any significant change to the page (for instance "log in" will now consistently be called "log on"), it means you have less changes to make (less maintenance for the win!).



Exploring methods with some examples

I'm going to talk through some of the features of methods, using a few examples, each one building on a previous one, and expanding them.

The way I learn any language (and how I really recommend you do too) is not just to read, and copy examples.  But also to play and experiment with it.  I'll try as always to suggest ways to do this as we go along.

My examples are all in Github, and I'll include references as I go along.


Be aware, this is a pretty big section, and I've broken it down for you.  You might want to work through them all in one go, or pace yourself through them!



A basic method

Okay - so as a minimum viable product for the use of a method "write a hello world program which uses a method you've created to print to screen".

My code for this can be found here.



Here printMe is our method - the following is the header definition for the function, which shares a lot of similarities with the main() method when we previously put that under the microscope,

  • private - this could also be public.  It defines how visible this method is.  The main() function can see this because it's part of the same class definition for basicMethod.  However if you tried to use this outside of the basicMethod class, you'd get an error.
  • static - as we've said, because we have a main() method our methods have to be static within this class.
  • void - means that this method just does it's job, it doesn't return a value.
  • printMe - this is the name of our function.  We can choose it to be whatever we want to be (as long as it's not a reserved word used for something else like "int", "double", "static" etc).
  • () - this helps to define that we've got a function here.  If we were passing values, they'd be inside the brackets, but this is our minimum viable product remember!

After this, the print statement which is bounded by {...}.  Everything within here is part of the

Within the main() function you can see there is the command printMe(); which calls the function.

Try,

  • Changing the visibility of the function from private to public. Anything bad happen?
  • Do I really need that static definition?  Remove it and see what happens.



Method visibility

I've created a project on Github here where my printMe() and main() functions are in separate classes, so that you can see how this works.

So we have a print class here:



And a main class here:


Notice how printMe doesn't have to be static now?  We've also had to do a slightly odd call of the printMe method, which will make more sense when we cover objects.

Notice that both classes are using the package sharedMethods, which they're part of, and hence they can see each other.

Try,

  • What happens when you change printMe to private?

[Note - my suggestion is that you download my code from Github.  To create yourself you need to use a common package, which we don't discuss until Part 13]


Passing variables

As mentioned before, we can pass data to our methods when we call them - which helps to unlock a lot of behaviour.

We have to defined the parameters we use in the function header, in the () part.  You can have multiple variables defined here, all comma separated.

We use a nomenclature similar to where we define variables in a program so ...

addNum (int num1, int num2);

So you start with the type of parameter/object, then follow with the name,
int is the data type of integer
num1 and num2 are the names of the variables

Variables defined in the header can be used inside the function, so you wouldn't get an error if you had a line like,
num1 + num2;

Because the variables weren't found.


I have in Github an example here,


Here you can see I've redefined printMe to take in a number "num" and a string "str", which it prints to screen.

In the main() method you can see how I declare values that I then pass to my method with the call printMe(printNum, printStr).

Notice how I don't need to match the name of the variable string I use in main() ie printStr to the one I use in printMe ie str.


Passing values

When you send values to a method, you're sending over a copy of your actual variable, not the variable variable.

It's similar to a thriller where the good guy hands over a tape with something incriminating on, only to see the villain destroy it.  Somewhere later on the good guy goes "aha - you thought you'd destroyed it - you only destroyed a copy!!!".

The best way to demonstrate this of course ... is with an example.  Which can be found here.



Here,

  • We create variable "number" within main(), which is set to 1.
  • We then pass "number" to incrementNumber function, which increases it's copy to 2, and prints that it's 2.
  • When the function finishes, it returns to the main() function.  Where the original version of "number" is still set to 1.

This is often called "passing by value".


Returning values

This might have you asking "is calling a method a one-way street?  I can pass information into it, but it's not much use getting information out".

Up until now we've defined void functions.  Ones which don't return any information.  However we can change that to any variable or object type we want.

So we have an example ready to go here,

Here we have a sightly difference version of incrementNumber,


This one increments the number, and then returns it using the return command.  The return command means that the system exits the method on it's execution

Try to,
  • Return a non-int, you should get an error
  • Add a print command after the return command.  You should get an error that the code is non-reachable (as the system will exit on the return command).

This method takes two string, and returns a new string where they've been joined together with a space in-between.


Finally, in our main() method you'll see something interesting,


The main() method is calling the function and using an assignment operator "=" to take the value, and assign it to a local variable.  Hence unlike the previous example, the work of the method is returned and retained.  Essentially you can use this design to "over-write your original".




There are also be some other ways we can manipulate data with methods, but we'll look at them later when we look at objects.



See ... everything so much easier when you keep things short ...


2 comments:

  1. I like your blog a lot. Its informative and full of information. Thank you for sharing.

    ReplyDelete
  2. Your blog has given me that thing which I never expect to get from all over the websites. Nice post guys!

    ReplyDelete