일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |
- Binary Tree
- Method
- Tree
- 코딩테스트
- dynamic programming
- 파이썬
- Data Structure
- greedy
- two pointers
- geometry
- string
- database
- 자바
- java
- Number Theory
- Math
- hash table
- Matrix
- implement
- Binary Search
- sorting
- bit manipulation
- SQL
- Stack
- 구현
- array
- 코테
- Counting
- Class
- simulation
- Today
- Total
코린이의 소소한 공부노트
메서드의 생성(선언)과 사용(호출) 본문
메서드는 객체지향 언어에서 쓰는 말로, 작업 단위로 문장들을 묶어서 이름 붙인 것이다. 함수는 클래스에서 독립적으로 있을 수 있는 반면 메서드는 클래스 안에 존재해야 한다. 이런 차이가 있긴 하나, 결과적으로 함수와 메서드는 같은 말이다.
메서드를 왜 사용하는지 배열의 모든 요소를 2번 출력하는 상황을 보자.
- 왼쪽 코드: 출력할 때마다 for문 사용
- 오른쪽 코드: 배열 요소를 출력하는 메서드를 만들어 놓고 메인 메서드에서 메서드 호출(사용) <- printArr(arr);
- 코드의 길이는 (그림상에서는) 왼쪽 < 오른쪽
- 왼쪽의 경우 for문을 다 훑어봐야 무슨 작업인지 알 수 있음
- 오른쪽의 경우 메서드 이름만 봐도 어떤 작업을 하는 메서드인지 알 수 있음
- 배열의 요소를 앞에서부터 50개까지만 출력하는 형식으로 바꾸려면 왼쪽은 2번, 오른쪽은 1번 수정해야 함
여기까지만 봐도 메서드를 사용하는 것이 훨씬 좋다는 게 느껴질 것이다. 지금부터 자세히 설명하겠다.
[메서드의 장점]
1. 코드의 중복을 줄일 수 있다.
- 같은 작업을 수행하는 코드를 1번만 쓰면 됨
- if 중복 제거가 안됨 -> 수정이 필요할 때 모든 중복 코드를 다 찾아서 일일이 수정 -> 관리가 어려움
2. 코드 관리가 쉽다.
- 메서드를 한 곳에 써놓고 사용하기 때문에, 메서드 수정이 필요한 경우 여러 군데에서 메서드 호출을 해도 1군데만 수정하면 됨(=코드의 유지보수성이 좋음)
3. 코드를 재사용할 수 있다.
- 필요할 때 몇 번이든 호출해서 쓸 수 있음
- 재사용성이 올라갈수록 코드가 간결해지고 이해하기 쉬워진다.
[메서드의 작성법]
메서드는 클래스 영역에만 정의가 가능하고, 선언부와 구현부로 이루어져 있다. 선언부에는 입력과 출력이 설명되어있고, 구현부는 메서드의 기능을 실행한다.
class Mathfunc{
int add(int x, int y) {
int result = x + y;
return result;
}
}
1. 선언부: 반환타입 메서드이름 (타입 변수명, 타입 변수명, ...)
int add(int x, int y)
1) 반환타입: 메서드 작업 후 반환할 타입(output)
- 반환 값은 1개가 기본 -> 타입도 1개만 작성
- 만약 반환할 것이 없다면 void로 쓰기
- 만약 반환할 것이 2개 이상이라면, 배열 등의 객체에 결과를 담아서 반환타입으로 쓰기
- 참조형 반환타입에 대한 설명은 링크 제일 아래 >> 2022.03.06 - [Java] - 메서드의 매개변수
2) 메서드이름: 메서드 호출 시 사용할 이름
- 1개의 메서드는 1개의 기능만 수행하게 짜는 것이 일반적
- 그 기능이 잘 드러나게 메서드 이름 작성
3) 매개변수(parameter): 메서드 내부에서 쓸 지역 변수(input)
- 호출하는 메서드와 호출받는 메서드의 중간 역할을 한다고 해서 매개변수라고 부름
- 어떤 값을 받아서 작업해야 한다면 매개변수로 타입과 변수명을 선언해주기
- 매개변수의 개수는 딱히 제한 없음 -> 0개여도 상관없음. 여러 개는 콤마, 로 구분 짓기
- 매개변수는 자동 형변환이 가능함
- 기본형, 참조형 관계없이 올 수 있음
2. 구현부: { // 메서드 호출 시 수행될 코드 }
{
int result = x + y;
return result;
}
1) 프로그램에서 반복적으로 수행되는 여러 문장을 메서드로 작성
2) 모든 문장을 수행하거나 return문을 만나면 호출한 메서드(main)로 돌아감
- 반환타입이 void면 return문 생략 가능. 필요시 사용
- 반환타입이 void가 아니라면 반드시 return문 사용
- return문이 조건식이 참일 때만 실행된다면 에러 발생
-> 조건식이 거짓일 때도 return문이 있도록 작성해야 함
예를 들어, 두 정수를 받아 더 큰 값을 반환하는 함수를 만들었다고 해보자.
int findBigger(int x, int y) {
if (x>y)
return x; // error: This method must return a result of type int
}
사람이 봤을 때, 반쪽짜리 구현이라 당연히 이상하게 느낄 것이다. 컴파일러는 이것을 return문이 없다는 에러로 표현한다. 조건식이 거짓일 때 return문이 없기 때문이다.
int findBigger(int x, int y) {
if (x>y)
return x;
else
return y;
}
이제 좀 편안해졌다.
[메서드가 여러 개의 기능을 수행하게 작성하면 안 되는 이유]
1. 메서드 이름을 직관적이게 만들기 어려움
2. 재사용성이 떨어짐
- A 메서드는 a, b를 수행하고 B 메서드는 a만 수행한다고 할 때, a가 주 기능이라고 한다면 B 메서드를 더 많이 사용
-> A 메서드의 재사용성이 떨어짐
3. 유지보수성이 떨어짐
- A 메서드에 기능이 3가지가 있는데, 그중 하나를 수정하게 되면 다른 기능도 수정하게 될 가능성이 커짐
[메서드의 호출(call)]
작성만 하면 메서드가 실행되지 않는다. 호출을 해줘야 메서드 구현부가 실행된다.
1. 메서드이름();
- 입력 값이 필요 없을 때의 호출법
2. 메서드이름(입력값1, 입력값2, ...);
- 입력 값이 필요할 때의 호출법
- 매개변수에는 변수 or 값을 입력
- 입력으로 넘긴 값이 메서드의 매개변수에 대입됨
- 입력값으로 넘기는 매개변수의 개수 = 메서드 선언 시 설정해놓은 매개변수의 개수
작업을 마치면 호출한 곳으로 돌아오고, 이때 반환 값이 있을 경우 그 값을 같은 타입의 변수에 저장할 수 있다. 반환 값이 있는데 변수에 저장을 하지 않아도 에러는 발생하지 않는다.
[메서드 선언 후 호출 시 일어나는 일]
입력 값의 여부, 반환 값의 여부에 따라 메서드 호출 시 어떤 일이 일어나는지 하나하나 살펴보자.
1. Mathfunc 클래스에 4가지 메서드를 선언했다.
class Mathfunc {
// 입력O, 반환O
double sub(double x, double y){
double result = x-y;
return result;
}
// 입력X, 반환O
double givemePi() { return 3.14; }
// 입력O, 반환X
void printPlus1(int x) {
System.out.println(x+1);
}
// 입력X, 반환X
void printMath() {
System.out.println("What a wonderful Math!");
}
}
2. 각각의 메서드를 활용하기 위해 메인 메서드에서 객체를 생성한다.
public static void main(String args[]) {
Mathfunc mf = new Mathfunc();
}
3. 이제 메인 메서드에서 각 메서드를 호출하고, 결과를 확인해보겠다.
1) 반환O, 입력O
double result = mf.sub(6, 8); // int로 넘겼지만 double로 자동 형변환
System.out.println(result); // -2.0
class Mathfunc {
double sub(double x, double y){
double result = x-y;
return result;
}
}
메인이 sub을 호출하며 6과 8을 넘김
-> x=6.0, y=8.0 대입 후 6.0-8.0을 계산하여 -2.0를 result에 저장
-> 메인으로 -2.0이 반환되어 result에 대입되고, println문에서 -2.0 출력
# 변수 result의 중복
- sub 메서드에도, main 메서드에도 int 타입의 변수 result가 존재
- 지역 변수의 유효 범위는 메서드 내부
- 따라서 이름이 같아도 다른 메서드 영역에 있기 때문에 다른 것으로 취급
2) 반환O, 입력X
double myPi = mf.givemePi();
System.out.println(myPi); // 3.14
class Mathfunc {
double givemePi() { return 3.14; }
}
메인이 givemePi를 호출
-> 3.14를 반환함
-> 3.14가 myPi에 대입되고, println문에서 3.14 출력
3) 반환X, 입력O
mf.printPlus1(5); // 6
class Mathfunc {
void printPlus1(int x) {
System.out.println(x+1);
}
}
메인이 printPlus1을 호출하며 5를 넘김
-> x=5가 대입되고, println문에서 5+1을 계산 후 6 출력
4) 반환X, 입력X
mf.printMath(); // "What a wonderful Math!"
class Mathfunc {
void printMath() {
System.out.println("What a wonderful Math!");
}
}
메인에서 printMath 호출
-> println문에서 문구 출력
>> 메서드의 실행 흐름: 메서드 선언 -> main에서 객체 생성 -> 메서드 호출 -> 메서드 구현부 실행 -> 반환타입에 따라 값 반환 or 구현부 실행 끝 -> main으로 돌아옴
[쿠키글] 리팩터링(refactoring)
코딩을 하다 보면 처리는 간단한데 일일이 쓰기 귀찮은 작업이 생긴다. 그럴 때 쓰라고 만들어둔 것이 메서드이다.
예를 들어, 0부터 9 사이의 숫자 중 랜덤으로 2개를 골라 그 정수를 각각 십의 자리와 일의 자리로 하는 정수 값이 필요하다고 해보자. 그럼 아래처럼 메서드 하나를 간단하게 만들 수 있다.
int into2digits(int x, int y) {
int result = 10*x + y;
return result;
}
십의 자리와 일의 자리 숫자를 받으면 그 2자리 수의 값을 반환하는 메서드이다. 지금도 충분히 간단해 보이지만, 더 간단하게 만들 수도 있다.
int into2digits(int x, int y) {
return 10*x + y;
}
이렇게까지 할 일인가 싶지만, 절대 무시할 수 없는 작업이다!
리팩터링 전에는 입력받기 - 변수 선언 - 계산 - 변수에 저장 - 해당 변수에 저장된 값 불러오기 - 반환의 6가지 과정을 거쳐야 한다면, 리팩터링 후에는 입력받기 - 계산 - 반환의 3가지 과정만 거치면 되기 때문에 여러 번 메서드 호출이 일어나게 되면 훨씬 빠른 계산이 가능하다.
너무 간단한 작업이긴 하지만, 메서드 예시에 나왔던 add, findBigger, sub메서드도 리팩터링을 한다면 다음과 같이 된다.
int add(int x, int y) {
return x + y;
}
int findBigger(int x, int y) {
return x>y ? x : y;
}
double sub(double x, double y){
return x - y;
}
'Java' 카테고리의 다른 글
메서드의 매개변수 (0) | 2022.03.06 |
---|---|
메서드의 호출 스택 (0) | 2022.03.05 |
선언 위치에 따른 변수의 종류 (0) | 2022.03.03 |
클래스의 정의 (0) | 2022.03.02 |
객체 배열 (0) | 2022.03.01 |