본문 바로가기
Java & Spring

[Java] 람다식 안에서 변수를 사용하는 방법

by softserve 2022. 9. 16.
반응형

1. 문제점.

다음은 입력받은 두 문자열이 아나그램(한 단어에서 알파벳의 순서만 바꾼 것, 예: god dog)에 해당하는지 검사하는 간단한 프로그램입니다. 해쉬맵에 각 문자와 개수를 저장한 뒤, 해쉬맵이 서로 일치하는지 검사합니다.

이 때 해쉬맵이 서로 일치하는지 판단하기 위해 forEach 메소드를 사용했습니다. 그리고 내부에 람다식을 넣어 hm1의 값과 hm2의 값이 서로 일치하지 않으면 result 를 false로 변경해주려 했습니다.

딱히 이상할 것이 없어보이는 코드인데 빨간 줄이 똭!

Variable used in lambda expression should be a final or effectively final.

라고 하네요.

람다식 내부에서는 final 이거나 effectively final인 변수만 사용할 수 있다는 겁니다.

바로 return을 하는 것도 안 됩니다.

Scanner sc = new Scanner(System.in);
String s1 = sc.next();
String s2 = sc.next();
Boolean result = true;

HashMap<Character, Integer> hm1 = new HashMap<>();
HashMap<Character, Integer> hm2 = new HashMap<>();

if(s1.length() != s2.length()) return false;
for(int i = 0; i < s1.length(); i++) {
    char next1 = s1.charAt(i);
    char next2 = s2.charAt(i);
    int cnt1 = 0, cnt2 = 0;

    if(hm1.get(next1) != null) cnt1 = hm1.get(next1);
    if(hm2.get(next2) != null) cnt2 = hm2.get(next2);
    hm1.put(next1, cnt1 + 1);
    hm2.put(next2, cnt2 + 1);
}


hm1.forEach((key, value)->{
    if(value != hm2.get(key)) {
    	result = false; (X)
        return false;   (X)
    }
});

return result;

 

2. 원인

(1) java의 람다식 또는 익명 클래스 내부에서는 final이거나 effectively final외부 지역 변수에만 접근할 수 있습니다.

final은 최초 1회 할당된 후 변경되지 않는 엔티티를 의미합니다.

effectively final은 명시적으로 final은 아니나, 실질적으로 final처럼 사용되는 경우를 말합니다.

즉,

final int realFinal = 10;

int effectivelyFinal = 10;

final 키워드로 선언된 변수, 메서드, 클래스는 final이므로 값을 변경할 수 없고,

final로 선언하지는 않았지만 코드 상에서 값이 변경되지 않는 변수는 effectively final 이라고 할 수 있습니다.

위 코드에서 result 는 람다식 외부에서 선언된 지역 변수이므로 람다식 내부에서는 접근할 수가 없습니다.

(2) 왜?

는 나중에 알아보도록 하고 우선 문제를 해결하겠습니다.

(참조 : https://vagabond95.me/posts/lambda-with-final/)

 

3. 해결

① 별도의 클래스를 만들고 객체를 생성하여 값을 저장해주는 방법

class result {
    public String result = "";
}

② 클래스 변수를 선언하여 사용하는 방법

import java.util.*;

public class Problem {
    String result = "YES";
    public String solve() {
        Scanner sc = new Scanner(System.in);
        String s1 = sc.next();
        String s2 = sc.next();
        HashMap<Character, Integer> hm1 = new HashMap<>();
        HashMap<Character, Integer> hm2 = new HashMap<>();

        if(s1.length() != s2.length()) return "NO";
        for(int i = 0; i < s1.length(); i++) {
            char next1 = s1.charAt(i);
            char next2 = s2.charAt(i);
            int cnt1 = 0, cnt2 = 0;

            if(hm1.get(next1) != null) cnt1 = hm1.get(next1);
            if(hm2.get(next2) != null) cnt2 = hm2.get(next2);
            hm1.put(next1, cnt1 + 1);
            hm2.put(next2, cnt2 + 1);
        }

        Result r = new Result();
        hm1.forEach((key, value)->{
            if(value != hm2.get(key)) {
            	result = "NO";
            }
        });

        return result;
    }
}

 

반응형

'Java & Spring' 카테고리의 다른 글

[Java] 자료구조 - LinkedList  (0) 2022.09.28
[Java] 자료구조 - 큐(Queue)  (0) 2022.09.22
java) 예외 처리  (0) 2021.12.13
java) 스레드 Thread 와 동기화  (0) 2021.12.09
Java 입출력을 위한 BufferedReader / BufferedWriter  (0) 2021.11.14

댓글