간단하게 계산기 기능을 구현했었는데, 여기서 더 발전된 코드로 개선했다.
<요구사항>
1. 클래스를 적용하기
2. 결과값을 저장하는 리스트 만들기
3. 캡슐화를 통해 결과값을 저장하고 있는 컬렉션에 직접 접근하지 못하도록 하기
기존 코드는 do-while로 작성했는데, 코드가 복잡했다.
그래서while문 과 case문을 활용하여 더욱 깔끔한 코드로 개선하기로 했다.
boolean 타입으로 true false를 통해 시스템을 유지할지 말지 결정해야했고, 불필요하게 else if (operator.equals("-")) 이러한 코드가 반복되었다.
import java.util.Scanner;
public class Calculator1Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in) ;
boolean system = true;
do {
System.out.print("첫 번째 정수를 입력하세요 : ");
int a = scanner.nextInt();
System.out.print("두 번째 정수를 입력하세요 : ");
int b = scanner.nextInt();
System.out.print("사칙연산 기호를 입력하세요: ");
String operator = scanner.next();
if (operator.equals("+")) {
add(a,b);
} else if (operator.equals("-")){
subtract(a,b);
} else if (operator.equals("*")) {
multiply(a,b);
} else if (operator.equals("/")){
divide(a,b);
}
System.out.println("더 계산하시겠습니까? 아무 문자나 입력하세요. (exit 입력 시 종료)");
String ask = scanner.next();
if (ask.equals("exit")){
system = false;
System.out.println("시스템을 종료합니다");
}
}while (system);
}
//더하기
static void add(int a, int b){
System.out.println("결과 : "+(a+b));
}
//빼기
static void subtract(int a, int b){
System.out.println("결과 : "+(a-b));
}
//곱하기
static void multiply(int a, int b){
System.out.println("결과 : "+(a*b));
}
//나누기
static void divide(int a, int b) {
if (b == 0) {
System.out.println("수행할 수 없는 연산입니다");
}else {
System.out.println("결과 : "+(double) a/b);
}
}
}
그래서 코드 중복을 개선하고 더욱 깔끔한 코드로 바꾸기 위해 while과 case를 적극 활용하기로 했다.
package MakeCalculator1;
import java.util.Scanner;
public class Calculator1Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.print("첫 번째 정수를 입력하세요: ");
int a = scanner.nextInt();
System.out.print("두 번째 정수를 입력하세요: ");
int b = scanner.nextInt();
System.out.print("사칙연산 기호를 입력하세요: ");
String operator = scanner.next();
double result; // 연산 결과 저장
switch (operator) {
case "+":
result = add(a, b);
break;
case "-":
result = subtract(a, b);
break;
case "*":
result = multiply(a, b);
break;
case "/":
result = divide(a, b);
break;
default:
System.out.println("잘못된 연산 기호입니다. 다시 입력하세요.");
continue; // 다시 입력 받도록 함
}
System.out.println("결과: " + result);
System.out.println("더 계산하시겠습니까? 아무 문자나 입력하세요. (exit 입력 시 종료)");
String ask = scanner.next();
if (ask.equals("exit")) {
System.out.println("시스템을 종료합니다.");
break;
}
}
}
static int add(int a, int b) {
return a + b; // 더하기
}
static int subtract(int a, int b) {
return a - b; // 빼기
}
static int multiply(int a, int b) {
return a * b; // 곱하기
}
static double divide(int a, int b) {
if (b == 0) {
System.out.println("0으로 나눌 수 없습니다.");
return 0;
}
return (double) a / b;
}
}
(1) while문으로 반복문을 실행하고, 만약 exit가 입력되었다면 break를 통해 반복문이 종료될 수 있도록 함
(2) case 문을 활용하여 불필요한 코드의 중복을 줄임.
(3) 연산 값을 저장하는 result변수 정의 -> 나중에도 활용될 수 있도록 함
(4) 연산 메서드를 void 에서 각각에 맞는 타입으로 변경
→ 값을 return함
사칙연산을 수행 후, 결과값 반환 메서드 구현 & 연산 결과를 저장하는 컬렉션 타입 필드를 가진 Calculator 클래스를 생성해야한다.
CalculatorClass 클래스 만들기위의 코드에서 사칙연산을 수행하는 부분을 클래스로 만들어서 사용해보자
먼저 CalculatorClass 클래스를 같은 패키지 안에 만들고 사칙연산을 수행하자
//더하기
int add(int a, int b){
int result = a+b;
return result;
}
대표적으로 더하기 인스턴스를 보자. return값이 필요하므로 void가 아닌 반환 타입 int로 정의해 메서드를 만든다.
그리고 Main코드에CalculatorClass 클래스를 호출한다
CalculatorClass calculator = new CalculatorClass();
switch문에 calculator 클래스의 add함수를 호출하여 사용한다.
switch (operator) {
case "+":
result = calculator.add(a, b);
break;
클래스를 적용해 연산을 수행할 수 있다!
연산을 수행한 결과를 저장하는 컬렉션 필드를 만들자
✨ArrayList✨ :
배열은 크기가 고정되어 있어서 한 번 설정하면 길이를 변경할 수 없지만 ArrayList는 정해진 크기 없이 요소의 순서를 유지하고 중복된 값을 저장할 수 있는 자료구조입니다.
자바에서 List는 ArrayList로 구현할 수 있다.
import java.util.ArrayList;
...생략
ArrayList<Double> calculateList = new ArrayList<>();
<> 안에는 정의하고싶은 타입을 적는다.
ArrayList는 add remove get키워드로 각각 추가, 삭제, 조회를 수행할 수 있다.
직접 더하기 메서드에 적용해보자
public class CalculatorClass {
ArrayList<Double> calculateList = new ArrayList<>(); //연산 결과 저장하기
//더하기
int add(int a, int b){
int result = a+b;
calculateList.add((double) result); //calculateList 리스트에 저장
return result;
}
calculateList.add를 통해 연산 결과를 calculateList에 순서대로 저장할 수 있다.
만약 코드에서 오류가 발생했다? 왜, 어디에서 발생했는지 알고 싶고, 오류가 발생했을때 수행할 로직을 정하고 싶다. 그럴때 try-catch문을 사용하면 된다!
: 프로그램 실행 중 예상하지 못한 상황이 발생하는 것
throw 키워드를 통해 발생예외처리(try-catch)를 통해 프로그램이 안정적으로 실행되게 할 수 있다.코드로 예시를 보면서 이해해보자
계산기 로직을 수행하면서 0으로 나누는 상황에서 예외가 발생할 수 있다.
→ 10 / 0 수행 시 오류 발생
이때 0으로는 나눌수없다고 경고문을 보여주면 좋지 않을까?
//나누기
double divide(int a, int b) {
if (b==0){
throw new ArithmeticException("0으로는 나눌 수 없습니다");
}
double result = (double) a/b ;
calculateList.add(result);
return result;
}
throw 키워드를 통해 만약 0으로 나누려고한다면 ArithmeticException 예외를 날려줘서 오류 문자를 띄울 수 있게 해줄 수 있다.
이를 적용한 main 코드를 보면
case "/":
try { //0으로 나누었을때 연산 오류 잡기 try-catch로
result = calculator.divide(a, b);
} catch (ArithmeticException e) {
System.out.println("오류! " + e.getMessage());
System.out.println("다시 입력해주세요.");
continue; // 0으로 나누었을 경우 다시 입력 받도록 함.
}
break;
먼저 try로 result를 수행하면 클래스에서는 ArithmeticException을 날려준다.
이때 catch문이 System.out.println("오류! " + e.getMessage()); 로직을 수행한다.
: 클래스의 캡슐화(Encapsulation)를 위해 사용되는 메서드
→ 클래스 내부의 private 변수에 접근하고 수정할 수 있도록 해줌
: 객체의 private 변수 값을 외부에서 읽을 수 있도록 하는 메서드
get + 변수명 형식으로 메서드 이름을 작성
예시로 알아보자!
public class Person {
private String name; // private 변수 (직접 접근 불가)
// Getter 메서드
public String getName() {
return name; // 변수 값 반환
}
}
Person person = new Person();
System.out.println(person.getName()); // name 값을 가져옴
private 로 정의된 변수는 원래 외부에서 접근이 불가능하지만
getter를 사용하면 가져올 수 있다!
: 객체의 private 변수 값을 외부에서 변경할 수 있도록 하는 메서드
set + 변수명 형식으로 메서드 이름 작성
public class Person {
private String name; // private 변수
// Setter 메서드
public void setName(String name) {
this.name = name; // 받은 값을 변수에 저장
}
}
Person person = new Person();
person.setName("홍길동"); // name 값 넣어주기
Setter를 사용하면 private로 정의된 변수값도 인자를 받아서 저장해줄 수 있다.
그럼 한번 계산기에 적용해보자
계산기에 저장된 값을 private로 설정해 직접 접근하지 못하도록 보호하고, getter로 가져올 수 있도록 개선해보자!
(1) 먼저 ArrayList를 외부에서 직접 접근하지 못하게 private로 바꿔주자
private ArrayList<Double> calculateList = new ArrayList<>();
(2) main클래스에서 지금까지 저장된 연산의 수를 출력할 수 있도록 이를 반환하는 getter 메서드를 정의하자
int getListNum(){
return calculateList.size();
}
(3) main클래스에 불러오자
calculator.getListNum();