In review...
    In the statement:
System.out.print("What is your first name? ");
we see a method call.  A method (the name Java uses for subroutine) is a named block of code (like the main method).  We can execute a method by calling it, which you do by giving the method's name in the code.  The name of the method we are using here is System.out.print.  All method calls will have parentheses () after them, which may or may not have anything in them.  If anything goes in them, it is called an argument (also referred to as a parameter), which is a piece of data passed to a method.  If a method has more than one argument, the arguments will be separated by commas.  In this particular method call, there is only one argument, a string literal.  String literals will always be surrounded with quotes.  That string is shown to user before they are asked for input, explaining to them what they need to be entering.  This type of string is called a prompt.
    In this statement:
fname = Stdin.readLine();
the method named Stdin.readLine is being called.  When method calls need to be evaluated (such as when they are used on the right side of an assignment statement like we have here), they evaluate to that method's return value, which is a piece of data passed from a method back to whoever called it.  Stdin.readLine returns a String, so to be able to store that string in our program, we have to assign it to a String variable.  Not all methods have return values though; the ones that do are called functions.  The ones that don't are called procedures.  A procedure call (method call where the method is a procedure) cannot be evaluated, and therefore cannot be used on the right side of an assignment statement.  System.out.print is an example of a procedure.
...end review.

    Methods allow us to simplify the programs we write.  They can seperate out a complex task, allowing that task to be accomplished anywhere in our program with one line of code.  Parsing text input to a program and converting it to a numeric data type, or converting the opposite way for text output takes takes some fairly complex code that may be needed many times in a program.  When we use the Stdin.readInt() and System.out.print() methods though, we are not interested in what doing those conversions entails.  We just want to get some input or output to or from the user.
    Besides using the methods built into Java or ones provided by third parties, we can create our own methods to further simplify our code, and seperate the complex details of how each task our program does is accomplished into smaller chunks.  Each method we write should do only one task, making them easy to write, easy to read, and easy to understand.  It will also make it clear what is happening in each place in our program where that method is called.  Methods also allow us to reduce duplication of code, as the code for tasks that are done more than one will appear in only one location.  This reduces the likelihood of errors, and makes it easier to change things later.
    Here is a program that asks the user for a number, determines whether or not the number is prime, and prints an appropriate message to the screen.
public class Primes {

    public static void main(String[] args) {
        int number;
        boolean prime = true;

        System.out.print("What is the number? ");
        number = Stdin.readInt();
       
        for (int i=2; i <= number/2; i++)
            if (number%i == 0) {
                prime = false;
                break;
            }

        if (prime)
            System.out.println("The number is prime");
        else
            System.out.println("The number is not prime");

        System.exit(0);
    }
}
    You can see that the program accomplishes three tasks that are completely independent of one another.  Again, one task is getting a number from the user.  Another task is determining if a number is prime.  Finally, the last task is printing a message.  Each of these tasks should become a method.
    Before any method can be written, you must determine what data (if any) it needs to do its task, and what data (if any) will result with that task being accomplished.  You also need to determine the data type for each of these pieces of data.
    To get a number from the user, we need to know the prompt.  If we need to get more than one number from the user, this prompt could be different every time.  The prompt is a String.  Once we get a number, the result (that number) is an int.
    The pieces of data the method needs to do its task will be the arguments.  The result will be the return value.  Every method will be in a class.  A method should be in the block of code that makes up the class, and only that block.  We have already seen one method: the main() method.  It is inside of a class, and looks like this:
public static void main(String[] args) {
    // code
}
    That whole block of code is called the method definition for the main() method.  Other method definitions we write will look just like this.  They start with the words "public static."  The next word is the data type of the return value.  Next is the name of  the method, and finally, the arguments are listed in parentheses.  The arguments look like variable declarations, each with a data type and a name.  Multiple arguments are seperated with commas.  So, the structure is this:
