Thursday, December 3, 2009

Java Methods


As we saw in Introduction to Objects, a class can define both attributes and behaviors. Attributes are represented by instance variables; behaviors are defined by methods. Without methods, an object cannot do anything. It can only passively wait for other objects to manipulate its visible data. Some programming languages use passive data structures that do exactly this; they contain a cohesive set of data, but they have no behavior and must rely on other functions or subroutines to manipulate their data.

Fortunately, Java is an object-oriented programming language. Good object-oriented design calls for a class's data to be as hidden as possible. If a class's data is hidden, other classes cannot manipulate the data directly. If another class wants to update the data, it must request this by invoking a mutator or setter method.

Note: Data hiding is known as encapsulation and is an object-oriented best practice.

Method Invocation

When an object calls a method (either one of its own or another object's), the calling object is actually requesting that the receiving object perform some action; set a value, return a value, write to a file, or send an email, for example. This is also know as message passing; one object passes a message to a second object. The message contains the name of the method to execute on the receiving object and any required data that the receiving method requires. Data that are passed to a method are known as arguments; the required arguments for a method are defined by a method's parameter list.

Let's look at some examples of method invocations:

// Call method executeQuery() on myObject.
myObject.executeQuery();

// Call method set() on date, passing it the
// arguments Calendar.MONTH and 11.
date.set(Calendar.MONTH, 11);

// Call static method parseInt on Integer, passing
// it argument "32" and assigning the return
// value to variable age.
int age = Integer.parseInt("32");

Method Signature

The combined name and parameter list for each method in a class must be unique. The uniqueness of a parameter list takes the order of the parameters into account. So int myMethod (int x, String y) is unique from int myMethod (String y, int x ).

Let's take a look at the general syntax for a method declaration:

[modifiers] return_type method_name (parameter_list) [throws_clause] {

[statement_list]
}

Everything within square brackets [] is optional. Of course, you don't include the square brackets in your code; they are included here only to indicate optional items. You can see that the minimal method declaration includes:

  • Return Type: The return type is either a valid Java type (primitive or class) or void if no value is returned. If the method declares a return type, every exit path out of the method must have a return statement.
  • Method Name: The method name must be a valid Java identifier. See Java Variables for the rules for Java identifiers.
  • Parameter List: The parentheses following the method name contain zero or more type/identifier pairs that make up the parameter list. Each parameter is separated by a comma. Also, there can be zero parameters.
  • Curly Braces: The method body is contained in a set of curly braces. Normally, the method body contains a sequence of semicolon delimited Java statements that are executed sequentially. Technically, though, the method body can be empty.

Note: If a method is declared with the abstract modifier or is defined in an interface instead of a class, there will be no method body; instead a semicolon will follow the parameter list's parentheses.

Other Modifiers

There are a number of optional modifiers that you can use when declaring a method. They are listed in the following table:

Optional Modifiers
Modifier Description
Visibility Can be one of the values: public, protected, or private. Determines what classes can invoke the method.
static The method can be invoked on the class instead of an instance of the class. For example, String.valueOf(35) is calling valueOf on the String class instead of on any specific String object. Of course, static methods can still be called on object instances: myString.valueOf(35).
abstract The method is not implemented. The class must be extended and the method must be implemented in the subclass.
final The method cannot be overridden in a subclass.
native The method is implemented in another language.
synchronized The method requires that a monitor (lock) be obtained by calling code before the method is executed.
throws A list of exceptions thrown from this method.


Java Methods -Java's main() Method


Everything Begins in main()

Remember that Java programs are executed on the command line using the java command. The java command takes a fully-qualified class name as an argument; this class's main method is where program execution begins.

Let's look at a basic class that prints out a date and message:

 package arunsoft.method;

import java.util.Date;

public class Message1 {

public static void main(String []args) {

Date now = new Date();
String message = now.toString();
message += ":";
message += "Hello";
System.out.println(message);
}
}

Compile and execute Message1.java from a DOS or UNIX shell:

Kevin-Taylors-Computer:~/src ktaylor$ javac methods/Message1.java   Kevin-Taylors-Computer:~/src ktaylor$ java methods.Message1  Thu Jan 20 21:57:02 CST 2005:Hello   

Behind the scenes, the JVM finds methods.Message1 in the classpath and begins executing main(). When main() exits, the program ends and the JVM shuts down.

Let us take a closer look at the attributes of main():

  • public: It must be declared public.
  • static: It must be declared static because it is being called on the class, not on a specific instance.
  • void: Its return type is void because it doesn't return a value.
  • String []args: Its only parameter is a String array that holds optional arguments passed to the class on the java command line.

Passing Arguments to main()

The version of main() above has the message hardcoded. This isn't very useful, so let's update main() so we can pass a message into main() as an argument on the java command line. Change Message1's main() to the following:

    public static void main(String []args) {

// Make sure the command
// line argument was passed in
if(null == args || args.length < 1) {
// Command line argument
// doesn't exist, so exit with
// an error flag
System.exit(1);
}

// Timestamp the message
Date now = new Date();
String message = now.toString();
message += ": ";

// Extract the only command line
// argument from the first element
// of the array
message += args[0];
System.out.println(message);
}

The new version of Message1 can be executed with the following command line:

 java example.Message1 "Hello from the command line"   

Command line arguments are delimited by spaces, so arguments that contain spaces must be wrapped in double quotes, otherwise each word will be considered a separate argument. (Remember, this program only prints out the first element.)

Methods Enable Code Reuse

Message1.main() does all the work in our program. It retrieves the command line arguments from the args parameter, prepends a timestamp to it, and then prints it out. This is a lot of work for one method. A good coding practice is to write small methods that do only one thing. This makes it more likely that you will be able to reuse that small bit of functionality. Also, if you need to change the functionality and it is contained in a single method, you only need to make the change in that one place.

In our example, what if we want to print out each element of the array on its own line, instead of just the first element? It will be much easier to make this change if we first break out the current functionality that creates a timestamp into its own method. Here is a new version, Message2, that does just that:

    package methods;

import java.util.Date;

public class Message2 {

public static void main(String []args) {

// Make sure the command
// line argument was passed in
if(null == args || args.length < 1) {

// Command line argument
// doesn't exist, so exit with
// an error flag
System.exit(1);
}

// Extract the only command line
// argument from the first element
// of the array
String message = args[0];
String formattedMessage = prependTimestamp(message);
System.out.println(formattedMessage);
}

public static String prependTimestamp(String str) {

Date now = new Date();
String timeStamp = now.toString();
return timeStamp + ": " + str;
}
}


Message2 has the same behavior as Message1. But, now the code in prependTimestamp is reusable. Any code that needs to prepend the current date to a String can call this method. An added benefit is that the method name clearly indicates what the method does; this reduces the need for an explaining comment.

Note: Always strive to use clear, meaningful identifiers for classes, methods, and variables. This will reduce the number of comments needed in your code by clearly expressing the intent of the program. This is know as "programming by intention."

Now let's update Message2 so that it loops through the elements in the args array and prints out each element. Move the current code that reads and prints out the first array element into its own method named printMessages(String []messages). Then, update main() to call this new method. Finally, update printMessages to loop through the array.

Note: Make the change in the order I specified. When changing the internal structure of code (know as refactoring), it is critical to do it in small steps, compiling and testing after each step.

I have renamed the final class as Message3. Here it is:

    package methods;

import java.util.Date;

public class Message3 {

public static void main(String []args) {

// Make sure the command
// line argument was passed in
if(null == args || args.length < 1) {

// Command line argument
// doesn't exist, so exit with
// an error flag
System.exit(1);
}
printMessages(args);
}

public static void printMessages(String []messages) {

if(null == messages) {
return;
}

for(int i = 0; i < messages.length; i++) {
String formattedMessage = prependTimestamp(messages[i]);
System.out.println(formattedMessage);
}
}

public static String prependTimestamp(String str) {
Date now = new Date();
String timeStamp = now.toString();
return timeStamp + ": " + str;
}
}



Method Overloading

Each method in a class is uniquely identified by its name and parameter list. What this means is that you can have two or more methods with the exact same name, but each with a different parameter list. This is a powerful feature of the Java language called method overloading. Since method names typically represent an action, this allows you to define how to perform the same action on different types of inputs. Here is an example of overloading a method max() in order to calculate a maximum value for different combinations of inputs:

public static int max ( int x, int y ) {
// calculate max using two ints
}

public static double max ( double x, double y ) {
// calculate max using two doubles
}


Method Overriding

If a child class extends a parent class, the child inherits all of the methods and attributes of the parent class. So, if a parent class contains a method reorder():

public int reorder(int x, int y) {
//some parent implementation
return x;
}
The child inherits this method. But, the child may decide to override the parent's implementation by redefining the method:
public int reorder(int x, int y) {
//new child implementation
return y;
}

Notice that the child returns y whereas the parent returns x. This feature of Java enables a powerful, object-oriented technique called polymorphism.

Note: Although a child class inherits all methods and attributes of their parent class, the methods and attributes must have the correct visibility in order for the child to access them.

Method Visibility

A method's visibility (also know as its access scope) defines what objects can invoke it and whether subclasses can override it. The four possible visibility modifiers are: public, protected, private, and no modifier. Keeping an object's methods as hidden as possible helps simplify the object's published API. Make a method only as visible as it needs to be. For instance, if a method is intended to be overridden by a subclass but never invoked by client code, make the visibility protected instead of public. If a method should never be invoked by another class and is not meant to be overridden, make it private. Visibility of variables is covered in Java Variables.

Method Visibility
Modifier Can be Accessed By
public any class
protected owning class, any subclass, any class in the same package
No Modifier owning class, any class in the same package
private owning class

Parameters are Passed by Value

In Java, when a value is passed into a method invocation as an argument, it is passed by value. This is unlike some other programming languages that allow pointers to memory addresses to be passed into methods. When a primitive value is passed into a method, a copy of the primitive is made. The copy is what is actually manipulated in the method. So, the value of the copy can be changed within the method, but the original value remains unchanged.

When an object reference or array reference is passed into a method, a copy of the reference is actually manipulated by the method. So, the method can change the attributes of the object. But, if it reassigns a new object or array to the reference, the reassignment only affects the copy, not the original reference. As an example, if you pass a URL object reference named myURL into a method invocation, the method can call myURL.set(someNewUrl) to change the URL's attributes, but if it tries to reassign a new URL object to the myURL reference, the change will only be in effect for the scope of the method invocation. In other words, myURL = new URL() changes the memory address that the copy of myURL points to, not the memory address of the original myURL.

In this tutorial we have covered the basics of using and writing methods in Java. This, combined with previous tutorials on variables and objects, provides the foundation for more advanced concepts in object-oriented programming and design patterns.

0 comments:

Post a Comment

 

JAVA INTRODUCTION Blak Magik is Designed by productive dreams for smashing magazine Bloggerized by Ipiet © 2008