10월 16일

Yullgiii·2023년 10월 16일
0
post-thumbnail

내일 배움 캠프

자 이번주 시작이다!!!!!!!!가보자!!!!!!!!!!

Java

상속!!

클래스 간의 관계를 알아야한다.
유산을 물려주는 행위
코드 중복을 제거! 재사용성이 크게 증가하여 생산성과 유지보수성에 매우 유리!!!


1. 부모 클래스에 새로운 필드와 메서드가 추가되면 자식 클래스는 이를 상속받아 사용할 수 있다.
2. 자식 클래스에 새로운 필드와 메서드가 추가되어도 부모 클래스는 어떠한 영향도 받지 않는다.
3. 따라서 자식 클래스의 멤버 개수는 부모 클래스보다 항상 같거나 많다.
= 상속 받아서 사업을 할수있는거잖아>????그러니 자식이 더 크겠지
잘 기억해둘것!!!!!!!!

클래스간의 관계!

  • 상속관계 : is - a (”~은 ~(이)다”)
  • 포함관계 : has - a (”~은 ~을(를) 가지고 있다”)

단일 상속/ 다중 상속

Java는 다중상속을 허용하지 않는다!!!!!!!!!!!!!!!!
간단히 이해하면 부모는 자식이 여러명 있을 수있지만 자식이 부모가 여러명...?쉽지않다.
다중상속을 허용하면 클래스간의 관계가 복잡해지는 문제
클래스에 final 키워드를 지정하여 선언하면 최종적인 클래스가 됨으로 더 이상 상속할 수 없는 클래스
메서드에 final 키워드를 지정하여 선언하면 최종적인 메서드가 됨으로 더 이상 🌟오버라이딩🌟할 수 없는 메서드

Object

Object 클래스는 Java 내 모든 클래스들의 최상위 부모 클래스
얄코님이 말하길 조상님격이라고 했다.

  • Object clone() : 해당 객체의 복제본을 생성하여 반환함.
  • boolean equals(Object object) : 해당 객체와 전달받은 객체가 같은지 여부를 반환함.
  • Class getClass() : 해당 객체의 클래스 타입을 반환함.
  • int hashCode() : 자바에서 객체를 식별하는 정수값인 해시 코드를 반환함.
  • String toString() : 해당 객체의 정보를 문자열
    로 반환함. & Object 클래스에서는 클래스이름 @해쉬코드값 리턴함

오버라이딩

부모 클래스로부터 상속받은 메서드의 내용을 재정의 하는 것을 오버라이딩
부모 클래스의 메서드를 그대로 사용 가능하지만 자식 클래스의 상황에 맞게 변경을 해야하는 경우 오버라이딩을 사용

  • 오버라이딩을 하기 위해서는 아래 조건들을 만족해야합니다.
  1. 선언부가 부모 클래스의 메서드와 일치해야 합니다.
  2. 접근 제어자를 부모 클래스의 메서드 보다 좁은 범위로 변경할 수 없습니다.
  3. 예외는 부모 클래스의 메서드 보다 많이 선언할 수 없습니다.

@ <-이게 뭐지? 에노테이션 (annotaion)

super 와 super()

this(인스턴스), this()(생성자) 랑 비슷

super는 부모 클래스의 멤버를 참조할 수 있는 키워드

super는 부모를 건드리고
this는 거기있는 그냥 자식을 건드린다!

super(…)는 부모 클래스의 생성자를 호출할 수 있는 키워드

  • 자식 클래스 객체를 생성할 때 생성자 매개변수에 매개값을 받아와 super(…)를 사용해 부모 생성자의 매개변수에 매개값을 전달하여 호출하면서 부모 클래스의 멤버를 먼저 초기화합니다.
  • 오버로딩된 부모 클래스의 생성자가 없다고 하더라도 부모 클래스의 기본 생성자를 호출해야합니다.
  • 눈에 보이지는 않지만 컴파일러가 super(); 를 자식 클래스 생성자 첫 줄에 자동으로 추가

다향성

