Sei sulla pagina 1di 16

Chapter 4:

Functions Defining Methods

4.0 Introduction

Objects created from a class are capable of behaving according to the methods lying
defined within that class. The question is – how to write codes for those methods?

Methods are written in the form of functions. That is why, methods are also called
functions. Then the next question comes -- what is a functional form? Those who are familiar with
algebraic functions already know the answer.

If we say --- y is a function of x or y = f(x) – then you understand that if a value of x is


passed to the function f(x), a y-value will be returned. For example – say, y = 3x + 5; if we pass
a value of x as 2, the function will return a value of 11.
A function can be taken as a block capable of accepting zero, one or more input
parameters but returning a single output as shown in fig-4.1 (a).

Output y
f(x)
x Input(s) Fig-4.1(a) A Functional block

So a function, to its users, can be regarded as a black box which is capable of returning
an output value [obtained according to the codes written inside] when its users feed some
input argument(s). All methods in a java class take this view of a functional form as shown in
fig-4.1 (b). Therefore, java’s methods are nothing but functions.

Input argument(s), if any output of the < return type>


Java codes inside a
method

Fig-4.1 (b) Java’s Method block

Next question – what are the advantages of having this functional form of a class-
method? The answer is –
i) to hide low-level inner code details from its users. External use of methods may be
allowed without exposing inner details;
ii) to reuse portion(s) of class codes, as and when necessary, by simply using the
method-name, and
iii) to divide a complex computational task into a collection of smaller methods so
that problem solving becomes easier, object-specific and modular.

All these aspects will be clear gradually as we go further into its details.

The general form of a member function of a class is shown below:

[access-specifier] <return-type> function-name ( parameter-list)


{
body of the function;
return < output>; // if Computational type
}
where

[access-specifier] can be either public or protected or private type.

When a function is specified as private, a member of that class type only can use that
function.
Any member, even belonging to external classes can use a public function or method.

Protected is mainly concerned with the inherited class types. That is, only inherited class
members can access the protected functions.

When no access –specifier is mentioned, by default java takes that function as public
within its own package boundary. [A folder or directory containing a number of defined
classes forms a Package]. Detailed discussions about such packages will be made in
chapter-9.

<return-type> is concerned with the data type ( like int, double, char, boolean,
etc. ....) of the output produced by the function. It may so happen that a function is defined
to take some actions inside but not to return any output value. Even in that case, the return-
type should be marked as void.

When a function is defined to return some output, the body of the function must include the
statement -- return < output variable>;

Each function, except those of type void, actually returns a value of the specified
data type. That is the property of a function. A function can be classified according to its
internal activities.

A Computational Function has to return some output value.


A Manipulative Function can return success or failure information by outputting 0
or 1 respectively.
A Procedural Function, which takes some inner actions (like input/output
operations) but does not return any output value, but defined with the return-type as void.
(parameter list) – a list of comma separated input variables, with their respective
data types, required by the function for internal computation. An empty parameter list for a
function is very much allowed. For example ---

In addMethod() function – access-specifier is public and the return-type is double,


because it returns the sum of x and y values which were declared individually as double
[ see example-2.1]. Moreover, that function needs no input argument to pass, that is why the
parameter list is empty.

public double addMethod( )


{
return x + y;
}

In cosMethod() function – access-specifier is public but return-type is void, because


the function does not return any value. This function makes use of a public library function
sin(rad) which is a member of the Math class and it accepts only one parameter – i.e.
angle expressed in radian [ example-2.12].

public void cosMethod()


{
double rad = deg*22/(7*180);
double result = Math.cos(rad); // using Math class of java.lang package
System.out.println(" cos of the angle =" + result);
}

However, parameter list of a function can take the general form of –

<function-name> ( type variable1, type variable2, ... , type variableM)


{
function body;
}

Please note that always meaningful function-name should be chosen. Function-


name normally starts with a lowercase letter. You will notice that a function-name tries to
use a verb because every method is supposed to take some action(s) inside or output some
data-value doing computation within the functional block.

4.1 Pure Functions

