diff --git "a/4\354\243\274\354\260\250/VO(Value Object).md" "b/4\354\243\274\354\260\250/VO(Value Object).md" new file mode 100644 index 00000000..6ce19c05 --- /dev/null +++ "b/4\354\243\274\354\260\250/VO(Value Object).md" @@ -0,0 +1,86 @@ +# [Java] VO(Value Object) +## 1. VO(Value Object)란 +VO(Value Object)란 말 그대로 값 객체라는 의미를 가지고 있다. 즉, 데이터를 담는 객체이다. +VO는 데이터베이스에서 한 테이블에 대한 컬럼들과 매칭하여 사용하는 것으로 많이 사용된다. +VO의 핵심 역할은 **equals()** 와 **hashcode()** 를 오버라이딩 하는 것이다. 즉, VO 내부에 선언된 속성(필드)의 모든 값들이 VO 객체마다 값이 같아야 같은 객체라고 판별한다. + +## 2. Value Object 기본 특성 +**Value Object**에는 기본 특성이 있다. +> 1. Immutability(불변성) - 수정자(setter)가 없음 +> 2. Value Equality(값 동등성) - 내부 값 동등성 검사 +> 3. Self Validation(자가 유효성 검사) - 생성자에서 validate + +### 2-1. Immutability(불변성) - 수정자(Setter)가 없음 +Value Object는 **불변**이다. + +불변이라는 뜻은 한번 생성되면 이후 내부 값을 바꿀 수 없음을 의미한다. 즉 **수정자(Setter)를 허용하지 않는다**는 말이다. + +쉽게 말하면, 생성자에게 하나 혹은 그 이상의 파라미터가 주입돼서 객체가 만들어지면, 돌아갈 수 없음을 의미한다. 해당 객체는 **GC(Garbage Collector)** 에 의해 폐기될 때까지 동일함을 보장한다. + +- Hassle-free Sharing(번거로움없는 공유) + Value Object는 코드의 다른 부분에서 수정되지 않기 때문에 **Reference(참조)로 공유**할 수 있다. 이는 side effect를 피하기 위해 사용되는 코드의 복잡성과 부하를 극적으로 감소시키며, 멀티스레드 환경에서 그 이점이 뚜렷해진다. +- Improved Semantics(향상된 의미) + 불변성을 **"무의미한 생성자(Getter)를 Value Object에 추가하지 않는다."**라는 규칙과 결합해야 한다. 초기 클래스에는 생성자와 private 접근 지정자인 속성만 있어야 한다. + +> ### Value Object를 조작하는 방법 +> - 생성자 또는 정적 메소드를 통해 새 인스턴스 만들기 +> - 현재 객체에서 다른 객체 생성하기 +> - 내부 데이터를 추출해 다른 유형으로 변환하기 +> - 정적 팩토리 메소드 패턴을 활용해 생성하기(생성자를 private하게 바꿈) + +위와 같은 방법은 Value Object를 명확하게 해준다. +```java +final class ComplexNumber { + private float realPart; + private float complexPart; + + // 정적 메소드를 통해 새 인스턴스 만들기 + public static ComplexNumber zero() { + return new ComplexNumber(0, 0); + } + + // 생성자를 통해 새 인스턴스를 만들기 + private ComplexNumber(float realPart, float complexPart) { + this.realPart = realPart; + this.complexPart = complexPart; + } + + // 정적 팩토리 메소드 패턴을 활용하여 생성하기 (생성자를 private하게 바꿈) + public static ComplexNumber of(float realPart, float complexPart) { + return new ComplexNumber(realPart, complexPart); + } + + // 현재 객체에서 다른 객체를 생성하기 + public ComplexNumber add(ComplexNumber anotherComplexNumber) { + return new ComplexNumber( + realPart + anotherComplexNumber.realPart, + complexPart + anotherComplexNumber.complexPart + ); + } + + // 내부 데이터를 추출하여 다른 유형으로 변환하기 + public String toString() { + return String.format("%f + %f i", realPart, complexPart); + } +} +``` + +### 2-2. Value Equality(값 동등성) - 내부 값 동등성 검사 +Value Object는 내부 값이 모둗 각각 동일한지 확인하여 동등성을 테스트할 수 있다. + +> ### 동일성 vs 동등성 +> **동일성**은 객체가 완전히 같은지 판단할 수 있는 성질이고, **동등성**은 객체가 같은 정보를 가지고 있는지 판단할 수 있는 성질이다. +> 동일성은 ```==```로 **주소값**을 비교하고, 동등성은 ```equals()```로 **내용**을 비교한다. + +### 2-3. Self Validation(자가 유효성 검사) - 생성자에서 validate +Value Object는 context에서 유효한 값만 허용한다. 이는 유효하지 않은 값으로 Value Object를 만들 수 없음을 의미한다. + +생성자가 주입될 때 값의 유효성을 확인해야 한다. 유효하지 않으면 의미있는 에러를 표출한다. 이는 객체의 인스턴스에 더이상 if가 없음을 의미한다. **모든 유효성 검사는 생성 시간**에 이루어진다. + +## 3. 정리 +객체를 Value Object로 만들기 위한 체크 리스트 +- 불변하며 수정자(Setter)가 없다 +- 도메인의 의미론을 반영한다 +- 런타임동안 정보의 흐름과 변환 방법을 보여준다 +- default나 쓸모없는 Getter 메소드가 없다 +- private 속성을 가지며 다른 Value Object와 비교할 수 있다 \ No newline at end of file diff --git "a/4\354\243\274\354\260\250/\352\260\235\354\262\264 \354\247\200\355\226\245-\354\227\255\355\225\240, \354\261\205\354\236\204, \355\230\221\353\240\245.md" "b/4\354\243\274\354\260\250/\352\260\235\354\262\264 \354\247\200\355\226\245-\354\227\255\355\225\240, \354\261\205\354\236\204, \355\230\221\353\240\245.md" new file mode 100644 index 00000000..d5bc73c0 --- /dev/null +++ "b/4\354\243\274\354\260\250/\352\260\235\354\262\264 \354\247\200\355\226\245-\354\227\255\355\225\240, \354\261\205\354\236\204, \355\230\221\353\240\245.md" @@ -0,0 +1,93 @@ +# [Java] 객체 지향 +## 1. 객체 지향이란 +객체지향의 목표는 실세계를 모방하는 것이 아닌 새로운 세계를 창조하는 것이다. + +객체를 스스로 생각하고 스스로 결정하는 현실 세계의 생명체에 비유하는 것은 상태와 행위를 **'캡슐화'** 하는 소프트웨어 객체의 **'자율성'** 을 설명하는 데 효과적이다. 현실 세계의 사람들이 암묵적인 약속과 명시적인 계약을 기반으로 목표를 달성해 나가는 과정은 **'메시지'** 를 주고받으며 공동의 목표를 달성하기 위해 **'협력'** 하는 객체들의 관계를 설명하는 데 적합하다. + +객체지향이란 +- 시스템을 상호작용하는 자율적인 객체들의 공동체로 바라보고 객체를 이용해 시스템을 분할하는 방법이다. +- 자율적인 객체란 상태와 행위를 함께 지니며 스스로 자기 자신을 책임지는 객체를 의미한다. +- 객체는 시스템의 행위를 구현하기 위해 다른 객체와 협력한다. 각 객체는 협력 내에서 정해진 역할을 수행하며 역할을 관련된 책임의 집합이다. +- 객체는 다른 객체와 협력하기 위해 메시지를 전송하고, 메시지를 수신한 객체는 메시지를 처리하는 데 적합한 메소드를 자율적으로 선택한다. + +## 2. 객체 지향의 이해 +### 2-1. 역할 +역할은 관련성 높은 책임의 집합이다. 객체의 역할은 사람의 역할과 유사하게 다음과 같은 특징을 가진다. +- 여러 객체가 동일한 역할을 수해할 수 있다. +- 역할은 대체 가능성을 의미한다. +- 각 객체는 책임을 수행하는 방법을 자율적으로 선택할 수 있다. +- 하나의 객체가 동시에 여러 역할을 수행할 수 있다. + +역할은 협력 내에서 다른 객체로 대체할 수 있음을 나타내는 일종의 표식이다. 협력 안에서 역할은 "이 자리는 해당 역할을 수행할 수 있는 어떤 객체라도 대신할 수 있습니다."라고 말하는 것과 같다. + +역할을 대체하기 위해서는 각 역할이 수신할 수 있는 메시지를 동일한 방식으로 이해해야 한다. + +역할은 객체지향 설계의 **단순성**, **유연성**, **재사용성**을 뒷받침하는 핵심 개념이다. + +역할의 대체 가능성은 행위 호환성을 의미하고, 행위 호환성은 동일한 책임의 수행을 의미한다. + +### 2-2. 책임 +책임이란 객체가 어떤 행동을 하라고 다른 객체로부터 요청을 수신했을 때 요청을 처리하기 위해 객체가 수행하는 행동 즉, 메시지를 수신받았을 때 그 메시지의 요청을 처리하기 위해 수행하는 행동이다. + +객체의 책임은 크게 두 가지 범주로 분류된다. +- 하는 것 + - 객체를 생성하거나 계산을 하는 등의 스스로 하는 것 + - 다른 객체의 행동을 시작시키는 것 + - 다른 객체의 활동을 제어하고 조절하는 것 +- 아는 것 + - 개인적인 정보에 대해 아는 것 + - 관련된 객체에 대해 아는 것 + - 자신이 유도하거나 계산할 수 있는 것에 대해 아는 것 + +메시지는 객체로 하여금 자신의 책임, 즉 행동을 수행하게 만드는 유일한 방법이다. 메시지를 처리할 수 있다는 것은 객체가 해당 메시지에 해당하는 행동을 수행할 책임이 있다는 것을 의미한다. 따라서 메시지의 개념은 책임의 개념과 연결된다. + +### 2-3. 협력 +객체의 세계에서는 협력이라는 문맥이 객체의 행동 방식을 결정한다. 중요한 것은 개별 객체가 아니라 객체들 사이에 이루어지는 협력이다. + +객체가 다른 객체에게 주어진 책임을 수행하도록 요청을 보내는 것을 **메시지** 전송이라고 한다. 따라서 **두 객체 간의 협력은 메시지를 통해 이루어진다.** + +객체 지향 설계는 협력에 참여하기 위해 어떤 객체가 어떤 책임을 수행해야 하고 어떤 객체로부터 메시지를 수신할 것인지를 결정하는 것으로부터 시작된다. 어떤 클래스가 필요하고 어떤 메소드를 포함해야 하는지를 결정하는 것은 책임과 메시지에 대한 대략적인 윤곽을 잡은 후에 시작해도 늦지 않다. + +## 3. 객체 지향 프로그래밍의 특징 +### 3-1. 추상화(Abstraction) +- 객체들의 공통적인 특징(기능, 속성)을 도출하는 것 +- 객체 지향적 관점에서는 클래스를 정의하는 것을 추상화라고 할 수 있다. + (클래스가 없는 객체 지향 언어도 존재 ex. JavaScript) + +### 3-2. 캡슐화(Encapsulation) +- 실제로 구현되는 부분을 외부에 드러나지 않도록 하여 정보를 은닉할 수 있다. +- 객체가 독립적으로 역할을 할 수 있도록 데이터와 기능을 하나로 묶어 관리하는 것 +- 코드가 묶여있어서 오류가 없어 편리하다. +- 데이터를 보이지 않고 외부와 상호작용을 할 때는 메소드를 이용하여 통신을 한다. 보통 라이브러리로 만들어서 업그레이드해 사용할 수 있다. + +### 3-3. 상속성(Inheritance) +- 하나의 클래스가 가진 특징(함수, 데이터)을 다른 클래스가 그대로 물려받는 것 +- 이미 작성된 클래스를 받아서 새로운 클래스를 생성하는 것 +- 기존 코드를 재활용해서 사용함으로써 객체 지향 방법의 중요한 기능 중 하나에 속한다. + +### 3-4. 다형성(Polymorphism) +- 약간 다른 방법으로 동작하는 함수를 동일한 이름으로 호출하는 것 +- 동일한 명령의 해석을 연결된 객체에 의존하는 것 +- 오버라이딩(Overriding), 오버로딩(Overloading) + - 오버라이딩(Overriding) : 부모 클래스의 메소드와 같은 이름을 사용하며 매개변수도 같되, 내부 소스를 재정의하는 것 + - 오버로딩(Overloading) : 같은 이름의 함수를 여러 개 정의한 후 매개변수를 다르게 하여 같은 이름을 경우에 따라 호출하여 사용하는 것 +- 다형성은 메시지 수신자의 종류를 캡슐화한다. + +## 4. 정리 +객체 지향의 기본 개념은 책임을 수행하는 자율적인 객체들의 협력을 통해 애플리케이션을 구축하는 것이다. 객체지향의 세계에서 객체들이 서로 협력하기 위해 사용할 수 있는 유일한 방법은 **메시지**를 전송하는 것이다. + +**객체지향 애플리케이션의 중심 사상은 연쇄적으로 메시지를 전송하고 수신하는 객체들 사이의 협력 관계를 기반으로 사용자에게 유용한 기능을 제공하는 것이다.** + +클래스 기반의 객체 지향 언어를 사용하는 대부분의 사람들은 객체 지향 애플리케이션을 클래스의 집합으로 생각한다. 프로그래머 입장에서 클래스는 실제 볼 수 있고 수정할 수 있는 구체적인 존재다. 그러나 클래스는 단지 동적인 객체들의 특성과 행위를 정적인 텍스트로 표현하기 위해 사용할 수 있는 추상화 도구일 뿐이다. 중요한 것은 클래스가 아니라 **객체**다. 클래스를 정의하는 것이 먼저가 아니라 객체들의 속성과 행위를 식별하는 것이 먼저다. **클래스는 객체의 속성과 행위를 담는 틀일 뿐이다.** + +객체 지향 설계의 중심에는 메시지가 위치한다. 객체가 메시지를 선택하는 것이 아니라 메시지가 객체를 선택하게 된다. 메시지가 객체를 선택하게 만드려면 메시지를 중심으로 협력을 설계해야 한다. + +책임-주도 설계란 책임을 찾고 책임을 수행할 적절한 객체를 찾아 책임을 할당하는 방식으로 협력을 설계하는 방법을 말한다. +책임-주도 설계의 핵심은 어떤 행위가 필요한지를 먼저 결정한 후에 이 행위를 수행할 객체를 결정하는 것이다. 즉, '어떻게'가 아닌 '무엇을'을 먼저 생각하는 것이다. +이 과정을 흔히 What/Who 사이클이라고 한다. + +> 결론적으로 협력이라는 문맥 안에서 필요한 메시지를 먼저 결정한 후에 메시지를 수신하기에 적합한 객체를 선택한다. 그리고 수신된 메시지가 객체의 책임을 결정한다. + +협력이라는 문맥 안에서 객체의 책임을 결정하는 것은 메시지다. 책임이 먼저 오고 객체가 책임을 따른다. 결과적으로 시스템이 수행해야 하는 전체 행위는 협력하는 객체들의 책임으로 분배된다. + +객체가 자신이 수신할 메시지를 결정하게 하지 말고 메시지가 협력에 필요한 객체를 발견하게 해야 한다. \ No newline at end of file diff --git "a/4\354\243\274\354\260\250/\354\236\220\353\260\224 \352\270\260\354\264\210.md" "b/4\354\243\274\354\260\250/\354\236\220\353\260\224 \352\270\260\354\264\210.md" new file mode 100644 index 00000000..5b43ae44 --- /dev/null +++ "b/4\354\243\274\354\260\250/\354\236\220\353\260\224 \352\270\260\354\264\210.md" @@ -0,0 +1,306 @@ +# [Java] Java 기초(3) +연산자란 하나, 둘 혹은 세 개의 피연산자에 대해서 특정 연산을 수행한 후 **결과를 반환**하는 기호이다. + +간단히 말해 **'연산을 수행하는 기호'**이다. + +피연산자는 **연산의 대상**이라고 할 수 있다. 리터럴이 될 수도 있고, 변수가 될 수도 있으며, 또 다른 식이 될 수도 있다. + +식은 연산자와 피연산자를 조합한 것이고, 이를 수행한 것을 평가한다고 한다. + +> 연산은 식을 평가하고 식의 평가 결과를 반환하는 것 + +## 1. 산술 연산자 +산술 연산자는 우리가 흔히 말하는 더하기, 빼기, 곱하기, 나누기를 수행하는 연산자이다. + +|연산자|설명| +|:---:|---| +|+|더하기 연산자(문자열 연결에도 사용)| +|-|빼기 연산자| +|* |곱하기 연산자| +|/|나누기 연산자| +|%|나머지(모듈로) 연산자| + +```java +int result = 1 + 2; +System.out.println("1 + 2 = " + result); // 3 + +int originalResult = result; +result = originalResult - 1; +System.out.println(originalResult + " - 1 = " + result); // 2 + +originalResult = result; +result = originalResult * 7; +System.out.println(originalResult + " * 7 = " + result); // 14 + +originalResult = result; +result = originalResult / 3; +System.out.println(originalResult + " / 3 = " + result); // 4 + +result = originalResult % 3; +System.out.println(originalResult + " % 3 = " + result); // 2 + +double doubleResult = 14.0 / 3.0; +System.out.println("14.0 / 3.0 = " + doubleResult); // 4.66667 + +doubleResult = 14.0 % 3.0; +System.out.println("14.0 % 3.0 = " + doubleResult); // 2.0 + +doubleResult = 14.0 / 0.0; +System.out.println("14.0 / 0.0 = " + doubleResult); // Infinity + +doubleResult = -14.0 / 0.0; +System.out.println("14.0 / 0.0 = " + doubleResult); // -Infinity + +doubleResult = 14.0 % 0.0; +System.out.println("14.0 % 0.0 = " + doubleResult); // NaN + +doubleResult = -14.0 % 0.0; +System.out.println("14.0 % 0.0 = " + doubleResult); // NaN + +try { + result = 14 / 0; // ArithmeticException: / by zero +} catch (ArithmeticException e) { + System.out.println("14 / 0 = " + e.getMessage()); +} + +try { + result = 14 % 0; // ArithmeticException: / by zero +} catch (ArithmeticException e) { + System.out.println("14 % 0 = " + e.getMessage()); +} +``` + +정수형일 때 0으로 나누거나 모듈로 연산을 수행하는 것을 조심해야 한다. 이는 런타임에 발생하는 오류이기 때문에 컴파일타임에 확인할 수 없다. + +또한 자료형의 크기에 따른 오버플로우도 조심해야 한다. + +실수형은 연산 과정 자체에서 오차가 발생할 수 있으며 이를 조심해야 한다. 이는 특히 테스트 코드를 작성할 때, 어느 정도의 오차를 허용할 것인지 반드시 설정해주어야 하는 이유이다. + +실수형은 0으로 나누거나 모듈로 연산을 사용하면 위와 같이 ```Infinity```, ```-Infinity```, ```NaN``` 값을 가진다. +(```Infinity```와 ```NaN```이 피연산자인 경우도 존재) + +### 1-1. 단항 연산자 +```+```를 붙이면 양수 값을 나타낸다. (생략 가능) +```-```를 붙이면 음수 값을 나타낸다. + +### 1-2. 증감 연산자 +```++```를 붙이면 값을 1씩 증가시킨다. +```--```를 붙이면 값을 1씩 감소시킨다. +```++```, ```--```는 오른쪽에 위치하는 경우 식을 평가하기 전에 증가시키고, 왼쪽에 위치하는 경우 식을 평가한 후에 증가시킨다. + +```java +int result = 1; +System.out.println(result); // 1 + +result--; +System.out.println(result); // 0 + +result++; +System.out.println(result); // 1 + +for (int i = 0; i < 3; i++) { + System.out.println(++result); // 2, 3, 4 +} + +System.out.println(result); // 4(이미 이전에 증가해서 그대로 출력된다.) + +for (int i = 0; i < 3; i++) { + System.out.println(result++); // 4, 5, 6 +} + +System.out.println(result); // 7(마지막에 증가한다.) +``` +> 증감 연산자가 앞에 오면 먼저 증가/감소시키고, 대입 후 계산 +> 증감 연산자가 뒤에 오면 먼저 대입시키고, 계산 후 증가/감소 + +## 2. 비트 연산자 +Java에서는 정수 타입에 대해서 비트와 시프트 연산을 제공하는데 이를 비트 연산자라고 한다. + +우리가 사용하는 정수 타입을 컴퓨터가 이해할 수 있도록 이진수 형식으로 표현된다. 이 이진수 조각 하나 하나를 비트라고 표현하고, 비트 연산은 각 비트마다의 연산을 수행한다. + +```~```는 ```NOT``` 연산으로, 비트를 반전시키는 단항 연산자이다. +```&```는 ```AND``` 연산으로, 피연산자들의 비트별로 ```AND``` 연산을 수행하게 된다. +```|```는 ```OR``` 연산으로, 피연산자들의 비트별로 ```OR``` 연산을 수행하게 된다. +```^```는 ```XOR``` 연산으로, 피연산자들의 비트별로 ```XOR``` 연산을 수행하게 된다. + +|x|~x| +|:---:|:---:| +|0|1| +|1|0| +
+ +|x|y|x \| y|x & y|x ^ y| +|:---:|:---:|:---:|:---:|:---:| +|1|1|1|1|0| +|1|0|1|0|1| +|0|1|1|0|1| +|0|0|0|0|0| + +```java +// 참고로 부호비트도 고려해야 합니다. +byte a = 0b00001010; // 10 (0|0001010) +byte b = 0b00101000; // 40 (0|0101000) +byte c = -0b00001010; // -10 (1|1110110) + +// ~ 연산자(1의 보수를 만들어줌) +System.out.println(~a); // 1|1110101 => -11 여기에 1을 더하면 -10이 됩니다.(2의 보수) +System.out.println(~c); // 0|0001001 => 9 여기에 1을 더하면 10이 됩니다. + +// & 연산자 +System.out.println(a & b); // 0|0001000 => 8 +System.out.println(a & c); // 0|0000010 => 2 +System.out.println(b & c); // 0|0100000 => 32 + +// | 연산자 +System.out.println(a | b); // 0|0101010 => 42 +System.out.println(a | c); // 1|1111110 => -2 +System.out.println(b | c); // 1|1111110 => -2 + +// ^ 연산자(다른 경우에만 1) +System.out.println(a ^ b); // 0|0100010 => 34 +System.out.println(a ^ c); // 1|1111100 => -4 +System.out.println(b ^ c); // 1|1011110 => -34 +``` + +### 2-1. 시프트 연산자 +시프트 연산자는 피연산자의 각 비트를 오른쪽(```>>```) 또는 왼쪽 (```<<```)으로 이동시키는 연산자이다. + +```<<``` 연산자의 경우 빈 칸을 0으로 채우면 되지만, ```>>``` 연산자는 음수일 때는 1로, 양수일 때는 0으로 빈칸을 채운다. + +> ```x << n``` 연산은 x * 2n과 같다. +> ```x >> n``` 연산은 x / 2n과 같다. + +이를 사용하는 이유는 비트 연산이 일반 산술 연산보다 속도가 빠르기 때문이다. 하지만 가독성이 떨어지므로 성능 개선이 필수적인 부분에서만 사용해야 한다. + +Unsigned Right 시프트 연산자(```>>>```)는 오른쪽으로 이동하되, 빈칸을 0으로 채운다. + +## 3. 관계 연산자 +관계 연산자는 피연산자가 같은지(```==```), 같지 않은지(```!=```), 큰지(```>```), 크거나 같은지(```>=```), 작은지(```<```), 작거나 같은지(```<=```) 비교하는 연산자들이다. + +연산 결과가 맞으면 true, 틀리면 false로 boolean 타입을 반환한다. + +```java +System.out.println(a == b); // false +System.out.println(a != b); // true +System.out.println(a > b); // false +System.out.println(a >= b); // false +System.out.println(a < b); // true +System.out.println(a <= b); // true +``` +> 문자열의 동등성을 비교할 때에는 ```equals()``` 메소드를 사용해야 한다. + +## 4. 논리 연산자 +논리 연산자는 피연산자로 boolean 값을 받으며, 이는 평가의 결과가 될 수도 있다. + +```&&``` 연산자는 두 연산결과가 참인지 판단한다. 만약 둘 중 하나라도 거짓이라면 거짓을 반환한다. 만약, 왼쪽의 피연산자가 거짓이라면 오른쪽의 피연산자는 평가하지 않는다. +```||``` 연산자는 두 연산결과 중 한 쪽만 참이어도 참을 반환한다. 만약, 왼쪽의 피연산자가 참이라면 오른쪽의 피연산자는 평가하지 않는다. +```!``` 연산자는 피연산자를 하나만 받는 단항 연산자이며, true를 false로, false를 true로 변경한다. 식의 평가 방향은 오른쪽에서 왼쪽이다. + +위에서 말한 평가하지 않는 것을 **short circuit evaluation**이라고 하며, 식의 평가를 수행하지 않기 때문에 좀 더 빠른 결과를 얻을 수 있다. + +## 5. instanceof +```instanceof``` 연산자는 타입 비교 연산자이다. 이를 이용해 객체가 클래스의 인스턴스, 하위 클래스의 인스턴스 또는 특정 인터페이스를 구현하는 클래스의 인스턴스인지 테스트할 수 있다. + +```java +public class Main { + + public static void main(String[] args) { + Animal animal1 = new Animal(); + Animal animal2 = new Cat(); + + System.out.println("animal1 is instanceof Animal: " + (animal1 instanceof Animal)); // true + System.out.println("animal1 is instanceof Cat: " + (animal1 instanceof Cat)); // false + System.out.println("animal1 is instanceof Meowable: " + (animal1 instanceof Meowable)); // false + + System.out.println("animal2 is instanceof Animal: " + (animal2 instanceof Animal)); // true + System.out.println("animal2 is instanceof Cat: " + (animal2 instanceof Cat)); // true + System.out.println("animal2 is instanceof Meowable: " + (animal2 instanceof Meowable)); // true + } +} + +class Animal {} +interface Meowable {} +class Cat extends Animal implements Meowable {} +``` + +## 6. assignment(=) operator +할당 연산자(```=```)는 연산자 오른쪽의 값을 연산자 왼쪽의 피연산자에 할당한다. 식의 평가 방향은 오른쪽에서 왼쪽이다. + +```int x = 0;``` +위와 같은 연산자는 ```x```라는 이름을 가진 변수 공간에 0이라는 ```int```형 리터럴을 할당한다. + +또한, 객체도 할당할 수 있다. + +```Animal animal = new Cat();``` +위와 같은 식은 ```animal```이라는 ```Animal``` 타입 참조 변수에 새로 만들어진 ```Cat``` 인스턴스의 참조를 할당한다. + +할당할 수 없는 리터럴과 같은 값은 왼쪽 피연산자가 될 수 없다. + +### 6-1. 복합문(Compound Statement), 복합 할당(Compond Assignment) +다른 연산자와 할당 연산자를 결합한다. + +```a = a + 1;``` 이라는 식의 경우 ```a```가 중복된다. 이를 간단히 나타내기 위해 ```a += 1;```로 표현할 수 있다. + +|대입 연산자|기능| +|:---:|---| +|=|왼쪽의 피연산자에 오른쪽 피연산자 대입| +|+=|왼쪽의 피연산자에 오른쪽의 피연산자를 더한후, 그 결과 값을 왼쪽의 피연산자를 대입| +|-=|왼쪽의 피연산자에 오른쪽의 피연산자를 뺀후, 그 결과 값을 왼쪽의 피연산자를 대입| +|*=|왼쪽의 피연산자에 오른쪽의 피연산자를 곱한후, 그 결과 값을 왼쪽의 피연산자를 대입| +|/=|왼쪽의 피연산자에 오른쪽의 피연산자를 나눈후, 그 결과 값을 왼쪽의 피연산자를 대입| +|%=|왼쪽의 피연산자에 오른쪽의 피연산자를 나눈후, 그 나머지 값을 왼쪽의 피연산자를 대입| +|&=|왼쪽의 피연산자에 오른쪽의 피연산자와 비트 & 연산후, 그 결과 값을 왼쪽의 피연산자를 대입| +|\|=|왼쪽의 피연산자에 오른쪽의 피연산자와 |연산후, 그 결과 값을 왼쪽의 피연산자를 대입| +|^=|왼쪽의 피연산자에 오른쪽의 피연산자와 ^연산후, 그 결과 값을 왼쪽의 피연산자를 대입| +|<<=|왼쪽의 피연산자에 오른쪽의 피연산자만큼 왼쪽 시프트 후, 그 결과 값을 왼쪽의 피연산자를 대입| +|>>=|왼쪽의 피연산자에 오른쪽의 피연산자만큼 부호 유지 오른쪽 시프트후, 그 결과 값을 왼쪽의 피연산자를 대입| +|>>>=|왼쪽의 피연산자에 오른쪽의 피연산자만큼 부호에 상관없이 오른쪽 시프트 후, 그 결과 값을 왼쪽의 피연산자를 대입| + +## 7. 화살표(->) 연산자 +화살표 연산자는 Java8에서 추가된 람다 표현식의 한 부분이다. + +```(파라미터) -> { 함수몸체 }``` 형태로 작성한다. + +람다 표현식은 함수형 프로그래밍에서 가장 중요한 부분 중 하나이며, 이를 도입함으로써 Java는 함수형 언어로도 기능하게 되었다. 이는 일부 익명 클래스를 간단히 표현할 수 있는 방법이라고도 볼 수 있다. +또한 ```@FunctionalInterface``` 어노테이션을 붙인 인터페이스의 구현체로도 사용할 수 있다. + +IntelliJ에서는 이런 람다 표현식으로 코드를 변경시켜주는 기능이 내장되어 있다. + +람다식은 메소드가 매개변수로 전달되는 것이 가능하고, 결과로 반환되는 것도 가능하게 해준다. + +## 8. 삼항 연산자 +```? :```는 논리 연산자의 일종으로 피연산자 세 개를 받는 유일한 연산자여서 삼항 연산자로 많이 불린다. +이는 ```if-else```문과 비슷하게 보이며, 한 줄로 간단하게 표현할 수 있다. + +```조건 ? 참일 때 값 : 거짓일 때 값```의 표현으로 사용한다. + +## 9. 연산자 우선 순위 +연산자 우선 순위는 식을 평가할 때 많은 영향을 미친다. 우선 순위에 따라서 의도한 대로 프로그램이 동작하지 않을 수 있기 때문이다. + +아래 표는 연산자의 우선순위를 나타낸 표이다. 상단에 가까울 수록 우선순위가 높으며, 같은 줄의 연산자는 동일한 우선순위를 가진다. 이런 경우 식의 평가순서가 영향을 미치게 된다. 할당 연산자를 제외한 모든 이항 연산자는 왼쪽에서 오른쪽으로 평가되며, 할당 연산자는 오른쪽에서 왼쪽으로 평가한다. + +![](https://images.velog.io/images/minide/post/e217f152-0888-4790-9201-1d2459872f8c/%EC%97%B0%EC%82%B0%EC%9E%90%20%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84.png) + +실제 프로그래밍을 할 때는 헷갈릴 가능성이 높으므로 ```()```로 먼저 수행하고 싶은 식을 묶어주는 것이 가독성 등의 여러 관점에서 더 좋다. + +## 10. switch 연산자 +기존 switch문에서는 다수의 ```case```와 ```break```가 존재하게 된다. ```break```를 빼먹을 경우 다음 분기로 넘어가고, return값이 존재할 수 없다. + +switch 연산자에서는 ```break```를 사용하지 않아도 된다. ```yield``` 예약어를 사용해 값을 return 할 수 있다. +```case -> A```와 같이 표현하거나 ```break``` 대신 ```yield```로 return 값을 반환해주도록 표현한다. +```java +switch(expression){ + case expression -> expression; + ... + default -> expression +}; + +switch(expression){ + case expression: + expression; + yield expression; + ... + default: + expression; + yield expression; +}; \ No newline at end of file diff --git "a/4\354\243\274\354\260\250/\355\224\204\353\241\234\352\267\270\353\236\230\353\260\215\352\263\274\354\240\2341/build.gradle" "b/4\354\243\274\354\260\250/\355\224\204\353\241\234\352\267\270\353\236\230\353\260\215\352\263\274\354\240\2341/build.gradle" new file mode 100644 index 00000000..353aec80 --- /dev/null +++ "b/4\354\243\274\354\260\250/\355\224\204\353\241\234\352\267\270\353\236\230\353\260\215\352\263\274\354\240\2341/build.gradle" @@ -0,0 +1,19 @@ +plugins { + id 'java' +} + +group 'org.javastudy' +version '1.0-SNAPSHOT' + +repositories { + mavenCentral() +} + +dependencies { + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.0' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine' +} + +test { + useJUnitPlatform() +} \ No newline at end of file diff --git "a/4\354\243\274\354\260\250/\355\224\204\353\241\234\352\267\270\353\236\230\353\260\215\352\263\274\354\240\2341/gradle/wrapper/gradle-wrapper.jar" "b/4\354\243\274\354\260\250/\355\224\204\353\241\234\352\267\270\353\236\230\353\260\215\352\263\274\354\240\2341/gradle/wrapper/gradle-wrapper.jar" new file mode 100644 index 00000000..e708b1c0 Binary files /dev/null and "b/4\354\243\274\354\260\250/\355\224\204\353\241\234\352\267\270\353\236\230\353\260\215\352\263\274\354\240\2341/gradle/wrapper/gradle-wrapper.jar" differ diff --git "a/4\354\243\274\354\260\250/\355\224\204\353\241\234\352\267\270\353\236\230\353\260\215\352\263\274\354\240\2341/gradle/wrapper/gradle-wrapper.properties" "b/4\354\243\274\354\260\250/\355\224\204\353\241\234\352\267\270\353\236\230\353\260\215\352\263\274\354\240\2341/gradle/wrapper/gradle-wrapper.properties" new file mode 100644 index 00000000..be52383e --- /dev/null +++ "b/4\354\243\274\354\260\250/\355\224\204\353\241\234\352\267\270\353\236\230\353\260\215\352\263\274\354\240\2341/gradle/wrapper/gradle-wrapper.properties" @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git "a/4\354\243\274\354\260\250/\355\224\204\353\241\234\352\267\270\353\236\230\353\260\215\352\263\274\354\240\2341/gradlew" "b/4\354\243\274\354\260\250/\355\224\204\353\241\234\352\267\270\353\236\230\353\260\215\352\263\274\354\240\2341/gradlew" new file mode 100755 index 00000000..4f906e0c --- /dev/null +++ "b/4\354\243\274\354\260\250/\355\224\204\353\241\234\352\267\270\353\236\230\353\260\215\352\263\274\354\240\2341/gradlew" @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git "a/4\354\243\274\354\260\250/\355\224\204\353\241\234\352\267\270\353\236\230\353\260\215\352\263\274\354\240\2341/gradlew.bat" "b/4\354\243\274\354\260\250/\355\224\204\353\241\234\352\267\270\353\236\230\353\260\215\352\263\274\354\240\2341/gradlew.bat" new file mode 100644 index 00000000..ac1b06f9 --- /dev/null +++ "b/4\354\243\274\354\260\250/\355\224\204\353\241\234\352\267\270\353\236\230\353\260\215\352\263\274\354\240\2341/gradlew.bat" @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git "a/4\354\243\274\354\260\250/\355\224\204\353\241\234\352\267\270\353\236\230\353\260\215\352\263\274\354\240\2341/settings.gradle" "b/4\354\243\274\354\260\250/\355\224\204\353\241\234\352\267\270\353\236\230\353\260\215\352\263\274\354\240\2341/settings.gradle" new file mode 100644 index 00000000..64cf2835 --- /dev/null +++ "b/4\354\243\274\354\260\250/\355\224\204\353\241\234\352\267\270\353\236\230\353\260\215\352\263\274\354\240\2341/settings.gradle" @@ -0,0 +1,2 @@ +rootProject.name = 'javastudy' + diff --git "a/4\354\243\274\354\260\250/\355\224\204\353\241\234\352\267\270\353\236\230\353\260\215\352\263\274\354\240\2341/src/main/java/Calculator.java" "b/4\354\243\274\354\260\250/\355\224\204\353\241\234\352\267\270\353\236\230\353\260\215\352\263\274\354\240\2341/src/main/java/Calculator.java" new file mode 100644 index 00000000..a5398c12 --- /dev/null +++ "b/4\354\243\274\354\260\250/\355\224\204\353\241\234\352\267\270\353\236\230\353\260\215\352\263\274\354\240\2341/src/main/java/Calculator.java" @@ -0,0 +1,20 @@ +public class Calculator { + public int add(int a, int b) { + return a + b; + } + + public int sub(int a, int b) { + return a - b; + } + + public int mul(int a, int b) { + return a * b; + } + + public int div(int a, int b) { + if (b == 0) { + throw new IllegalArgumentException("숫자 0으로 나눌 수 없습니다."); + } + return a / b; + } +} diff --git "a/4\354\243\274\354\260\250/\355\224\204\353\241\234\352\267\270\353\236\230\353\260\215\352\263\274\354\240\2341/src/main/java/Operator.java" "b/4\354\243\274\354\260\250/\355\224\204\353\241\234\352\267\270\353\236\230\353\260\215\352\263\274\354\240\2341/src/main/java/Operator.java" new file mode 100644 index 00000000..642a632b --- /dev/null +++ "b/4\354\243\274\354\260\250/\355\224\204\353\241\234\352\267\270\353\236\230\353\260\215\352\263\274\354\240\2341/src/main/java/Operator.java" @@ -0,0 +1,48 @@ +import java.io.BufferedReader; +import java.io.InputStreamReader; + +public class Operator { + private static int sum; + private static int num; + + public static void inputFormula() throws Exception { + BufferedReader bf = new BufferedReader(new InputStreamReader(System.in)); + String arr[] = bf.readLine().split(" "); + + // 문자 입력 예외 처리 + try { + sum = Integer.parseInt(arr[0]); + } catch (Exception e) { + throw new IllegalArgumentException("숫자가 아닌 문자가 입력되었습니다."); + } + + executeCalc(arr); + } + + public static void executeCalc(String[] arr) throws Exception { + Calculator calculator = new Calculator(); + + for (int i = 1; i < arr.length; i = i + 2) { + // 문자 입력 예외 처리 + try { + num = Integer.parseInt(arr[i + 1]); + } catch (Exception e) { + throw new IllegalArgumentException("숫자가 아닌 문자가 입력되었습니다."); + } + + // 계산 + if (arr[i].equals("+")) { + sum = calculator.add(sum, num); + } else if (arr[i].equals("-")) { + sum = calculator.sub(sum, num); + } else if (arr[i].equals("*")) { + sum = calculator.mul(sum, num); + } else if (arr[i].equals("/")) { + sum = calculator.div(sum, num); + } + + System.out.println(sum); + } + System.out.println("계산 값 : " + sum); + } +} diff --git "a/4\354\243\274\354\260\250/\355\224\204\353\241\234\352\267\270\353\236\230\353\260\215\352\263\274\354\240\2341/src/main/java/main.java" "b/4\354\243\274\354\260\250/\355\224\204\353\241\234\352\267\270\353\236\230\353\260\215\352\263\274\354\240\2341/src/main/java/main.java" new file mode 100644 index 00000000..1fea8015 --- /dev/null +++ "b/4\354\243\274\354\260\250/\355\224\204\353\241\234\352\267\270\353\236\230\353\260\215\352\263\274\354\240\2341/src/main/java/main.java" @@ -0,0 +1,6 @@ +public class main { + public static void main(String[] args) throws Exception { + Operator operator = new Operator(); + operator.inputFormula(); + } +} \ No newline at end of file