부모타입 변수 = 자식타입객체; 는 자동으로 부모타입으로 변환

  • 자식 객체는 부모 객체의 멤버를 상속받기 때문에 부모와 동일하게 취급될 수 있습니다.
    • 예를 들어 포유류 클래스를 상속받은 고래 클래스가 있다면 포유류 고래 = 고래객체; 가 성립될 수 있습니다.
    • 왜냐하면 고래 객체는 포유류의 특징인 모유수유 행위를 가지고 있기 때문입니다.
    • 다만 주의할 점은 부모타입 변수로 자식객체의 멤버에 접근할 때는 부모 클래스에 선언된 즉, 상속받은 멤버만 접근할 수 있습니다.

자식타입 변수 = (자식타입) 부모타입객체;

  • 부모타입객체는 자식타입 변수로 자동으로 타입변환되지 않습니다.
  • 이럴때는 (자식타입) 즉, 타입변환 연산자를 사용하여 강제로 자식타입으로 변환할 수 있습니다.

다형성이란 ‘여러 가지 형태를 가질 수 있는 능력’
참조변수와 타입변환을 활용하여 사용 가능!!!!

instanceof

다형성 기능으로 인해 해당 클래스 객체의 원래 클래스명을 체크하는것이 필요한데 이때 사용할 수 있는 명령어가 instance of

  • 이 명령어를 통해서 해당 객체가 내가 의도하는 클래스의 객체인지 확인할 수 있게된다.
  • {대상 객체} instance of {클래스 이름} 와 같은 형태로 사용하면 응답값은 boolean !!!!!

추상클래스-클래스가 설계도라면 추상 클래스는 미완성된 설계도

abstract 키워드를 사용하여 추상 클래스를 선언

  • 추상 클래스는 추상 메서드를 포함할 수 있습니다.
    • 추상 메서드가 없어도 추상 클래스로 선언할 수 있습니다.
  • 추상 클래스는 자식 클래스에 상속되어 자식 클래스에 의해서만 완성될 수 있습니다.
  • 추상 클래스는 여러개의 자식 클래스들에서 공통적인 필드나 메서드를 추출해서 만들 수 있습니다.

추상 메서드-추상 메서드는 아직 구현되지 않은 미완성된 메서드
abstract 키워드를 사용하여 추상 메서드를 선언

public abstract class 추상클래스명 {
		abstract 리턴타입 메서드이름(매개변수, ...);
}

추상 클래스 상속

  • 추상 메서드는 extends 키워드를 사용하여 클래스에서 상속됩니다.

인터페이스

인터페이스는 두 객체를 연결해주는 다리 역할

  • 사람과 삼성티비, 엘지티비 객체가 존재한다고 생각해 보겠습니다.
  • 사람 객체는 멀티 리모컨 인터페이스를 통해서 삼성티비 객체의 채널을 변경할 수 있습니다.
  • 이때 삼성티비가 아니라 엘지티비로 객체가 교체된다고 해도 채널을 변경할 수 있습니다.

좋은 예제이다!!!!

  • 상속 관계가 없는 다른 클래스들이 서로 동일한 행위 즉, 메서드를 구현해야할 때 인터페이스는 구현 클래스들의 동일한 사용 방법과 행위를 보장해 줄 수 있습니다.
    • 인터페이스는 스팩이 정의된 메서드들의 집합입니다.
    • 인터페이스의 구현 클래스들은 반드시 정의된 메서드들을 구현해야합니다.
    • 따라서 구현 클래스들의 동일한 사용 방법과 행위를 보장해 줄 수 있습니다.
    • 이러한 특징은 인터페이스에 다형성을 적용할 수 있게 만들어 줍니다.

interface 키워드를 사용하여 인터페이스를 선언

인터페이스의 멤버

모든 멤버변수는 public static final(생략가능)
모든 메서드는 public abstract (생략가능)
생략되는 제어자는 컴파일러가 자동으로 추가(좋은 프로그램이네)

인터페이스 구현

implements 키워드를 사용하여 인터페이스를 구현
인터페이스의 추상 메서드는 구현될 때 반드시 오버라이딩
만약 인터페이스의 추상 메서드를 일부만 구현해야 한다면 해당 클래스를 추상 클래스로 변경