Functions are mostly used to produce some computational output. Actions inside a
function may be like reading and displaying some data values; assigning or modifying some
existing values; computing and returning a result for further use, etc.
Out of all such actions, some operations like write or modify can disturb or change the value
of some already stored member-data. Therefore, write or update operations are to be treated
very carefully and unrestricted public access should not be allowed.
On the other hand, read or display operations are not destructive, because read operations
do not change data values. So no access restriction will be necessary for such operations.

Based on the operational side effects, functions can be classified as either pure
functions or impure functions.
A pure function, when invoked, does not cause any change in the state of an object,
that means there will be no change in the values of the object’s instance variables.
For example readData() or getData() functions can be treated as pure functions as
they do not change any existing data values.

Pure functions can safely be declared as public also.

Now the use of a pure function will be demonstrated [see example-4.1].

// Example-4.1 Demonstration of a Pure Function

public class PureFunc


{
// instance variables
String name;
int rollno;
int total;
char grade;

public char gradDiv( int tmarks) {


if (tmarks >= 750)
grade = '*';
else {if( (tmarks >= 600) & (tmarks < 750))
grade = 'F';
else if ((tmarks >= 400) & (tmarks < 600))
grade = 'S';
else if ( tmarks <400)
grade = 'P';}
return grade;
}
public void display( int roln, char grad) {
System.out.println(" Roll No. : " + roln + " Division: " + grad);
}

public static void main() {


PureFunc std1 = new PureFunc(); //first object created
std1.name = " Ashoke";
std1.rollno = 3216;
std1.total = 583;
std1.grade = std1.gradDiv(std1.total);
System.out.println ( "Student Name :" + std1.name);
std1.display( std1.rollno, std1.grade);

PureFunc std2 =new PureFunc(); //second object created


std2.name =" Bimala";
std2.rollno = 5432;
std2.total = 808;
std2.grade = std2.gradDiv(std2.total);
System.out.println(" Student Name : " + std2.name);
std2.display( std2.rollno, std2.grade);

}
}

If you run this program, you will get the output as shown below –

Student Name: Ashoke


Roll No: 3216 Division : S

Student Name : Bimala


Roll No : 5432 Division : *

Please Note:

1) The states of the objects std1 and std2 remain unchanged in whatever way you run the
pure method display (int, char). There will be no change in the object’s state.
2) Carefully observe how the control if-else statements are used in the gradDiv(int)
method. Details about such control statements you will learn in chapter-6.
3) The class PureFunc has used three methods – gradDiv(int), display(int,char) and the
main() method.

4.2 Impure Functions

Impure functions, also called modifier functions, are those that can cause a change
of state in the object. That means, values of the object’s instance variables get modified or
changed depending on the current state of the object on which the function operates. Such
functions can cause some unwanted side effects if not carefully controlled by the access-
modifier.

So more restrictions are to be imposed on the use of such impure functions. To impose
different categories of restrictions – java allows optional inclusion of modifier along with
the access-specifier while defining member functions or methods of a class.
A modifier can be one of – final, native, synchronized, transient, volatile. The
functionality of a final method can never be changed. Final modifier prevents overloading
[not allowing same function names with different arguments] of functions. Final modifier
also prevents inheritance that is creation of a sub-class from a pre-defined base class is not
allowed. For advanced java programmers, knowledge of other types of modifiers may be
necessary but for the beginners, those are unnecessary and have been kept out of scope of
this book.

// Example-4.2 Demonstration of an Impure Function

public class ImpureFncTest


