본문 바로가기

TIL

삭제한데이터를 undo 하는 기능 만들기

계산기 기능중 계산결과를 삭제하는 기능이 있습니다.

이 삭제된 결과를 어딘가에 저장 해 두었다가 삭제 취소 시 삭제 했던 데이터를 다시 가져오는 기능을 추가해 보고자합니다. 

 

    private final ArrayList<T> deletedList = new ArrayList<>();

일단 삭제된 데이터들을 저장하는 변수를 하나 만들어줍니다.

해당 변수는 외부에서 접근을 못하게 막아야 하고, 다시 set할수 없게 하기위해서 private final키워드를 이용해줬습니다.

 

따로 새로 add메서드는 만들어주지 않을 것입니다.

왜냐하면 기존에 만들어둔 삭제하는 메서드에 제거된 요소를 deletedList에 추가만 해주면 되기때문입니다. 

여기서 저 removeFirst 메서드에서 반환해 주는 값을 확인 하기 위해

public void removeFristCalculateResult() {
        if(this.calculateResult.isEmpty()){
            System.out.println("계산된 결과가 없습니다, 먼저 계산을 진행 해 주세요.");
            return ;
        }
        T removedValue = this.calculateResult.removeFirst();
        this.deletedList.add(removedValue);
        System.out.println("삭제 후 결과 : " + this.calculateResult);
    }

메서드 안으로 들어가보니, oldValue를 반환 해 주는것을 확인 할 수 있습니다.

그렇게 반환 받은 삭제된 요소를 deletedList에 add해주면 삭제된 데이터를 저장해주는건 끝납니다. 

다음은 유저가 삭제취소 요청 시 삭제되어있던 리스트 중 하나를 가져와 다시 저장하는 메서드입니다.

요구사항은 아래와 같습니다.

1. 가장 나중에 삭제된 데이터가 가장먼저 복구됩니다.

2. 복구된 데이터는 배열의 가장 앞으로 들어갑니다.

public void undoDelete(){
        if(deletedList.isEmpty()){
            System.out.println("복구할 데이터가 없습니다.");
            return;
        }
        T deletedValue = this.deletedList.removeLast();
        System.out.println("deletedValue = " + deletedValue);
        this.calculateResult.addFirst(deletedValue);

        System.out.println("현재 저장된 결과 : " + this.calculateResult);
    }

그렇기 때문에 removeLast 메서드를 사용하여 가장 나중에 저장된 데이터를 가져옵니다.(마찬가지로 삭제된 데이터를 리턴합니다)

해당 값을 계산 결과 가장 앞에 추가해줍니다. (해당 메서드는 반환 타입이 void이기때문에 this 키워드를 사용해 데이터를 출력합니다)

 

이렇게 간단하게 기능을 하나 추가해 보았는데 과정중 알게된 사실이있습니다. 

 

final 키워드에대한 오해

저는 final키워드를 사용하면 내부적으로 아예 요소 수정을 하면 안되는건줄 알았습니다. (수정이 되는것은 알았는데 왜 수정이 되는거지??했음)

 

근데 이제 deletedList 를 만들면서 아 이건 아무리 생각해도 class바깥에서 set하거나 get할 이유없이 추가 삭제는 외부가 모르게 동작해도 될거같은데 하는 생각이들었습니다. 

그럼 setter getter가 필요 없는데 그러면 계속

"필드 'deletedList'이(가) 'final'이 될 수 있습니다 " 경고가 나와서 이게 왜 뜨는거지?? 하고 튜텨님에게 물어보니

해당 필드는 일단 final 로 선언 되어야 하는게 맞고 제가 한가지 오해를 하고있었습니다. 

 

final 로 선언된 필드는 "바깥"에서 제어할 수 없게 만드는게 목적이다.

무슨 말이냐면 제가 calcualate라는 객체를 만들면 그 객체가 가지고있는 필드들은 외부에서 새로운 결과로 할당해줄 필요가 없습니다.

예를 들어서 final로 선언하지 않고 setter메서드를 통해 재할당이 가능하다면

 

Calculator<Double> calculator1 = new Calculator<>();
Calculator<Double> calculator2 = new Calculator<>();

calculator1.setCalculateResult(calculator2.getCalculateResult());
calculator2.setCalculateResult(calculator1.getCalculateResult());

이렇게 calculator1 의 계산 결과에 calculator2의 계산 결과를 넣어버리고

calculator2 의 계산 결과에 calculator1의 결과를 넣어버리는 참사가 일어날 수 있습니다.

 

즉, 여기서의 final은 요소의 데이터값을 수정을 못하게 하는 개념이 아니라 객체가 고유하게 가지고있어야 할 필드를 선언해준다고 생각하면 될거같습니다.

'TIL' 카테고리의 다른 글

의존성 주입 해보기 (DI)  (0) 2026.01.15
Java의 record 클래스 타입으로 상세기록 만들기  (0) 2026.01.14
이중콜론(::)(매서드 참조)표현식  (0) 2026.01.14
enum이란 무엇인가?  (0) 2026.01.13
Flowchart에 대하여.  (0) 2026.01.13