인터페이스 상속

인터페이스간의 상속은 implements 가 아니라 extends 키워드를 사용
인터페이스는 클래스와는 다르게 다중 상속이 가능

디폴트 메서드와 Static 메서드

defult

static 메서드

static의 특성 그대로 인터페이스의 static 메서드 또한 객체 없이 호출이 가능

타입변환

구현객체타입 변수 = (구현객체타입) 인터페이스변수;

인터페이스의 다형성

예제로 설명해주셔서
만약 다시금 생각하며 복습하고 싶으면
인텔리제이에 interFinal을 볼것!!!

이 자식 클래스는 부모 클래스로 Tv를 상속하고 있고 또한 인터페이스로 리코컨도 사용하는중이다.

계산기를 만들어 보아요

Calculator

public class Calculator {
    private AbstractOperation operation;

    public Calculator(AbstractOperation operation) {
        this.operation = operation;
    }

    public double calculate(int firstNumber, int secondNumber) {
        return operation.operate(firstNumber, secondNumber);
    }
}

Calculator는 주입 받은 연산 객체를 이용해서 연산을 수행하는 클래스
연산 객체는 AbstractOperation 타입으로, 어떤 연산을 수행할 것인지를 결정
calculate 메서드는 주입 받은 연산 객체의 operate 메서드를 호출하여 연산 결과를 반환

AbstractOperation

public abstract class AbstractOperation {
    public abstract double operate(int firstNumber, int secondNumber);
}

AbstractOperation은 추상 연산 클래스
이 클래스를 상속받는 모든 연산 클래스는 operate 메서드를 구현

AddOperation

public class AddOperation extends AbstractOperation {
    @Override
    public double operate(int firstNumber, int secondNumber) {
        return firstNumber + secondNumber;
    }
}

더하기 연산을 수행하는 클래스

SubstractOperation

public class SubstractOperation extends AbstractOperation {
    @Override
    public double operate(int firstNumber, int secondNumber) {
        return firstNumber - secondNumber;
    }
}

빼기 연산을 수행하는 클래스

MultiplyOperation

public class MultiplyOperation extends AbstractOperation {
    @Override
    public double operate(int firstNumber, int secondNumber) {
        return firstNumber * secondNumber;
    }
}

곱하기 연산을 수행하는 클래스

DivideOperation

public class SubstractOperation extends AbstractOperation {
    @Override
    public double operate(int firstNumber, int secondNumber) {
        return firstNumber - secondNumber;
    }
}

나누기 연산을 수행하는 클래스

Main

public class Main {
    public static void main(String[] args) {
        Calculator addCalculator = new Calculator(new AddOperation());
        System.out.println(addCalculator.calculate(5, 3));  // 출력: 8.0

        Calculator subCalculator = new Calculator(new SubstractOperation());
        System.out.println(subCalculator.calculate(5, 3));  // 출력: 2.0

        Calculator mulCalculator = new Calculator(new MultiplyOperation());
        System.out.println(mulCalculator.calculate(5, 3));  // 출력: 15.0

        Calculator divCalculator = new Calculator(new DivideOperation());
        System.out.println(divCalculator.calculate(5, 3));  // 출력: 1.6666666666666667
    }
}

여러 연산 객체를 생성하고, 각각의 연산 객체를 Calculator에 주입하여 연산 결과를 출력

이렇게 3주차가 마무리 되고

4주차!!

오류 및 예외에 대한 이해

오류(Error)
시스템 레벨에서, 또는 주로 환경적인 이유로 발생
발생하는경우 일반적으로 회복이 불가능
에러가 발생한 경우 우리는 어떠한 에러로 프로그램이 종료되었는지를 확인하고 대응

예외(Exception)
코드레벨에서 할 수 있는 문제상황에 대한 대응은 “예외처리”