public static return-type method-name (datatype name1, datatype name2) {
    // code
}
with as many arguments listed in the parentheses (including zero) as needed, each with a datatype (which don't need to all be the same).  When you write the code for a method, you can assume all of the arguments (the variables listed in the parentheses at the beginning of the method definition; also called the formal parameters) already have values, because those values will be supplied when the method is called (the arguments in the method call are called the actual paramters).  The name of a method and the data types of its arguments make up that method's signature.  Every method must have a different signature.  This means that you could have more than one method with the same name, as long as the argument lists aren't the same length with the same data types; this is called method overloading.
    If the return type of a method is anything other than void, it is expected that there be a return value.  To return a value, you use a return statement, which is just the word return followed by the value being returned.  A method for getting a number from the user could look like this:
public static int number(String prompt) {
    int num;
    System.out.print(prompt + " ");
    num = Stdin.readInt();
    return num;
}
    Just as with variables, it is important that methods have appropriate and descriptive names.  Methods that return a value should generally be named with nouns, describing what is being returned.  Arguments, like any variables, should be named describing what they represent in that method.
    The next step in our example program is to determine if the number is prime.  To do that, the method that does this task needs to know what the number is.  The data type will be an int.  The method will determine that the number either is, or is not prime.  When there are only two possibilities, it is often appopriate for the return type to be a boolean (as a boolean value can only be true or false).  Grammatically, it should make sense.  It is either "true" that the number is "prime," or it is "false" that the number is "prime."  Methods that return a boolean value should generally be named with an adjective.  Our next method could look like this:
public static boolean prime(int number){
    for (int i=2;i <= number/2;i++)
        if (number%i == 0)
            return(false);
    return true;
}
    A return statement is like a break or continue statement in that it terminates the enclosing block of code.  A return statement, in fact, will terminate the entire method.  You should use a return statement at the earliest opportunity in the code that the return value is known.  It is quite possible, and perfectly acceptable, to have more than one return statement in a method.  No matter what path you take through a method (with all possibilities for the results of loops and if statements), a method that says it's going to return something must always return something.  In our prime method, the for loop and the if statement can determine that a number is not prime.  If this doesn't happen (for instance, if the for loop body never executes, or the if condition is never true), and the for loop runs to completion without false being returned, we must return true.
    Finally, to print a message, we need to know what the message is.  The data type will be a String.  There will be no other data that results from this task.  This method will just do its task and be done.  It will not return anything, and the return type will be void.  It could look as follows:
public static void printMsg(String msg) {
    System.out.println(msg);
}
    A method that doesn't return anything should generally be named with a verb.  The name for this method says exactly what it does.  It prints the message, which it calls msg.  With our methods written, our program would look like this:
public class Primes {

    public static int number(String prompt) {
        int num;
        System.out.print(prompt + " ");
        num = Stdin.readInt();
        return num;
    }

    public static boolean prime(int number){
        for (int i=2;i <= number/2;i++)
            if (number%i == 0)
                return(false);
        return true;
    }

    public static void printMsg(String msg) {
        System.out.println(msg);
    }

    public static void main(String[] args) {
        int num;

        num = number("What is the number?");
       
        if (prime(num))
            printMsg("The number is prime");
        else
            printMsg("The number is not prime");

        System.exit(0);
    }
}
    The main method is shorter, and much easier to read and understand.  You can see exactly what the program will do, without getting lost in all of the details of how all of these things are done.  The way the methods were designed facilitated this.  Some important qualities of our methods were that they did one well-defined task, and that they were written to be as generally useful as possible.  The process of breaking down a larger piece of code (which could be a whole program, or could just be a method) into smaller pieces of code as we just did is called refactoring.
    With our number() method being called number, it is a generic name that doesn't say what that number represents.  It takes a String as an argument, which lets us use any prompt we need.  As far as the number() method is concerned, the number could represent anything; it doesn't matter.  We could call the number() method as many times as we needed, to get any variety of numbers from the user.  With the method being called in more than one place, if we decided later that we wanted to change how to get a number, we would only have to change code in one place.
    With the prime() method returning a boolean value, that method call will evaulate to a boolean value (either true or false), which allows us to use it as a condition in an if statement or a loop.  If the method returned a String, it would be less useful, because it would not only figure out of the the number was prime, but also what to do in response.  Just returning a boolean lets our main program make that decision.  We will also see then, in main(), what exactly is being done.
    Finally, with printMsg() taking a String as an argument, we can see in main() exactly what String will be printed, and we could use that method to print any String we wanted.
    One last point is that the order in which the methods appear in the class is not important.

    A variable is only accessible within the block of code in which it is declared.  This accessibility is called a variable's scope.  In the Primes program, the variable num declared in main() is only accessible (or "in scope") within the main() method.  The variable num declared in the number() method is completely unrelated.  The fact that, in this program, they both happen to represent the same piece of data, is only a coincidence of the way we wrote the program.  It is not important, and will not always be the case.
    When a variable is declared in a method, its scope is said to be local (confined) to that method (or it is said to have "local scope").  A variable can be declared in a method either in its argument list, or in the actual block of code that defines the method.  The variable prompt in the number() method is local to that method, and is accessible nowhere else.
    When a variable is declared, a piece of memory in the computer is set aside to store that piece of data.  A variable declared as an argument to a method is created and assigned a value when that method is called.  When we say:
prime(num)
the prime() method is called, and memory is set aside for a variable named number that is local to the prime() method.  Its value will be a copy of the value being passed to it as an argument from main() (which in this case is the value of the variable num that is local to the main() method), and it will be a seperate memory location.  Since it is a copy, if the value of the variable number is changed during the execution of the prime() method, the value of the num variable in main() will not be changed.  When a method only receives a copy of an argument, that argument is said to have been passed by value.  If the method were to have access to the actual memory location of the data passed as an argument, the argument would be said to have been passed by reference.  This is not possible in Java.
    A variable will no longer exist (and its memory will be reclaimed by the computer) once the block of code it is declared in finishes executing.  The time in which a variable does exist in memory during the execution of a program is called that variable's lifetime.  Once the prime() method returns (and therefore finishes executing), its number variable will no longer exist in memory.  The next time the prime() method is called, the number variable will be a completely different variable with a different location in memory.

    When you write a method, you know at the time you write it what the method is supposed to do, what the arguments represent, and what the return value represents.  You try to make these things as clear as possible with the way you name the method and the arguments, but it is still useful to document these things with comments so that it is 100% clear to you and anybody else that reads your code.  In Java, there is a standard way to document a method; it is called a Javadoc comment.
   Javadoc comments are opened with a /** and closed with a */ and are placed right before a method.  They describe the whole method, each argument, and the return value.  A properly documented version of the prime() method would look like this:
/**
  * Determines if a number is prime
  * @param number the number
  * @return true if number is prime, false if not
  */
public static boolean prime(int number){
    for (int i=2;i <= number/2;i++)
        if (number%i == 0)
            return(false);
    return true;
}
    The method description is always first.  There will be a @param line for each argument.  Sometimes some of the information can be a bit redundant.
    A class can have a Javadoc comment too.  It would go right before the line that says public class classname and looks like this:
/**
 * Description of the program or class
 * @author Author's Name
 */
    Once a Java class is fully documented with Javadoc comments, the javadoc program can be used to automatically create a nice HTML file with all of the documentation.  Other programmers can use this documentation to figure out how to use a class and its methods without having to look at the actual code.  Here's a snippet of the HTML document generated for the prime method:
Method Detail 

prime

public static boolean prime(int number)
Determines if a number is prime

Parameters:
number - the number
Returns:
true if number is prime, false if not

    It's quite common that methods that are written by one person will be used by many other people.  The other progammers that use a method will only look at its documentation to figure out what it does and how to use it; they will not look at the code.  For this reason, it is important that a method only do what it says it's going to do, and nothing more.  If a method does anything else besides what it says it will do, that unexpected behavior is called a side-effect.  One common side-effect is having a method that prints something to the screen and returns something.  Generally this is a bad idea.  In most cases, printing something would not be a part of creating some piece of data and returning it.  If a method is designed that way, the design should be re-evaluated.

    The way this Primes program was redesigned and explained here involved writing the methods first, and writing the main() method (that controls the execution of the whole program) last.  When a program is designed and written this way, the process is called bottom-up design.  An alternative to the way it was designed and explained here, could go as follows.  You could think through what the program has to do, determine what all of the methods need to be (including their arguments and return values), but not actually write them.  You could save the work for figuring out how to implement each of the individual methods until later, and then start by actually writing the main() method, as if the other methods already existed.  As a last step, you would then write the methods.  This type of design process is called top-down design.  Both design processes are commonly used, and each one works better for different people.
    If you take the top-down design approach and you have a main() method that calls other methods that don't actually exist, you can't run the program or test it in any way.  One way around this is to start writing the methods, but just have them do something simple.  A sensible thing to do is have them do what they would do for one specific set of inputs.  A method that doesn't actually do it's job, but just does something so that the program that uses it can be compiled and tested is called a stub.  For the Primes program, we could have written some stubs that would assume that the number 12 would be entered into the program.  The stubs could look like this:
    public static int number(String prompt) {
        // this is just a stub
        return 12;
    }

    public static boolean prime(int number){
        // this is just a stub
        return false;
    }

    public static void printMsg(String msg) {
        // this is just a stub
        System.out.println("The number is not prime");
    }
    You can see that the methods don't do any real work, but they do essentially accomplish what they should if 12 was the number entered by the user.  With those 3 stubs and the main() method written, you could run the program, and make sure it at least flows correctly.
    Taking the bottom-up design approach, you fully implement one method at a time.  Once one has been written, before moving onto the next one, you really should test it and make sure it actually works.  One way to do this is to write a main() method that just calls your one method, with known inputs, and makes sure the proper job is done, or that the proper value is returned.  The method could be tested multiple times with different values to be thorough.  The small program you write for testing the method is called a driver.
    To test the number() method, you could have main() do:
System.out.println(number());
    and then run it, input a number, and make sure it prints the number you gave it.  For the prime() method you could do:
System.out.println(prime(12));
System.out.println(prime(13));
    and test some numbers to make sure it prints true for prime numbers and false for the other ones.
    No matter how which design approach you take, you really should be doing this kind of testing as you write a program, and should test each method you write with drivers.

recursive
precondition
postcondition

white box/black box testing