안녕하세요. 작가 J입니다. 오늘은 Java 중요한 것 중 하나인 메소드에 대해서 알아보도록 하겠습니다.
제어문, 반복문에 이어 계속 중요한 것이라고 말씀을 드리고 있는데, 메소드도 실제로 Java에서 많이 사용됩니다. 반복되는 코드를 줄이고, 유지보수 시 가독성이나 재상용성에서 굉장히 유용합니다.
Java의 객체지향 파트에 들어가기 전에 꼭 필요한 개념이니, 많은 이론과 실습이 준비되어 있습니다. 천천히 가보겠습니다.
1. Java 메소드의 필요성
Java 메소드는 코드의 재사용성을 높이고, 코드의 가독성을 향상하며, 프로그램의 유지보수성을 증대시키기 위해 사용됩니다. 메소드를 사용하면 반복적인 코드를 줄일 수 있고, 특정 기능을 별도의 블록으로 분리하여 프로그램의 구조를 명확하게 할 수 있습니다.
특징:
- 코드 재사용성 증가
- 가독성 향상
- 유지보수성 증대
실생활의 예를 들자면, 요즘 자주 쓰는 레시피가 좋은 예가 될 것 같습니다. 음식 같은 걸 만들 때 우리는 매번 만드는 법을 보고 만들지 않고, 레시피 같은 걸 저장하거나 기억해 놓습니다.
라면을 끓일 때, 물 500ml 넣고 끓으면 수프를 넣고 3분간 더 끓인다. 이러한 예처럼 무언가 반복되는 행동을 할 때 코드를 반복해서 작성하는 대신, 기존에 만들어 놓은 메소드를 재사용한다고 보시면 됩니다.
2. 메소드란?
메소드는 특정 작업을 수행하는 코드 블록입니다. Java에서 메소드는 클래스 내에 정의되며, 객체의 동작을 정의합니다. 메소드는 호출되어야 실행되며, 필요한 경우 값을 반환할 수 있습니다.
특징:
- 특정 작업 수행
- 클래스 내에 정의
- 호출 시 실행
메소드의 필요성과 메소드 정의에 대해 간단한 예제를 제가 만들어 보겠습니다. 실제 현업에서 사용한 기능을 예로 들어보겠습니다.
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("코드 입력 : ");
String code = sc.next();
String name = "";
if (code.equals("A")) {
name = "인문";
} else if (code.equals("B")) {
name = "정치";
} else if (code.equals("C")) {
name = "사회";
}
System.out.println("입력한 코드는 " + name + "입니다.");
System.out.print("코드 입력 : ");
String code2 = sc.next();
String name2 = "";
if (code2.equals("A")) {
name2 = "인문";
} else if (code2.equals("B")) {
name2 = "정치";
} else if (code2.equals("C")) {
name2 = "사회";
}
System.out.println("입력한 코드는 " + name2 + "입니다.");
}
}
위 예제는 입력한 코드에 따라서 그에 따른 코드명을 출력받는 프로그램입니다. 똑같은 기능이지만, 2번 필요해서 반복되는 코드가 2번 반복되는 것을 확인할 수가 있습니다. 변수도 2개씩입니다. 이 코드를 메소드를 사용하면 아래와 같은 코드가 됩니다.
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("코드 입력 : ");
String code = sc.next();
getCode(code); // 메소드 생성
}
private static void getCode(String code) {
String name = "";
if (code.equals("A")) {
name = "인문";
} else if (code.equals("B")) {
name = "정치";
} else if (code.equals("C")) {
name = "사회";
}
System.out.println("입력한 코드는 " + name + "입니다.");
}
}
메소드인 getCode를 사용해서 반복되는 코드를 줄이고, 재 사용성을 향상했습니다. 간단하게 2번만 반복되는 코드를 줄여보았지만, 실제 일할 때는 2번보다 훨씬 많이 반복되는 코드도 있습니다. 이러한 역할을 해주는 게 메소드라고 보시면 됩니다.
3. 메소드의 기본 구조와 소스 예제
Java 메소드는 다음과 같은 구조를 가집니다.
public class MyClass {
// 메소드 정의
public int add(int a, int b) {
return a + b;
}
}
여기서 add 메소드는 두 개의 정수를 받아 그 합을 반환합니다.
특징:
- 접근제한자, 리턴타입, 메소드 이름, 매개변수로 구성
- 메소드 본문에 수행할 작업 정의
4. 메소드의 기본구조에서 접근제한자, 리턴타입, 메소드이름, 매개변수에 대한 설명
접근제한자: 메소드에 대한 접근 권한을 설정합니다. 예를 들어, public, private, protected가 있습니다.
- public: 모든 클래스에서 접근 가능
- private: 해당 클래스 내에서만 접근 가능
- protected: 동일 패키지 또는 하위 클래스에서 접근 가능
리턴타입: 메소드가 반환하는 값의 타입을 정의합니다. 반환값이 없을 경우 void를 사용합니다.
- 예: int, double, String, void
메소드 이름: 메소드를 식별하는 이름입니다. 소문자로 시작하며, 명사나 동사 형태로 짓습니다.
- 예: add, calculateSum
매개변수: 메소드가 작업을 수행하기 위해 필요한 입력값을 받습니다. 여러 개의 매개변수를 가질 수 있습니다.
- 예: int a, int b
public class MyClass {
// 접근제한자 리턴타입 메소드이름(매개변수) { 메소드 본문 }
public int multiply(int x, int y) {
return x * y;
}
}
그럼 위의 메소드는 접근 제한자가 public, 리턴타입이 int(정수형), 메소드 이름이 multiply, 매개 변수가 int x, y 인 메소드라고 보시면 됩니다.
5. 메소드 사용하는 방법
메소드를 사용하려면 객체를 생성한 후, 객체를 통해 메드를 호출합니다.
public class MyClass {
public int add(int a, int b) {
return a + b;
}
public static void main(String[] args) {
MyClass obj = new MyClass(); // 객체 생성
int result = obj.add(5, 3); // 메소드 호출
System.out.println(result); // 출력: 8
}
}
저희가 Scanner, Random 객체를 생성해 보았기 때문에, 객체는 비슷하게 생성하시면 됩니다. 그다음 위 MyClass 클래스 내에 있는 메소드 add를 호출하시면 됩니다.
저희가 실습에 들어가기 앞서 메소드를 빠르게 생성하는 방법을 알아볼까 합니다.
대신 이런 단축키나 편리 기능은 본인이 충분히 익숙해지신 다음에 사용하시길 바랍니다.
실습
풀이 :
public class Main {
public static void main(String[] args) {
add(3, 5);
sub(3, 5);
mul(3, 5);
div(3, 5);
}
private static void div(int i, int j) {
System.out.println(i / j);
}
private static void mul(int i, int j) {
System.out.println(i * j);
}
private static void sub(int i, int j) {
System.out.println(i - j);
}
private static void add(int i, int j) {
System.out.println(i + j);
}
}
풀이 :
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("정수1 입력 : ");
int num1 = sc.nextInt();
System.out.print("정수2 입력 : ");
int num2 = sc.nextInt();
char op = '-';
System.out.println(cal(num1, num2, op));
}
private static int cal(int num1, int num2, char op) {
int sum = 0; // 합계를 추출할 변수
switch (op) {
case '+':
sum = num1 + num2;
break;
case '-':
sum = num1 > num2 ? num1 - num2 : num2 - num1; // 빼기를 수행할 때는 더 큰 수에서 작은 수 빼기
break;
case '*':
sum = num1 * num2;
break;
case '/':
sum = num1 / num2;
break;
}
return sum;
}
}
기호를 메드에서 매개변수로 받아 처리만 해주면 됩니다. 빼기 연산 시 항상 큰 수에서 작은 수를 빼도록 삼항 연산자를 사용합니다.
풀이 :
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("정수1 입력 : ");
int num1 = sc.nextInt();
System.out.print("정수2 입력 : ");
int num2 = sc.nextInt();
int result = close10(num1, num2);
System.out.println("10에 가까운 수 : " + result);
}
private static int close10(int num1, int num2) {
int result = 0;
int tempNum1 = num1, tempNum2 = num2; // num1, num2 계산을 위한 임시 변수 생성
tempNum1 -= 10; // 임시변수에 -10
tempNum2 -= 10;
if (tempNum1 < 0) tempNum1 = tempNum1 * -1; // 계산 결과가 음수면 -1을 곱해 양수로 만들어주기
if (tempNum2 < 0) tempNum2 = tempNum2 * -1;
if (tempNum1 != tempNum2) { // 계산 결과가 서로 같지 않으면 작은수를 리턴
result = tempNum1 < tempNum2 ? num1 : num2;
}
return result;
}
}
두 숫자에서 - 10을 해 준 뒤에 더 작은 숫자를 구하면 됩니다.
ex) 11 - 10, 13 - 10 결과 값 1, 3로 11이 더 가깝습니다.
다만, 이 문제에서 음수는 양수로 만들어줘야 합니다.
ex) -2 - 10, 11 - 10 결괏값 -12, 1로 -12가 더 적기 때문에 오류가 나게 됩니다.
풀이 :
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("num1 입력 : ");
int num1 = sc.nextInt();
System.out.print("num2 입력 : ");
int num2 = sc.nextInt();
boolean divisor = isDivisor(num1, num2);
System.out.println(divisor);
}
private static boolean isDivisor(int num1, int num2) {
boolean isTrue = false;
if (num1 % num2 == 0) { // 나머지가 없이 완전히 나누어지면 약수
isTrue = true;
}
return isTrue;
}
}
풀이 :
public class Main {
public static void main(String[] args) {
System.out.println(getSum(44));
}
private static boolean isDivisor(int num1, int num2) {
boolean isTrue = false;
if (num1 % num2 == 0) { // 나머지가 없이 완전히 나누어지면 약수
isTrue = true;
}
return isTrue;
}
private static int getSum(int num) {
int sum = 0;
for (int i = 1; i < num; i++) {
if (isDivisor(num, i)) { // 메소드에서 다른 메소드를 호출 가능하다!
sum += i;
}
}
return sum;
}
}
이는 메소드에서 다른 메드를 호출 가능하다는 것을 알려주는 문제입니다. 우리는 미리 만들어 놓은 약수를 구하는 기능을 getSum에서 호출해서 사용한 것입니다.
일단 이 문제는 완전수에 대한 개념부터 알고 가야겠습니다.
완전수란, 자기 자신을 제외한 약수(진약수)들의 합이 자기 자신이 되는 수를 말한다. 예를 들어, 6의 약수는 자기 자신인 6을 제외한 1, 2, 3이고 진약수들의 합은 1 + 2 + 3 = 6, 즉 자기 자신이므로 6은 완전수이다.
풀이 :
public class Main {
public static void main(String[] args) {
System.out.println(isPerfect(7));
}
private static boolean isDivisor(int num1, int num2) {
boolean isTrue = false;
if (num1 % num2 == 0) { // 나머지가 없이 완전히 나누어지면 약수
isTrue = true;
}
return isTrue;
}
private static int getSum(int num) {
int sum = 0;
for (int i = 1; i < num; i++) {
if (isDivisor(num, i)) { // 메소드에서 다른 메소드를 호출 가능하다!
sum += i;
}
}
return sum;
}
private static boolean isPerfect(int num) {
if (getSum(num) == num) return true;
return false;
}
}
우리는 앞서 자기 자신을 제외한 약수들의 합을 구하는 메소드를 만들었습니다. 그럼 입력받은 매개변수의 숫자와 getSum 메드의 합이 같으면 그 수는 완전수입니다.
풀이 :
public class Main {
public static void main(String[] args) {
System.out.println("1부터 1000까지의 완전수 : ");
for (int i = 1; i < 1000; i++) {
if (isPerfect(i)) System.out.print(i + " "); // 이미 만들어진 메소드를 사용해 간단히 계산
}
}
private static boolean isDivisor(int num1, int num2) {
boolean isTrue = false;
if (num1 % num2 == 0) { // 나머지가 없이 완전히 나누어지면 약수
isTrue = true;
}
return isTrue;
}
private static int getSum(int num) {
int sum = 0;
for (int i = 1; i < num; i++) {
if (isDivisor(num, i)) { // 메소드에서 다른 메소드를 호출 가능하다!
sum += i;
}
}
return sum;
}
private static boolean isPerfect(int num) {
if (getSum(num) == num) return true;
return false;
}
}
위처럼 이미 만들어진 메드를 사용해서 간단하게 해결하였다.
풀이 :
public class Main {
public static void main(String[] args) {
int base = 3;
int n = 3;
int result = powerN(base, n);
System.out.println("결과 확인 : " + result);
}
private static int powerN(int base, int n) {
int sum = 1;
for (int i = 0; i < n; i++) { // n 까지 반복(3)
sum *= base; //sum = base * base * base...
}
return sum;
}
}
풀이 :
public class Main {
public static void main(String[] args) {
System.out.println(pibo(1));
System.out.println(pibo(2));
System.out.println(pibo(3));
System.out.println(pibo(4));
System.out.println(pibo(5));
}
private static int pibo(int num) {
int[] pibo = new int[num + 1];
pibo[0] = 1;
pibo[1] = 1;
for (int i = 2; i < pibo.length; i++) {
pibo[i] = pibo[i - 2] + pibo[i - 1];
}
return pibo[num - 1];
}
}
다른 문제와 같이 반복문을 써서 해결하면 되지만, 처음 1, 1 << 이 패턴이 조금 문제가 되는 예제였습니다. 제 풀이가 정답은 아닙니다. 여러분도 여러분 방식대로 해결해 보시길 바랍니다.
6. 메소드 오버로딩이란?
메드 오버로딩은 같은 이름을 가진 메소드를 여러 개 정의하는 것을 말합니다. 단, 매개변수의 타입, 개수, 순서가 달라야 합니다. 이는 다양한 입력값에 대해 같은 작업을 수행할 수 있도록 합니다.
특징:
- 같은 이름의 메소드 여러 개 정의
- 매개변수의 타입, 개수, 순서가 다름
- 다형성(polymorphism) 구현
예제 :
public class MyClass {
// 메소드 오버로딩
public int add(int a, int b) {
return a + b;
}
public double add(double a, double b) {
return a + b;
}
public int add(int a, int b, int c) {
return a + b + c;
}
}
마무리
Java 메소드는 프로그램의 구조를 명확하게 하고, 코드의 재사용성을 높이며, 유지보수성을 향상하는 중요한 도구입니다. 메소드의 필요성, 기본 구조, 선언 방법, 사용 방법, 그리고 오버로딩을 이해하는 것은 Java 프로그래밍의 기초를 다지는 데 필수적입니다.
예제가 많은 걸 보셔도 알 수 있습니다. 그만큼 많이 사용하고 유용한 것이 메소드입니다. 여러분들도 메소드 생성과 사용에 익숙해지시길 바랍니다. 감사합니다!
'프로그래밍 기초 > Java' 카테고리의 다른 글
[Java] 2차원 배열 : 개념, 선언 방법, 및 실사용 예제 (0) | 2024.06.15 |
---|---|
[Java] 배열: 개념, 선언 방법, 데이터 접근 및 초기화 (0) | 2024.06.15 |
[Java] 이중 for문 쉽게 배우기: 초보자를 위한 개념과 예제 (0) | 2024.06.15 |
[Java] 반복문 완벽 가이드 : 초보자를 위한 이해와 예제 (0) | 2024.06.14 |
[Java] 조건문 완벽 가이드 : 정의, 종류, 사용법, 특징 총 정리 (0) | 2024.06.12 |