예외의 종류(이게 참 많다...하지만 크게는 두개!)
컴파일 에러!!!
컴파일이란

  • 프로그래밍 언어로 작성한 코드가 컴퓨터가 이해 할 수 있는 언어로 변환되는 것을 “컴파일”
  • 컴파일 된 코드는 컴퓨터가 이해 할 수 있어서, 실행 시킬수 있는 코드 뭉치인 “프로그램”

자바 프로그래밍 언어의 규칙을 지키지 않았기 때문에 발생
컴파일 에러가 발생하는 경우 해결 방법은 문법에 맞게 다시 작성하는 것

런타임 에러(코테하면서 젤 많이 본 에러....)
문법적인 오류는 아니라서, 컴파일은 잘 되었지만 “프로그램”이 실행도중 맞닥뜨리게 되는 예외

예외처리 관점에서 예외의 종류
확인된 예외(Checked Exception)
컴파일 시점에 확인하는 예외
반드시 예외 처리를 해줘야하는 예외
Checked Exception에 대한 예외처리를 하지 않으면 컴파일 에러가 발생

미확인된 예외(Unchecked Exception)
런타임 시점에 확인되는 예외
예외 처리가 반드시 필요하지 않은 예외

예외 발생, try-catch, finally 문


throws : 던지다!(예외를 던지다!/발생시키다)

throwsthrow
메서드 이름 뒤에 붙어 이 메서드가 어떠한 예외사항을 던질 수 있는지 알려주는 예약어 입니다.메서드 안에서, 실제로 예외 객체를 던질 때 사용하는 예약어 입니다.
여러 종류의 예외사항을 적을 수 있습니다.실제로 던지는 예외 객체 하나와 같이 써야 합니다.
일반 메서드의 return 키워드처럼 throw 아래의 구문들은 실행되지 않고, throw문과 함께 메서드가 종료됩니다.

try{
위험한 메소드의 실행을 "시도"
}catch() {
예외가 발생하면, "잡아서" handling
}finally {
예외의 발생 여부와 상관없이, 실행시켜야 하는 코드
}

 try {
 // "시도" 해보는 코드가 들어가는 블럭입니다.
    ourClass.thisMethodIsDangerous();
} catch (OurBadException e) {
    // 예외가 발생하는경우 "handling" 하는 코드가 들어가는 블럭입니다.
   // 즉 try 블럭 내의 구문을 실행하다가 예외가 발생하면
   // 예외가 발생한 줄에서 바로 코드 실행을 멈추고
  // 여기 있는 catch 블럭 내의 코드가 실행됩니다.
  System.out.println(e.getMessage());
} finally {
  // 무조건 실행되는 코드가 들어가는 블럭입니다.
   System.out.println("우리는 방금 예외를 handling 했습니다!");
}

정리!!!!
Checked Exception
예외가 발생하는 상황을 “인지” 했고, 어떠한 에러인지 “정의”
메서드를 선언 할 때 예외가 발생하는 위험한 메서드라는 것을 “알린다.(throws/throw)”.
checked exception을 정의하고, 알렸으니 이 메서드를 사용 할 때 예외처리를 하지 않으면 컴파일 에러가 발생!!!!!!!!!!!!!!

예외 구조 이해하기

  • 가장 추상적인 “문제”
  • 그것보다는 조금 더 구체적인 “오류”, “예외”
  • 그것보다 더 구체적인 “Checked Exception”, “Unchecked Exception”
    과 같이 정의

자바의 Throwable Class

  • 시작은 모든 객체의 원형인 Object 클래스에서 시작
  • 아까 정의한 “문제 상황”을 뜻하는 Throwable 클래스가 Object 클래스를 상속
  • Throwable 클래스의 자식으로 앞서배운 에러(Error)와 예외(Exception) 클래스
  • 에러(Error) 클래스와 예외(Exception) 클래스는 각각 IOError 클래스, RuntimeException 클래스와 같이 구분하여 처리



정말 많이 보게 될 예외들....

Java 예외 리스트


// 출처 : https://programming.guide/java/list-of-java-exceptions.html

