파일 구조
- Cal(계산인터페이스)
- CalResult(계산결과게터세터)
- ResultCollection(결과저장인터페이스)
- Main
package org.example;
@FunctionalInterface
public interface Cal{
double cal(double x, double y);
}
package org.example;
import java.util.ArrayList;
import java.util.List;
public interface ResultCollection {
List<Double> list = new ArrayList<>();
}
package org.example;
public class CalResult<T> { //결과를 제네릭으로 저장
private T result;
public T getResult() {
return result;
}
public void setResult(T result) {
this.result = result;
}
}
계산 결과는 제네릭으로 저장하여 좀 더 유동적으로 동작할 수 있도록 구현하였다.
public enum OperatorType{ //enum과 람다식 결합
ADD('+', (x,y) -> x + y),
SUB('-', (x,y) -> x - y),
MUL('*', (x,y) -> x * y),
DIV('/', (x,y) -> x / y),
MOD('%', (x,y) -> x % y);
private final char symbol;
private final Cal cal;
OperatorType(char symbol, Cal cal) { //생성자
this.symbol = symbol;
this.cal = cal;
}
public char getSymbol(){ //연산자 받아오기
return symbol;
}
public double cal(double x, double y){ //계산식(연산자는 람다로)
return cal.cal(x,y);
}
public static OperatorType findSymbol(char symbol){
for(OperatorType op : values()){
if (op.getSymbol() == symbol)
return op;
}
return null;
}
}
첫번째로 계산해주는 코드를 간략화 하기 위해 enum으로 각 연산자를 구분하였고, 그 안에 람다식인 (double x, double y) -> x 연산자 y) 를 사용하여 연산자만 구분된다면 알아서 계산이 수행되게 구현하였다.
또한 main메서드에서 입력할 char symbol 연산자를 가져오기 위해 findSymbol함수를 작성하였다.
OperatorType(char symbol, Cal cal) { //생성자
this.symbol = symbol;
this.cal = cal;
}
for(OperatorType op : values()){
if (op.getSymbol() == symbol)
return op;
}
return null;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while(true) { //원할때까지 계산 반복
System.out.print("Type first Number ");
double firstNum = sc.nextDouble();
System.out.print("Type calculator symbols ");
char symbols = sc.next().charAt(0);
System.out.print("Type second Number ");
double secondNum = sc.nextDouble();
OperatorType op = OperatorType.findSymbol(symbols); //연산자 타입 판단하기
if (op == null) { // 연산자가 아닐경우 오류 처리
System.out.println("plz type symbols (+, -, %, *, /)");
continue;
}
if ((op == OperatorType.DIV || op == OperatorType.MOD) && secondNum == 0) { // 0으로 나눌경우 오류처리
System.out.println("Can't div with 0");
continue;
}
CalResult<Double> result = new CalResult<Double>(); //결과값 제네릭으로 선언
result.setResult(op.cal(firstNum, secondNum));
System.out.println("The result is " + result.getResult());
ResultCollection.list.add(result.getResult());
System.out.println("Only results greater than the typed number will be displayed.");
double d = sc.nextDouble();
ResultCollection.list.stream()
.filter(ResultCollection -> ResultCollection > d)
.forEach(System.out::println);
System.out.println("If you want calculate again, type 1");
int keepCal = sc.nextInt();
if(keepCal != 1) break;
}
}
main에서는 연산자를 가져오는 과정과 연산자의 타입에 따른 오류처리를 추가하였다.
만약 연산자를 입력해야되는 부분에서 연산자가 아니거나 다른타입의 데이터를 입력할경우 연산자를 입력해 달라는 말과 함께 이후의 함수를처리하지 않고 넘어간다.
또한, 나누기나 나머지 연산의 경우에 0으로 나눌경우 오류가 발생하므로 연산자가 DIV, MOD이고 입력한 두번째 값이 0이면 그 이후의 코드를 실행하지 않게 만들었다.
CalResult<Double> result = new CalResult<Double>();
result.setResult(op.cal(firstNum, secondNum)); //계산과 동시에 결과값으로 설정
System.out.println("The result is " + result.getResult());
ResultCollection.list.add(result.getResult());
System.out.println("Only results greater than the typed number will be displayed.");
double d = sc.nextDouble();
ResultCollection.list.stream()
.filter(ResultCollection -> ResultCollection > d)
.forEach(System.out::println);
오류 처리과정이 무사히 넘어갔다면 그 다음으론 결과를 계산하여 컬렉션에 저장하는 과정을 거친다.
또한, 컬렉션에 저장해놓은 값을 활용해보고자, Scanner를 활용하여 입력받은 값보다 더 큰 값만 컬렉션에서 가져오는 코드를 작성해보았다.
여태까지 공부했던 내용들을 활용해보고자 람다, 스트림, 컬렉션등을 사용해 보았다.
enum내부에 람다식을 구현하면서 이를 활용하는 코드를 작성하는 부분이 비직관적으로 느껴져 조금 어려웠다.
이를 해결하기위해 인텔리제이의 단축키인 Alt + Insert를 활용하여 생성자와 게터를 만들고 연산자를 알아볼 수 있는 코드를 작성하였다.
이를 제외하곤 코드를 구현하는데 어려움은 없었다.
이후에 수정할 점 및 추가할점은
등이 있다.