Method = 함수(function)
👩🏻💻 특정 작업을 수행하는 일련의 문장들을 하나로 묶은 것
👩🏻💻 기본적으로 수학의 함수와 유사하며, 어떤 값을 입력하면 이 값으로 작업을 수행해서 결과를 반환
👩🏻💻 main 메서드는 '규칙'. 이 메서드 안에 실행되기를 기다리는 로직을 위치시켜야 한다.
1) 메서드의 장점과 작성지침
· 반복적인 코드를 줄이고 코드의 관리가 용이.
· 반복적으로 수행되는 여러 문장을 메서드로 작성.
· 하나의 기능을 위해 작성한 여러 코드를 하나의 단어로 표현할 수 있음. (추상화)
· 하나의 메서드는 한 가지 기능만 수행하도록 작성하는 것이 좋음.
· 메서드는 특정 동작을 하는 코드이기 때문에 이름을 동사로 시작 ex. getAge ()
2) 메서드 용어
· 인수 (argument) : 메서드에 전달할 입력(input)을 의미
· 매개변수 (parameter) : 인수를 받아서 저장하는 변수를 의미
· 반환값 (return) : 메서드의 출력(output)을 의미.
⚡️ return의 기능 1) 값을 반환 2) 함수를 종료 (반복문의 break와 비슷)
· 메서드 호출 : 메서드를 실제로 사용하는 것을 의미
사용 예제
📍 3명의 신장, 체중, 나이의 최대값을 구해서 표시
✔️ 메서드를 만들면 1) 소스가 줄어들어서 main 메서드의 기본 로직을 읽기 쉽고 2) 재사용을 할 수 있다
public class MyMethod_01 {
static Scanner scanner = new Scanner(System.in);
static int getMax(int a, int b, int c) { // a,b,c의 최대값을 반환
int max = a;
if(b > max) max = b;
if(c > max) max = c;
return max;
}
static void inputData(int[] height, int[] weight, int[] age) {
for (int i = 0; i < 3; i++) {
System.out.print("[" + (i+1) + "] ");
System.out.print("신장: "); height[i] = scanner.nextInt();
System.out.print(" 체중: "); weight[i] = scanner.nextInt();
System.out.print(" 나이: "); age[i] = scanner.nextInt();
}
}
public static void main(String[] args) {
// 3명의 신장, 체중, 나이의 최대값을 구해서 표시.
int[] height = new int[3]; // 신장
int[] weight = new int[3]; // 체중
int[] age = new int[3]; // 나이
inputData(height, weight, age);
/* // 신장의 최대값을 구한다
int maxHeight = height[0];
if (height[1] > maxHeight) maxHeight = height[1];
if (height[2] > maxHeight) maxHeight = height[2];
// 체중의 최대값을 구한다
int maxWeight = weight[0];
if (weight[1] > maxWeight) maxWeight = weight[1];
if (weight[2] > maxWeight) maxWeight = weight[2];
// 나이의 최대값을 구한다
int maxAge = age[0];
if (age[1] > maxAge) maxAge = age[1];
if (age[2] > maxAge) maxAge = age[2]; */
int maxHeight = getMax(height[0], height[1], height[2]); // 신장의 최대값
int maxWeight = getMax(weight[0], weight[1], weight[2]); // 체중의 최대값
int maxAge = getMax(age[0], age[1], age[2]); // 나이의 최대
System.out.println("신장의 최대값은 " + maxHeight + "입니다." );
System.out.println("체중의 최대값은 " + maxWeight + "입니다." );
System.out.println("나이의 최대값은 " + maxAge + "입니다." );
}
}
사용 예제 2
public class MyMethod_03 {
static int getMax(int a, int b) { // a,b의 최대값을 반환
// return이 여러번 나와도 된다.
System.out.println("함수 시작");
if(a>b)
return a;
else
return b;
// System.out.println("함수 종료") -> return 때문에 함수가 종료되기 때문에 출력되지 않음.
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("정수 a : ");
int a = scanner.nextInt();
System.out.print("정수 b : ");
int b = scanner.nextInt();
System.out.println("최대값은 " + getMax(a,b) + "입니다.");
scanner.close();
}
}
3) 메서드의 선언과 구현
🚀 메서드는 크게 두 부분 '선언부(header, 머리)'와 '구현부(body, 몸통)'로 이루어져 있다.
반환타입 메서드이름 (타입 변수명, 타입 변수명, ...)
{
// 메서드 호출시 수행될 코드
}
int add (int a, int b) {
int result = a + b ;
return result; // 호출한 메서드로 결과를 반환한다.
}
메서드 선언부 (method declaration, method header) |
- '메서드의 이름'과 '매개변수 선언' 그리고 '반환타입'으로 구성되어 있다. - 메서드가 작업을 수행하기 위해 어떤 값들을 필요로 하고 작업의 결과로 어떤 타입의 값을 반환하는지에 대한 정보를 제공 |
매개변수 선언 (prameter declaration) |
- 매개변수는 메서드가 작업을 수행하는데 필요한 값들(입력)을 제공받기 위한 것이며, 필요한 값의 개수만큼 변수를 선언. - 각 변수 간의 구분은 쉼표 ',' 를 사용. 두 변수의 타입이 같아도 변수의 타입을 생략하는 것 불가. ex. int add ( int x, y) {...} // 에러. 매개변수 y의 타입이 없다. |
메서드의 이름 (method name) |
- 특정 작업을 수행하므로 메서드의 이름은 'add' 처럼 동사인 경우가 많다. |
반환타입 (return type) |
- 메서드의 작업수행 결과(출력)인 '반환값(return value)'의 타입을 적는다. - 반환값이 없는 경우 'void' |
메서드의 구현부 (method body) |
- 메서드의 선언부 다음에 오는 괄호{}를 '메서드의 구현부'라고 . - 메서드를 호출했을 때 수행될 문장들을 넣는다. |
return 문 | - 메서드의 반환타입이 'void'가 아닌 경우, 구현부{} 안에 'return 반환값;'이 반드시 포함되어 있어야 한다. - 이 문장은 반환값을 호출한 메서드로 전달. - 이 값의 타입은 반환타입과 일치하거나 적어도 자동 형변환이 가능한 것이어야 한다. - 단 하나의 값만 반환할 수 있음. |
지역변수 (local variable) |
- 메서드 내에 선언된 변수들은 그 메서드 내에서만 사용할 수 있으므로 서로 다른 메서드라면 같은 이름의 변수를 선언해도 된다. - 이처럼 메서드 내에 선언된 변수를 '지역변수'라고 한다. |
public class ExMethod_02 {
public int add(int a, int b) {
int c = a + b;
return c;
// return 다음에 위치하는 데이터는 반드시 메서드의 리턴 타입과 일치해야 함.
// return 3.5; // 리턴 타입과 다른 데이터형을 반환하면 오류가 발생. (자동 형변환은 가능)
}
public static void main(String[] args) {
int numb1 = 10;
int numb2 = 20;
int result = 0;
ExMethod_02 method = new ExMethod_02();
result = method.add(numb1, numb2);
System.out.println("두수의 합은 " + result); // 메서드의 반환 값을 저장해서 출력.
System.out.println("두수의 합은 " + method.add(numb1, numb2)); // 메서드의 반환 값을 바로 출력
}
}
4) 메서드의 호출
인자(argument)와 매개변수(parameter)
int result = add(1,2,3); // 에러. 메서드에 선언된 매개변수의 개수가 다름
int result = add(1.5, 2.3); // 에러. 메서드에 선언된 매개변수의 타입이 다름
- 인자의 개수와 순서는 호출된 메서드에 선언된 매개변수와 일치해야 한다.
- 인자는 메서드가 호출되면서 매개변수에 대입되므로, 인자의 타입은 매개변수의 타입과 일치하거나 자동형변환이 가능한 것이어야 함.
반환 타입
- 반환타입이 void가 아닌경우, 메서드가 작업을 수행하고 반환한 값을 대입연산자로 변수에 저장하는 것이 보통이지만, 저장하지 않아도 문제가 되지 않는다.
메서드의 실행흐름
- main 메서드에서 메서드 getAge를 호출
- 호출시 지정한 인자들이 메서드 getAge의 매개변수 a,b에 각각 복사(대입)
- 메서드 getAge의 괄호 {} 안에 있는 문장들이 순서대로 수행
- 메서드 getAge의 모든 문장이 실행되거나 return문을 만나면, 호출한 메서드(main메서드)로 되돌아와서 이후의 문장들을 실행
⚒️ 메서드 호출방식
A. 값에 의한 호출
- 값에 의한 메서드 호출 방식은 메서드 호출 시에 값이 복사되어 전달
- 메서드의 매개변수 타입이 '기본형 데이터' 일 때 값에 의한 호출을 함.
💡 값 형식 (Value Type)
- 변수가 값을 담은 데이터 형식, 스택 메모리 영역과 관련.
- 코드 블록 안에서 생성된 모든 값 형식의 변수들은 프로그램 실행이 중괄호 "}"를 만나면 메모리에서 제거
public class CallByValue {
static public int increase(int n) {
++n;
return n;
}
public static void main(String[] args) {
int var1 = 100;
int result = increase(var1);
System.out.println("var1: " + var1 + ", result: " + result);
}
}
- 메서드 increase() 호출 시에 n이라는 매개변수가 메모리에 생성되어 var1의 값인 100 이 복사되어 처리
- 메서드 실행이 종료되면 매개변수 n은 메모리에서 소멸
- 이 처럼 값에 의한 호출은 호출시 매개변수로 전달되는 값이 복사되어 전달. 따라서 var1의 값은 변하지 않음
B. 참조에 의한 호출
- 매개변수의 타입이 참조형 타입일 때 사용, 참조에 의한 호출은 메서드 호출 시 참조 데이터의 위치가 매개변수에 전달
- 값에 의한 호출은 메모리에 동일한 값을 복사 후 사용하지만 참조에 의한 호출은 메모리의 주소를 넘기기 때문에 값을 복사하지 않음
💡 참조 형식 Reference Type
- 변수가 값 대신 값이 있는 곳의 위치(참조)를 담는 데이터 형식, 힙 메모리 영역과 관련
- 힙 영역에 데이터를 저장하고, 스택 영역에는 데이터가 저장된 힙 메모리의 주소를 저장
- 가비지 컬렉터가 프로그램 뒤에 숨어 동작하면서 힙에 더 이상 사용하지 않는 객체가 있으면 그 객체를 쓰레기로 간주하고 수거하는 기능을 함
ex. class, interface, delegate, object, string
public class CallByRef {
public static void increase(int[] array) {
/* 배열을 매개변수로 받아서, 원래 저장된 값보다 1이 증가한 값으로 업데이트 */
for(int i = 0; i < array.length; i++) {
array[i]++;
}
}
public static void main(String[] args) {
int[] refArray = {100, 800, 1000}; // 배열 선언 및 초기화. 배열은 참조형 데이터
System.out.println("메서드 호출 전");
for(int i = 0; i < refArray.length; i++) {
System.out.println("refArray[" + i + "]: " + refArray[i]);
}
increase(refArray); // 리턴이 없음.
System.out.println();
System.out.println("메서드 호출 후");
// 배열은 참조형이라 메서드 호출 후 값이 변경.
for(int i = 0; i < refArray.length; i++) {
System.out.println("refArray[" + i + "]: " + refArray[i]);
}
}
}
C. 문자열에 의한 호출
- 예외적으로 문자열을 전달하려면 참조형 데이터라도 값에 의한 호출을 함. 값에 의한 호출이기 때문에 값을 변경할려면 변경된 문자열을 리턴하고 호출한 쪽에서 값을 저장하면 됨
public class CallByString {
public static String setAddress(String addr) {
addr = "경기도 수원시 장안구";
return addr;
}
public static void main(String[] args) {
String address = " 서울시 강남구 논현동";
System.out.println("메서드 호출 전");
System.out.println("address: " + address); // address: 서울시 강남구 논현동
address = setAddress(address);
System.out.println("메서드 호출 후");
System.out.println("address: " + address); // address: 경기도 수원시 장안구
}
}
값 복사 VS 참조 복사
public class MyMethod_04 {
public static void main(String[] args) {
/* 깊은 복사. 값 복사. 기본형 변수
* deep copy
* 데이터 자체가 복사된다.
* 복사된 두 객체는 완전히 독립적인 메모리를 차지.
*/
int a = 1;
int b = a;
b++;
System.out.println("a: " + a + ", b: " + b); // a: 1, b: 2
/* 얕은 복사. 참조 복사. 참조형 변수
* shallow copy
* 값 자체를 복사하는 것이 아니라 주소값을 복사하여 같은 메모리를 가리키기 때문.
*/
int[] nums_01 = new int[1];
nums_01[0] = 1;
int[] nums_02 = nums_01;
nums_02[0] = 2;
System.out.println("nums_01[0]: " + nums_01[0] + ", nums_02[0]:" + nums_02[0]);
// nums_01[0]: 2, nums_02[0]:2
}
}
5) return 문
- 현재 실행중인 메서드를 종료하고 호출한 메서드로 되돌아간다.
- 반환타입이 void 인 경우, return문 없어도 문제가 되지 않는다 ➡️ 컴파일러가 메서드의 마지막에 자동적으로 추가해주기 때문
- 결과로 사용되는 유형 : void, 기본자료형, 클래스형 등
public class ExMethod {
public void print() {
System.out.println("메서드를 호출한다");
// 리턴 타입이 없더라도 return을 사용할 수 있음.
// 다만 return 다음에 값이 없어야 함.
// return의 의미는 이 부분에서 메서드 실행을 종료하고 복귀한다는 의미.
// return;
}
public static void main(String[] args) {
// 사용할 메서드가 있는 클래스의 인스턴스 선언
ExMethod method = new ExMethod();
method.print();
method.print();
method.print();
}
}
반환값(return value)
int add(int x, int y) {
int result = x + y;
return x+y;
}
- 반환값으로 주로 변수가 오긴 하지만 위의 코드처럼 'x+y' 수식이 올 수 있다. (수식의 결과가 반환됨)
- 간단한 메서드의 경우 if문 대신 조건연산자(ex. 삼항연산자)를 사용하기도 함.
매개변수의 유효성 검사
- 메서드의 구현부{}를 작성할 때, 제일 먼저 해야 하는 일이 매개변수의 값이 적절한 것인지 확인하는 것
➡️ 타입만 맞으면 어떤 값도 매개변수를 통해 넘어올 수 있기 때문.
- 적절하지 않은 값이 매개변수를 통해 넘어온다면 매개변수의 값을 보정하던가, 보정하는 것이 불가능하다면 return문을 사용해서 작업을 중단하고 호출한 메서드로 되돌아가야 한다.
예제 문제
📍 밑변이 30, 높이가 10인 사각형의 넓이를 출력하세요
* 단 메서드 calculator()를 호출해서 출력하세요
public class Ex_01_01 {
public static void main(String[] args) {
int width = 30;
int height = 10;
System.out.println("밑변이 "+ width + " 높이가 " + height + "인 사각형의 넓이는 " + calculator(width,height) + "입니다.");
}
static int calculator(int a, int b) {
System.out.println("계산을 시작합니다.");
int area = a * b; // 밑변 * 높이 = 사각형의 높이
return area;
}
}
직각 삼각형 만들기
public class Ex_01_02 {
/*
* 별이 출력되는 부분은 putStars() 메서드를 정의해서 구현하세요.
* 몇 단 : 4
* *
* **
* ***
* ****
*/
static void putStars(int limit) {
for( int i = 1; i <= limit; i++) {
System.out.print("*");
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("좌하변이 직각인 직각삼각형을 표시합니다.");
System.out.print("몇 단 : ");
int n = scanner.nextInt();
for(int i = 1; i <= n; i++) {
//putStars() 메서드 호출
putStars(i);
System.out.println();
}
scanner.close();
}
}
6) 메서드 종류
매개변수, 반환 값 모두 있는 경우
int method(int a) { int b; return b; }
매개변수는 있는데, 반환 값이 없는 경우
void method(int a) { }
매개변수는 없는데, 반환 값이 있는 경우
int method() { int b; return b; }
매개변수, 반환 값 모두 없는 경우
void method() { }
* 내용 참고 : 학원강의 및 자바의정석 3rd
'Programming Language > JAVA' 카테고리의 다른 글
[Java] 객체 지향 프로그래밍 (OOP) · 객체와 클래스 · 필드 (0) | 2024.08.10 |
---|---|
[Java] JVM 메모리 구조 · 오버로딩 (0) | 2024.08.09 |
[Java] Array | 배열의 활용 · 2차원 배열 (0) | 2024.08.09 |
[Java] Array | 배열 선언과 생성 · 배열 길이와 인덱스 · 배열 초기화 · 배열 출력 (0) | 2024.08.09 |
[Java] while 문 · break문 · continue 문 (0) | 2024.08.09 |