java.io
IOException
CharConversionException
EOFException
FileNotFoundException
InterruptedIOException
ObjectStreamException
InvalidClassException
InvalidObjectException
NotActiveException
NotSerializableException
OptionalDataException
StreamCorruptedException
WriteAbortedException
SyncFailedException
UnsupportedEncodingException
UTFDataFormatException
UncheckedIOException

java.lang

ReflectiveOperationException
ClassNotFoundException
InstantiationException
IllegalAccessException
InvocationTargetException
NoSuchFieldException
NoSuchMethodException
CloneNotSupportedException
InterruptedException

산술 예외
IndexOutOfBoundsException
ArrayIndexOutOfBoundsException
StringIndexOutOfBoundsException
ArrayStoreException
ClassCastException
EnumConstantNotPresentException
IllegalArgumentException
IllegalThreadStateException
NumberFormatException
IllegalMonitorStateException
IllegalStateException
NegativeArraySizeException
NullPointerException
SecurityException
TypeNotPresentException
UnsupportedOperationException

java.net
HttpRetryException
SocketTimeoutException
MalformedURLException
ProtocolException
SocketException
BindException
ConnectException
NoRouteToHostException
PortUnreachableException
UnknownHostException
UnknownServiceException
URISyntaxException

java.text
ParseException
 

java.time
DateTimeException
 

java.time.zone
ZoneRulesException

Chained Exception

연결된 예외 (Chained Exception)
예외는 다른 예외를 유발할 수 있다.
원인 예외를 다루기 위한 메소드

  • initCause()
    • 지정한 예외를 원인 예외로 등록하는 메소드
  • getCause()
    • 원인 예외를 반환하는 메소드

실제로 예외 처리하기

실질적으로 예외를 처리하는 방법으로는 예외 복구, 예외 처리 회피, 예외 전환 이 있다.

//예외 복구하기
public String getDataFromAnotherServer(String dataPath) {
		try {
				return anotherServerClient.getData(dataPath).toString();
		} catch (GetDataException e) {
				return defaultData;
		}
}
//실제로 try-catch로 예외를 처리하고 프로그램을 정상 상태로 복구하는 방법
//가장 기본적인 방식이지만, 현실적으로 복구가 가능한 상황이 아닌 경우가 많거나 
//최소한의 대응만 가능한 경우가 많기 때문에 자주 사용되지는 않는다...
//예외 처리 회피하기
public void someMethod() throws Exception { ... }

public void someIrresponsibleMethod() throws Exception {
		this.someMethod();
}
// 관심사를 분리해서 한 레이어에서 처리하기 위해서 이렇게 에러를 회피해서 그대로 흘러 보내는 경우도 있습니다.
//예외 전환하기
public void someMethod() throws IOException { ... }

public void someResponsibleMethod() throws MoreSpecificException {
		try {
			this.someMethod();
		} catch (IOException e) {
			throw new MoreSpecificException(e.getMessage());
		}
}
//예외처리 회피하기의 방법과 비슷하지만, 조금더 적절한 예외를 던져주는 경우
//보통은 예외처리에 더 신경쓰고싶은 경우나, 
//오히려 RuntimeException처럼 일괄적으로 처리하기 편한 예외로 바꿔서 던지고 싶은 경우 사용

Generic

제네릭의 효용

  • 첫 번째로 제네릭의 효용은 타입 언어에서 “중복되거나 필요없는 코드를 줄여주는 것”
  • 두 번째 제네릭의 효용은 그러면서도 타입 안정성을 해치지 않는 것
    제네릭은 클래스, 인터페이스, 메서드를 정의할 때 타입(type)을 파라미터로 활용할 수 있게 해주는 기능
    타입 안정성(type safety) 확보
    타입 체크와 형변환(casting)을 줄여 코드의 간결성 향상
    코드 재사용성 증대

아니 듣다보니 쫌 화나네?파이썬이랑 자바스크립트는 왜케 효용성이 좋아?
하지만...에러많이 난다니 힘내보자구

// 제네릭을 사용한 클래스 선언
public class Box<T> {
    private T data;

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}

// 사용 예:
Box<String> stringBox = new Box<>();
stringBox.setData("Hello, Generics!");
String str = stringBox.getData();

