Methods: parameters and return values
Giving objects behavior, passing values in, getting values back, and how arguments are copied.
Finished reading?
Mark this session so you can track where you are.
Giving objects behavior, passing values in, getting values back, and how arguments are copied.
Finished reading?
Mark this session so you can track where you are.
Last time you gave an object some data: a Rectangle that knows its width and height, aCounter that holds a number. But an object that only holds data is half an object. The other half is what it can do. This session is about giving objects behavior, the actions that live right next to the data they work on.
return to pass one back out.void means and when a method should have it.new, and to read and set those fields with the dot. You also know variables and types. That is everything you need. We will not touch constructors or inheritance yet; this session is only about methods.Here is a Rectangle class from last session, with two fields. Suppose we want its area. Width times height. We could compute that out in main, but the area of a rectangle is so obviously a thing a rectangle does that it belongs inside the class, sitting right next to the data it needs.
An action that lives inside a class is called a method. You have already met one:main is a method. Now we write our own. Read this, then press Run.
public class Main { public static void main(String[] args) { Rectangle r = new Rectangle(); r.width = 4; r.height = 3; int a = r.area(); System.out.println("Area is " + a); }} class Rectangle { int width; int height; int area() { return width * height; }}Area is 12
That prints Area is 12. Look closely at the method, because every method you ever write has the same four parts.
Reading the line int area() from left to right:
int): the type of value this method hands back to whoever called it. Here it gives back a whole number.area): what you call it by. Lowercase first letter, by convention, and usually a verb or a noun that reads like an action.()): the values the method needs handed in. This one needs nothing extra, so the parentheses are empty. We add some shortly.{ ... }): the code that runs when the method is called.A method is a named action that belongs to a class. It has a return type, a name, a list of parameters, and a body. Every method, including
main, fits this same shape.
def area(self): and in C a plain function int area(...). Java is close, with one big difference: a method lives inside a class, glued to the data it works on. There are no free-floating functions in Java the way there are in C. Everything is a method of some class.You call a method with the dot, the same dot you used to reach a field. r.area()reads as “run the area action belonging to r”. The parentheses are how you say “do it now”.
Now notice something inside the method body. It says width * height, notr.width * r.height. There is no r in sight. How does it know whose width to use? When you call r.area(), the method runs on r, so a bare widthinside the body means “the width of the object I was called on”. The object is already talking about itself.
public class Main { public static void main(String[] args) { Rectangle small = new Rectangle(); small.width = 2; small.height = 2; Rectangle big = new Rectangle(); big.width = 10; big.height = 5; System.out.println("small area: " + small.area()); System.out.println("big area: " + big.area()); }} class Rectangle { int width; int height; int area() { return width * height; }}small area: 4 big area: 50
One method, written once. Called on small it uses small's fields and gives 4. Called on big it uses big's fields and gives 50. The body is shared, but each call works on its own object. This prints small area: 4 then big area: 50.
this, and it matters when names collide. You do not need it yet, because nothing here is ambiguous. We give it a full session soon: the this keyword and object references. For now, “a bare field name means my own field” is the right picture.area only reads the fields. A method can also change them. Here is a Counter whose whole job is to hold a number and bump it up by one. The bumping is an action: increment. Press Run, and watch the count field inside the object in the object view. It is the same object both times; the number changes underneath it.
public class Main { public static void main(String[] args) { Counter c = new Counter(); c.increment(); c.increment(); System.out.println("Count is " + c.count); }} class Counter { int count; void increment() { count = count + 1; }}Count is 2
This prints Count is 2. The field count starts at 0 (an int field with no value set is 0, as you saw last session). The first increment() makes it 1, the second makes it 2. The line count = count + 1reads the object's own count, adds one, and stores it back into that same field.
But look at the front of increment. It does not say int, it says void. That is the thing to learn next.
void is the return type you write when a method does its job but has no value to give you. increment changes the counter; there is no number to return. area, by contrast, exists precisely to give you a number, so it returns an int. The return type is your promise about what comes back out.
void.int, double, String, and so on.c.increment();int a = r.area();return; to stop early, or none at all.return a value of the right type on every path out.increment, print, deposit.area, getBalance, toUpperCase.So far increment always adds exactly one. What if we want to add any amount? We let the caller hand a number in. A value handed into a method is passed through a parameter: a variable, declared in the parentheses, that exists only for the length of that one call.
public class Main { public static void main(String[] args) { Counter c = new Counter(); c.add(5); c.add(3); System.out.println("Count is " + c.count); }} class Counter { int count; void add(int amount) { count = count + amount; }}Count is 8
This prints Count is 8. The method now declares one parameter, int amount. When you write c.add(5), the value 5 you put in the parentheses is the argument, and it gets copied into the parameter amount for that call. So the body runs withamount equal to 5, making count 5. The next call copies 3 in, making count 8.
int amount): a named slot waiting for a value. The thing you actually pass at the call is theargument (5): the real value. Parameter is the slot, argument is what goes in it. People mix the words up constantly; you do not have to.A method can take several parameters, separated by commas, each with its own type. The arguments fill them in order, left to right.
public class Main { public static void main(String[] args) { Rectangle r = new Rectangle(); r.setSize(6, 4); System.out.println("Area is " + r.area()); }} class Rectangle { int width; int height; void setSize(int w, int h) { width = w; height = h; } int area() { return width * height; }}Area is 24
This prints Area is 24. The call r.setSize(6, 4) copies 6 into w and 4 intoh, by position, and the body stores them into the object's fields. Order matters:setSize(4, 6) would set a different rectangle.
Parameters carry values in. return carries one value out. When a method hits a return, two things happen at once: the method stops right there, and the value after return takes the place of the call. So r.area() is not just run, itbecomes the number 12 wherever you wrote it.
public class Main { public static void main(String[] args) { Greeter g = new Greeter(); String message = g.greeting("Sana"); System.out.println(message); System.out.println(g.greeting("Ravi")); }} class Greeter { String greeting(String name) { return "Hello, " + name; }}Hello, Sana Hello, Ravi
This prints Hello, Sana then Hello, Ravi. The method takes a String parameter and returns a String. The first call's result is stored in message and printed. The second call is dropped straight into println without a variable at all, because a method call that returns a value can be used anywhere that value would be allowed.
Parameters pass values into a method.
returnpasses one value back out, and the call stands in for that value.voidis the special case of passing nothing back.
Here is a question that trips up almost everyone at first. If I pass a variable into a method, and the method changes its parameter, does my original variable change too? Run this and watch carefully.
public class Main { public static void main(String[] args) { int score = 10; Tweaker t = new Tweaker(); t.tryToChange(score); System.out.println("score is still " + score); }} class Tweaker { void tryToChange(int number) { number = number + 100; System.out.println("inside the method, number is " + number); }}inside the method, number is 110 score is still 10
Read the output. Inside the method, number becomes 110. But back in main, scoreis still 10. The method's change did nothing to the caller's variable. The two lines printed are inside the method, number is 110 and then score is still 10.
The reason is the rule Java follows everywhere: pass by value. When you passscore as an argument, Java does not hand the method your variable. It copies thevalue (10) into the parameter number. From that point on, number is its own separate variable that happens to start at 10. Adding 100 changes the copy. Your original is untouched.
tryToChange is pointless as written. The fix is to return number; and have the caller writescore = t.tryToChange(score);. Returning is the only honest way to send a computed value back to where it is needed.Pass by value is the whole rule, but there is a subtlety worth a careful sentence. When you pass anobjectto a method, the value that gets copied is the reference, the object's address, not the object itself. Both the caller and the method then point at the sameobject. So the method cannot make your variable point somewhere new, but it canreach through the shared reference and change the object's fields.
public class Main { public static void main(String[] args) { Counter c = new Counter(); Bumper b = new Bumper(); b.bumpTwice(c); System.out.println("count is " + c.count); }} class Counter { int count; void increment() { count = count + 1; }} class Bumper { void bumpTwice(Counter target) { target.increment(); target.increment(); }}count is 2
This prints count is 2. The Counter we made in main and the targetinside bumpTwice are two variables pointing at one and the same counter object, so bumping through target shows up when we read c.count afterwards. This is not a different rule, it is the same pass by value: the reference got copied, but a copy of an address still points at the original.
intare copied, so a method cannot change your variable, while objects are shared, so a method can change the object's fields.Sometimes one action makes sense in more than one form. A rectangle's area takes a width and a height; a square's area takes only a side. Both are honestly called “area”. Java lets you give two methods the same name as long as their parameter lists differ. This is called overloading, and Java picks the right one by looking at the arguments you pass.
public class Main { public static void main(String[] args) { Areas calc = new Areas(); System.out.println(calc.area(3, 4)); System.out.println(calc.area(5)); }} class Areas { int area(int width, int height) { return width * height; } int area(int side) { return side * side; }}12 25
There are two methods named area. The call calc.area(3, 4) has two arguments, so Java chooses the two-parameter version and returns 12. The call calc.area(5) has one argument, so Java chooses the one-parameter version and returns 25. Same name, the argument list decides. The output is 12 then 25.
area it finds and give the wrong answer for area(5). Rather than show you a misleading trace, this snippet is presented as honest read-along code with the real Java output. When you run it in a true Java tool, you will see exactly 12 and 25.Try each one yourself first, then open the answer.
int area(), and say what each one is.void rather than int or String?c.add(5), which word is the parameter and which is the argument?t.tryToChange(score) runs, what does score print, and why?int area(int side) and int area(int width, int height). Which one runs for calc.area(7), and what does it return?Take these away. They continue exactly what we just did.
int perimeter() to the Rectangle class (it returns 2 * (width + height)). In main, set a rectangle to width 6 and height 4, then print both its area and its perimeter. Confirm you get 24 and 20.Counter two methods: void reset() that sets count back to 0, and int get() that returns the current count. Make a counter, add some amounts, print get(), then reset(), then print get() again. One method changes the object and returns nothing; the other only reads and returns a value.int max(int a, int b) on a small Math2 class that returns the larger of its two parameters using an if-else. Then overload it: add a second method, also named max, that takes three int parameters and returns the largest of the three. Call both from main and check the results by hand.int parameter cannot change the caller's variable, but a method that takes a Counter parameter can change that counter's fields. Use the words copy and reference.