{
// instance variables

String name;
int accNo;
double accBalance;
double withdrawVal;

public double transaction(double balance, double withdraw) {


if ( withdraw > balance) {
System.out.println("Sorry !! Transaction Impossible.");
}
else {
balance = balance - withdraw;
System.out.println("Transaction Successful.");
}
return balance;
}

public void show( double bal){


System.out.println ( "Balance Available : " + bal);
}

public static void main() {


// manipulation of the first object
ImpureFncTest customer1 = new ImpureFncTest(); //first object
customer1.name = " Anita Kar";
customer1.accNo = 8912;
customer1.accBalance = 123456.50;
customer1.withdrawVal = 5000.00;
System.out.println ( customer1.name + " -- Account No. :: " + customer1.accNo);
customer1.accBalance = customer1.transaction(customer1.accBalance,
customer1.withdrawVal);
customer1.show(customer1.accBalance);
// manipulation of the second object
ImpureFncTest customer9 = new ImpureFncTest(); //second object
customer9.name = " Kalyan Bhatt";
customer9.accNo = 13245;
customer9.accBalance = 3592.75;
customer9.withdrawVal = 4000.00;
System.out.println ( customer9.name + " -- Account No. :: " + customer9.accNo);
customer9.accBalance = customer9.transaction(customer9.accBalance,
customer9.withdrawVal);
customer9.show(customer9.accBalance);
}

If you run this program, you will see the output as shown below (picture 4.1)–

Picture 4.1

In this example, transaction (double, double) is an impure function, because it


causes a change in the object’s state by changing the value of the Balance Available.

Also note that the function main () can include both the types of member functions –
pure or impure. Programmer must be very careful about defining impure functions so far as
access-specifier is concerned.

4.3 Arguments to Functions

As mentioned earlier, functions are capable of accepting zero (i.e. no argument), one
or more argument variables to return either one or no output value. Input values are passed
as arguments to the formal parameters while calling a function or method. For example: -

Example-4.3 Computation of Area by passing Two Arguments


// length and width data -- are passed to function cover

public class Area


{ int length, width;
public int cover(int l, int w)
{
length =l;
width =w;
return (length*width);
}
}

// utilizing the function cover ( ) of the class Area


public class AreaDemo
{
public static void main(String args[]){
// two objects created out of class Area
Area area1 = new Area();
Area area2 = new Area();

System.out.println(" Covered area of 1 = " + area1.cover(15,10));


System.out.println(" Covered area of 2 + " + area2.cover(25,15));
}
}

Picture 4.2 Outputs of example – 4.3

Please note that the function cover of the class Area is defined to accept two argument
values — length and width. In AreaDemo class, the default Area () constructor is utilized to
create two area objects – area1 and area2, which can use the cover function by passing
appropriate argument values i.e. (15,10) and (25,15) respectively as shown in example-4.3.

4.4 Function Prototype & Function Signature

A function prototype is the first line of a function definition which describes the
return type of the output and the number and type of arguments to be passed to call it along
with its name and access-specifier. In example-4.3 the prototype of the function cover () is

public int cover(int l, int w)


Compiler checks each use of a function prototype during every invocation of it and report
error(s) in case of any mismatch.

On the other hand, a function signature is concerned mainly with the numbers and
data types of the arguments to be passed during its invocation by calling function name.
The signature of function cover () of example-4.3 is simply cover (int, int). Therefore, a
function signature is concerned with the function-name and arguments only, whereas a
function prototype takes care of the full functional interface -- including the signature,
return type of the output, access-specifier, modifier, etc.

4.5 Function Overloading

Like constructor overloading, a function overloading is very much allowed in java. That
means, in a java class more than one method can have the same name but they must have
separate signatures --- i. e. arguments with different data types and with different numbers of
them. Thus function overloading is made possible due to different function signatures. An
example here can make the conception clear.

// Example-4. 4 Function OverLoading

public class OverLoad


{

int a;
double r;
public void show()
{

System.out.println(" Nothing to show.");


}
public void show(int x)
{
a = x;
System.out.println(" The value of a is =" + a);
}
public void show(int x, int y)
{
a = x*y;
System.out.println(" The value of x*y is = " + a);
}
public void show(double u, double v)
{
r = u+v;
System.out.println(" Sum of two numbers is = " + r);
}
}
// The DemoOL with the main () method

public class DemoOL


{
public static void main(){
OverLoad obj = new OverLoad();
obj.show();
obj.show(25);
obj.show(12,36);
obj.show(7.6,13.4);
}
}

This program, on execution will produce the following outputs:

Nothing to show.
The value of a is = 25
The value of x * y is = 432
Sum of two numbers is = 21.0

In this example-4.4, the method show () is overloaded four times. The first one
takes no argument and displays “Nothing to show”. The second one takes one integer
parameter and displays that value. The third one accepts two integer parameters and
displays the product of those two. Finally the fourth one takes two double type parameters
and displays the sum of them. Four overloaded methods are performing different tasks
although they bear the same function name.

Function overloading is an example of polymorphism by which one functional


interface can take care of multiple methods. The overloaded functions are all having a
common name but multiple argument signatures, that is different types or number of
arguments. This overloading mechanism helps accommodating different arguments for
different situations to tackle. The programming flexibility is thus enhanced.

4.6 Object Variable as a Reference to the Class type

Whenever you define a class, a new special data type gets created for use in your
program. Different Objects of that user-defined data type can then be created and used.

Creating objects out of a class is a two-step process. One, to declare a variable of a


particular class type and two, acquiring a physical copy of that class type and connecting
that memory chunk with a reference address. The new operator allocates memory for the
object and returns a reference to it. This reference is then stored against that object of the
class type variable. In example-4.4, by the expression

OverLoad obj = new OverLoad();


the object obj gets created with a reference to the starting address where it is
supposed to appear physically.

Class type
variable
reference An object of the
OverLoad class
obj
type created
In Memory

Fig - 4. 2 Class type Variable obj refers to the memory space

In reality, the variable obj simply holds the memory address where the actual OverLoad
object exists. That object has links to four reference addresses for four over loaded
functions named show (...). During run-time those addresses are resolved by observing
the arguments passed along with the function call (example-4.4).

4.7 Invocation of Functions on the Created Objects

Any object created out of a class type can invoke any method(s) or function(s)
belonging to that class. So the object obj of OverLoad class type can invoke any one of
the show (..) functions as per argument matching. Four overloaded function – show (...) --
have been called (example-4.4), simply by passing appropriate arguments.

obj.show(); // no argument
obj.show(25); // with one int type argument
obj.show(12,36); // with two int type arguments
obj.show(7.6,13.4); // with two double type arguments

Therefore, we can say that the function invocation or call has a general form of –

<object-name>.function-name( nil or argument[s] of proper data type[s]) .

While defining a function formal parameters are specified, but during invocation of that
function, argument values are to be passed.

Just take a note of the use of (.) dot-operator in-between the object-name and the
function-name.

4.8 Concept of this

Sometimes a function needs to refer to a particular object, which is allowed to invoke it.
The this keyword can be used for that purpose. This refers to an object currently being used.
This can also be used as a reference to an object’s instance variable that can have different
reference for different object being created out of the same class type.

// Example-4.5 An Example of the use of this

class ThisDemo
{
// instance variables
int age;
double fare;

public void setAge(int yrs) {


if (yrs <5) {
this.fare = 0.0;
}
else {
this.fare = 125.0;
}
}

public void issue( int ag, double price) {

System.out.println ("Age " + ag + " years");


System.out.println ("Fare to pay :" + price);
}
}

public class PassTicket{

public static void main(){


ThisDemo passenger = new ThisDemo(); // passenger object created
passenger.age = 25;
passenger.setAge(passenger.age);
System.out.println (" Issue Ticket");
passenger.issue (passenger.age, passenger.fare);

ThisDemo child = new ThisDemo(); // child object created


child.age =3;
child.setAge(child.age);
System.out.println (" Ticket Unnecessary!!");
child.issue (child.age, child.fare);

}
}
Picture 4.3 Outputs of example-4.5

In example-4.5, this has been used to refer to the currently active object – either
passenger or child. The use of this keyword becomes essential when instance variables of
multiple categories of objects try to access the same method or function.

The keyword this can be used to hide local variables inside a method having the
same name as that of the class’s instance variables. In fact, this refers directly to the object.
So it can be used to resolve any name space conflict that might occur between instance
variables and local variables.

In example-4.5, the class methods are coded with this keyword, but the main ()
method invokes them with the objects’ instance variables. This just returns reference to the
currently used object. Here, this refers first to the passenger object and then to the child
object according to the reference of the object being used.

A word of caution: Programmers must be careful in using local variables and formal
parameter names so that no hidings of instance variables can occur.

4.9 Argument Passing in Functions

There are two ways of passing an argument to a function – call-by-value and call-by-
reference. In the first case, the value of an argument is directly copied into slot of the formal
parameter. So there will be no side effects due to such parameter passing.

On the other hand, in call-by-reference, a reference (i.e. address) to an argument is


passed to the parameter slot. This reference is then used to access the actual argument
specified. Java allows both the methods of argument passing.

4.9.1 Call-by-Value

When a simple primitive type data (like int, double, float, boolean, char, etc) is passed to
a method or function, call-by-value is used. The actual benefit of call-by-value is that call
does not put the value in the location where the original function resides, but the value
change occurs only inside a copy of that function. Thus original definition with any
argument values remain unaffected.

// Example-4.6 Use of call-by-Value

public class Test {


void method(int i, int j) {
i = i * 5;
System.out.println ("Value of i within test method:" + i);
j = j / 3;
System.out.println ("Value of j within test method:" + j);
}
}

public class CallByVal {


public static void main() {
int x = 4;
int y = 21;
System.out.println("Values of x & y before Call :: " + x + " " + y);
Test obj1 = new Test();
obj1.method(x,y); // calling method with values x=4 and y=21
System.out.println(" Values of x & y after Call :: " + x + " " + y);
}
}

If you run this program, the following output will appear in the Terminal Window –

Values of x & y before Call:: 4 21


Value of i within test method: 20
Value of j within test method : 7
Values of x & y after Call:: 4 21

This shows that call-by-value does not cause any change in the values of x and y
used in the call.

4.9.2 Call-by-Reference

Any object can be passed to a method or function using call-by-reference. Since


reference points to the address of an object including its methods inside, any change
in the methods internal value will cause a change in the state of that object. So call-
by-reference will give rise to side effects.

// Example-4.7 Use of Call-By-Reference

class TestRef {
int a,b;
TestRef (int i, int j) {
a = i;
b = j;
}
void method( TestRef objRef) {
objRef.a *= 3;
objRef.b += 10;
}
}

public class CallByRef {


public static void main() {
TestRef obj2 = new TestRef(10, 25);
System.out.println (" Values of obj2.a & obj2.b before Call:: " + obj2.a + " " + obj2.b);
obj2.method ( obj2);
System.out.println (" Values of obj2.a & obj2.b after Call:: " + obj2.a + " " + obj2.b);
}
}

If you run this program, the Terminal window will show the following (picture 4.4) –

Picture 4.4 Outputs of example-4.7

4.9.3 Side Effects of Call-by-Reference

You have just observed that passing argument using call-by-reference gives rise to a
change in the parameter reference. Within the parameter slot -- a reference address
pointing to data is put and not the actual data value. This can cause the side effects.

If the data value in the pointed location gets changed, the value accessed by the reference
pointer reads the changed value, not the value stored earlier. Whenever any argument is
passed to an object, side effects are bound to occur because objects are bound by
references. Java programmers should always remain careful about such side effects.
4.10 Conclusions

In a function oriented language, like C, both data and functions have isolated existence
within a program. But in Java, functions or methods remain enclosed together with data
members within a class or object and only those functions are capable of manipulating any
inside data member. This feature hides the internal details of an object but allows external
class/objects to interact through function interface by passing messages. These interfacable
functions of a class can be of either pure type or impure type.

A pure function does not cause any change in the state of an object, which means that the
called function does not cause a change in the values of instance variables. So pure functions
can be safely declared as public.

An impure function causes a change in the state of an object; so proper protection


mechanism using appropriate access specifier should be used.

The difference between function prototype and function signature has been explained with
examples.

The importance of this keyword is also demonstrated.


The concept of function overloading has been thoroughly explained and illustrated.

Argument passing is another very important aspect of any function call. Argument(s) can be
passed using either call-by-value or call-by-reference technique.

Call-by-value has no side effect; but call-by-reference gives rise to side effects.
A programmer must keep this point in mind. Call-by-value can be used with simple primitive
data types, but call-by-reference is got to be used for complex data types like object(s).

Potrebbero piacerti anche