제한된 타입 파라미터(Bounded Type Parameter):
특정 타입의 하위 클래스만 허용하고 싶을 때 사용

public class NumberBox<T extends Number> {
    private T data;

주의사항
기본 타입(primitive type)은 제네릭 타입 파라미터로 사용될 수 없다 (int, char 등)
실행 시(runtime) 제네릭의 타입 정보는 제거!!! 타입 소거(type erasure)

제네릭 문법 살펴보기

제네릭에서 <>사이에 들어가는 변수명 T는 타입 변수!
Generic 클래스를 원시 타입

제네릭의 제한

객체의 static 멤버에 사용 할 수 없다
제네릭 배열을 생성 할 수 없다.

제네릭의 문법

다수의 타입변수를 사용 할 수 있다
다형성 즉 상속과 타입의 관계는 그대로 적용
와일드 카드를 통해 제네릭의 제한을 구체적으로 정할 수 있다
와일드카드(Wildcard):
제네릭 타입의 제한된 유연성을 확보
<?>: 모든 타입이 허용. (예: List<?>)
<? extends T>: T와 T의 하위 타입만 허용됩니다.
<? super T>: T와 T의 상위 타입만 허용됩니다.

메서드를 스코프로 제네릭을 별도로 선언 할 수 있다

Collection 다시보기

List, 배열 예시

검색에는 유리하고, 수정/삭제는 불리한 자료구조
정한 규칙을 규정한 “리스트” 자료구조가 바로 “스택”, ”큐”

  • 빈 리스트를 만드는 연산
  • 리스트가 비어있는지 확인하는 연산
  • 리스트의 앞에 원소를 삽입하는 연산
  • 리스트의 뒤에 원소를 삽입하는 연산
  • 리스트의 제일 첫 원소를 알아보는 연산
  • 리스트의 첫 원소를 제외한 나머지 리스트를 알아보는 연산



결론은 생각하며 써야한다...그냥 냅다 이리 쓰라해서 쓰는건 도움이 안된다!

Wrapper 객체

Integer num = new Integer(17);  // Boxing
int n = num.intValue(); // UnBoxing

Character ch = 'X'; // AutoBoxing
char c = ch; // AutoUnBoxing

Wrapper 클래스는 Java의 기본 타입(primitive types)을 객체로 포장(wrap)하는데 사용되는 클래스

주요 Wrapper 클래스

Byte, Short, Integer, Long – 정수 타입
Float, Double – 부동 소수점 타입
Character – 문자 타입
Boolean – 불리언 타입

how to use

기본 타입을 객체로 사용할 필요가 있을 때 (예: 컬렉션 자료구조에서 사용)
타입에 관련된 유용한 메서드를 제공 (예: Integer.parseInt(), Character.isDigit())
null 값을 허용해야 할 때

오토박싱(Autoboxing) & 오토언박싱(Autounboxing)

오토박싱: 기본 타입의 값을 자동으로 해당 Wrapper 객체로 변환하는 것.
오토언박싱: Wrapper 객체를 자동으로 기본 타입의 값으로 변환하는 것.

주의사항

Wrapper 객체는 immutable(불변) 값이 변할 때마다 새로운 객체가 생성.
객체가 필요한 경우(예: 컬렉션에서 사용)에는 Wrapper 클래스를 사용
오토박싱과 오토언박싱이 편리하긴 하지만, 무분별하게 사용될 경우 성능 저하의 원인이 된다

4주차의 마무리 숙제

  1. 구현 1, 구현2 로 주석처리된 부분을 직접 구현해주세요
  2. 추가된 BadInputException은 우리가 이번 과제에서 사용할 예외 입니다.
  3. 추가된 CalculatorApp은 우리의 계산기를 실행시켜주는 클래스 입니다.
  4. Parser는 유저의 입력을 받아서 우리가 지난주에 구현한 계산기의 로직으로 전환시켜주는 객체 입니다.
  5. 우리는 주로 Parser를 구현할 예정 입니다.
  6. 우리는 유저의 입력을 String으로만 받아야 합니다.
  7. 입력받은 String을 숫자나 연산자로 변환하기 위해서 꼭! 예외처리를 해야합니다.
  8. 해당 예외처리를 하기 위해서는 Pattern.match() 메서드가 필요합니다. 해당 부분은 검색하면 알 수 있습니다.
  9. Pattern.match()메서드를 사용하기 위한 정규식 표현은 코드내에 제공되어 있습니다.
  10. 예외는 이미 구현된 BadInputException 객체를 사용합니다.
  11. 에외를 어디에 구현 할 지는 본인이 결정 할 수 있습니다. 어디가 더 좋을지 고민해보고 좋은 위치에 구현하고 간단하게 주석으로 자기의 생각을 표현해주세요

구현 1

import java.util.regex.Pattern;

public class Parser {
    private static final String OPERATION_REG = "[+\\-*/]";
    private static final String NUMBER_REG = "^[0-9]*$";

    private final Calculator calculator = new Calculator();

    public Parser parseFirstNum(String firstInput) {
				// 구현 1.

    }

    public Parser parseSecondNum(String secondInput) {
				// 구현 1.
    }

    public Parser parseOperator(String operationInput) {
       // 구현 1.
    }

    public double executeCalculator() {
        return calculator.calculate();
    }
}

를 혼자 뚱땅해보면

import java.util.regex.Pattern;

public class Parser {
    private static final String OPERATION_REG = "[+\\-*/]";
    private static final String NUMBER_REG = "^[0-9]*$";

    private final Calculator calculator = new Calculator();

    public Parser parseFirstNum(String firstInput) throws BadInputException {
        if (!Pattern.matches(NUMBER_REG, firstInput)) {
            throw new BadInputException("숫자");
        }
        calculator.setFirstNumber(Integer.parseInt(firstInput));
        return this;
    }

    public Parser parseSecondNum(String secondInput) throws BadInputException {
        if (!Pattern.matches(NUMBER_REG, secondInput)) {
            throw new BadInputException("숫자");
        }
        calculator.setSecondNumber(Integer.parseInt(secondInput));
        return this;
    }

    public Parser parseOperator(String operationInput) throws BadInputException {
        if (!Pattern.matches(OPERATION_REG, operationInput)) {
            throw new BadInputException("연산자 (+, -, *, / 중 하나)");
        }
        switch (operationInput) {
            case "+":
                calculator.setOperation(new AddOperation());
                break;
            case "-":
                calculator.setOperation(new SubstractOperation());
                break;
            case "*":
                calculator.setOperation(new MultiplyOperation());
                break;
            case "/":
                calculator.setOperation(new DivideOperation());
                break;
        }
        return this;
    }

    public double executeCalculator() {
        return calculator.calculate();
    }
}

구현 2

public class Main {
    public static void main(String[] args) {
        boolean calculateEnded = false;
				// 구현 2.
    }
}
public class Main {
    public static void main(String[] args) {
        boolean calculateEnded = false;
        // 구현 2.
        while (!calculateEnded) {
            try {
                calculateEnded = CalculatorApp.start();
            } catch (BadInputException e) {
                System.out.println(e.getMessage());
                // 사용자에게 다시 입력을 받기 위해 계속한다.
            } catch (IllegalArgumentException e) {
                System.out.println(e.getMessage());
                calculateEnded = true; // 0으로 나누기 시도시 프로그램 종료
            } catch (Exception e) {
                System.out.println("알 수 없는 오류 발생: " + e.getMessage());
                calculateEnded = true; // 알 수 없는 오류 발생시 프로그램 종료
            }
        }
    }
}

5주차는 내일 뵙도록해요....

후... 복습은 진즉에 끝나버렸고 새로운 개념들에 듣게 되니 머리가 아프구나?
몹시아프다 그렇다 아프다 이말이다
그래서 오늘은 4주차까지만 할수있었다.
내일은 5주차까지 마무리를 할 생각으로 열심히 달려봐야겠다!!!!!!!

profile
개발이란 무엇인가..를 공부하는 거북이의 성장일기 🐢

0개의 댓글