Java에서는 필요하지 않은 경우에도 매개 변수 및 로컬에 "최종"을 사용해야합니까?


105

Java는 변수 (필드 / 로컬 / 매개 변수)를로 표시하여 변수에 final재 할당되지 않도록합니다. 일부 속성 또는 전체 클래스가 변경 불가능한지 여부를 신속하게 확인할 수 있으므로 필드에 매우 유용합니다.

반면에 로컬 및 매개 변수에는 그다지 유용하지 않으며 일반적 final으로 다시 할당되지 않는 것처럼 표시하지 않습니다 (내부 클래스에서 사용해야하는 경우는 예외) . 그러나 최근에는 가능한 한 final을 사용하는 코드를 사용하여 기술적으로 더 많은 정보를 제공한다고 생각합니다.

내 프로그래밍 스타일에 대해 더 이상 확신을 가지지 않고, final어디에서든 적용 할 때 의 다른 장단점 , 가장 일반적인 산업 스타일 및 이유를 궁금합니다.


@Amir 코딩 스타일 질문은 SO보다 여기에 더 나은 것으로 보이며 FAQ 또는이 사이트의 메타에 관한 정책을 찾을 수 없었습니다. 당신은 저를 지시 할 수 있습니까?
Oak

1
@Oak는 말한다 : "특정 프로그래밍 문제, 소프트웨어 알고리즘, 코딩 , 스택 오버플로에 요청"
아미르 라자

7
@Amir 나는 동의하지 않는다. 이것이 어떻게 코딩 문제인지는 알지 못한다. 어쨌든이 토론은 여기에 속하지 않으므로이 문제에 대한 메타 주제를 열었습니다 .
Oak

3
@amir 이것은 프로그래밍에 대한 주관적인 질문이므로이 사이트의 주제에 관한 것입니다. / faq를 참조하십시오
Jeff Atwood

1
로컬 변수 : 이전 Java 컴파일러는 로컬 선언 여부에주의를 기울이고 final그에 따라 최적화했습니다. 최신 컴파일러는 스스로 알아낼 정도로 똑똑합니다. 적어도 지역 변수에 final대해서는 인간 독자의 이익을위한 것입니다. 당신의 일상이 너무 복잡하지 않다면, 대부분의 인간 독자들은 스스로도 스스로 알아낼 수 있어야합니다.
솔로몬 천천히

답변:


67

나는 final당신과 같은 방식으로 사용합니다. 나에게 로컬 변수와 메소드 매개 변수에 불필요한 것처럼 보이며 유용한 추가 정보를 전달하지 않습니다.

한 가지 중요한 점은 각각 단일 작업을 수행하는 방법을 짧고 깨끗하게 유지 하려고 노력하는 것입니다 . 따라서 내 로컬 변수 및 매개 변수는 범위가 매우 제한되어 있으며 단일 목적으로 만 사용됩니다. 이렇게하면 실수로 다시 할당 할 가능성이 최소화됩니다.

또한 확실히 아시다시피 final(기본이 아닌) 변수의 값 / 상태를 변경할 수 있다고 보장하지는 않습니다. 한 번 초기화되면 해당 객체에 대한 참조 를 다시 할당 할 수 없습니다 . 즉, 기본 또는 불변 유형의 변수에서만 완벽하게 작동합니다. 치다

final String s = "forever";
final int i = 1;
final Map<String, Integer> m = new HashMap<String, Integer>();

s = "never"; // compilation error!
i++; // compilation error!
m.put(s, i); // fine

이것은 많은 경우에 여전히 코드 내부에서 발생하는 상황을 이해하기가 쉽지 않으며,이를 오해하면 실제로 감지하기 어려운 미묘한 버그가 발생할 수 있습니다.


1
편집과 관련하여-의 의미를 알고 있습니다 final. 감사합니다 :) 그러나 짧고 깨끗한 방법에 대한 좋은 점-방법이 짧으면 변수가 다시 할당되지 않는 것이 분명합니다. final키워드 를 고려한 동기가 훨씬 적습니다 .
Oak

최종 매개 변수 및 지역 변수를 가질 수 있고 여전히 짧고 깔끔한 구문을 가질 수 있다면 좋지 않을까요? programmers.stackexchange.com/questions/199783/…
준수

7
"최종은 (기본적이지 않은) 변수의 값 / 상태를 변경할 수 없다는 것을 보증하지 않습니다. 초기화 된 객체에 대한 참조를 재 할당 할 수만 있습니다." Nonprimitive = reference (Java에서 유일한 유형은 기본 유형 및 참조 유형)입니다. 참조 형식의 변수의 값 이다 참조. 따라서 참조를 재 할당 할 수 없으며 = 값을 변경할 수 없습니다.
user102008

2
참조 / 상태 함정에 +1 Java8의 새로운 기능적 측면에서 클로저를 만들려면 변수를 final로 표시해야 할 수도 있습니다.
Newtopian

@ user102008이 지적한 것처럼 비교가 바이어스됩니다. 변수 할당은 값 업데이트와 동일하지 않음
ericn

64

Java 프로그래밍 스타일과 생각은 훌륭합니다. 의심 할 필요는 없습니다.

다른 한편으로, 나는 지역과 매개 변수에 대해 훨씬 덜 유용하다는 것을 알았습니다. 일반적으로 다시 할당되지 않을지라도 최종으로 표시하지 않습니다 (내부 클래스에서 사용해야 할 때 명백한 예외는 제외) ).

이것이 바로 final키워드 를 사용해야하는 이유 입니다. 당신은 상태 당신이 그것을 다시 할당되지 않을거야 알고 있지만, 아무도 그것을 모른다. final즉시 사용하면 코드가 조금 더 명확 해집니다.


8
방법이 명확하고 한 가지만 수행하면 독자도 알 수 있습니다. 마지막 단어는 코드를 읽을 수 없게 만듭니다. 그리고 읽을 수 없다면 훨씬 더 모호합니다
eddieferetro

4
@eddieferetro 동의하지 않습니다. 키워드 final는 의도를 나타내므로 코드를 더 읽기 쉽게 만듭니다. 또한 실제 코드를 다루어야하는 경우가 거의없고 명확하며, final어디서나 자유롭게 s를 추가 하면 버그를 발견하고 레거시 코드를 더 잘 이해할 수 있습니다.
Andres F.

4
변수가 절대 변하지 않는 "의도"이고 코드가 그 사실에 의존하고 있습니까? 또는 "이 변수는 절대 변경되지 않으므로 최종적으로 표시합니다"라는 의도입니다. 후자는 쓸모없고 해로운 소음 일 수 있습니다. 그리고 당신은 모든 지역을 표시하는 것을 옹호하는 것처럼 보이기 때문에 나중에하고 있습니다. 큰 -1.
user949300

2
final인 텐트는 일반적으로 코드 조각에서 좋은 일이지만 시각적 혼란을 추가하는 대가로 제공됩니다. 프로그래밍에서 대부분의 것들과 마찬가지로, 여기에 절충점이 있습니다. 변수가 추가 된 세부 정보의 가치가 한 번만 사용된다는 사실을 표현하고 있습니까?
christopheml

30

가능한 곳에서 final/ 를 사용하는 것의 한 가지 장점은 const코드 리더의 정신 부하를 줄인다는 것입니다.

그는 값 / 참조가 나중에 변경되지 않는다는 것을 확신 할 수 있습니다. 따라서 그는 계산을 이해하기 위해 수정에주의를 기울일 필요가 없습니다.

순수한 함수형 프로그래밍 언어를 배우고 나서 이것에 관해 마음이 바뀌 었습니다. 당신은 항상 초기 값을 유지하기 위해 "변수"를 신뢰할 수 있다면 소년, 얼마나 안심.


16
Java final에서는 (기본이 아닌) 변수의 값 / 상태를 변경할 수 없다고 보장하지 않습니다. 한 번 초기화되면 해당 객체에 대한 참조 를 다시 할당 할 수 없습니다 .
Péter Török

9
나는 그것이 내가 가치와 기준을 구별 한 이유입니다. 이 개념은 불변 데이터 구조 및 / 또는 순수 기능의 맥락에서 가장 유용합니다.
LennyProgrammers 2013

7
@ PéterTörök 기본 유형에 즉시 도움이되고 가변 객체에 대한 참조에 다소 도움이됩니다 (적어도 항상 동일한 객체를 다루고 있다는 것을 알고 있습니다!). 처음부터 변경 불가능하도록 설계된 코드를 처리 할 때 매우 유용합니다.
Andres F.

18

final메서드 매개 변수와 로컬 변수에서 코드 노이즈 라고 생각 합니다. Java 메소드 선언은 상당히 길 수 있으며 (특히 제네릭의 경우) 더 이상 만들 필요가 없습니다.

단위 테스트가 올바르게 작성된 경우 "유해한"매개 변수에 할당하면 선택되므로 실제로 문제 가되지 않습니다 . 비주얼 선명도는 피보다 더 중요 할 수 단위 테스트가 불충분 한 범위를 가지고 있기 때문에 포착되지 않는 버그.

FindBugs 및 CheckStyle과 같은 도구는 매개 변수 또는 로컬 변수에 할당 된 경우 빌드를 중단하도록 구성 할 수 있습니다.

당신이 경우 물론, 필요 하면, 익명의 클래스 다음 문제를 값을 사용하지 않고 있기 때문에, 예를 들어, 그들이 최종 만들기 위해 - 그 간단한 깨끗한 솔루션입니다.

매개 변수에 추가 키워드를 추가하여 IMHO를 위장하는 명백한 효과 외에도 메서드 매개 변수에 final을 추가하면 메서드 본문의 코드가 읽기 어려워 져 코드가 더 나빠질 수 있습니다. 가급적 읽기 쉽고 간단해야합니다. 고안된 예를 들어 대소 문자를 구분하지 않는 방법이 있다고 가정 해보십시오.

없이 final:

public void doSomething(String input) {
    input = input.toLowerCase();
    // do a few things with input
}

단순한. 깨끗한. 모두 무슨 일이 일어나고 있는지 알고 있습니다.

이제 '최종'으로 옵션 1 :

public void doSomething(final String input) {
    final String lowercaseInput = input.toLowerCase();
    // do a few things with lowercaseInput
}

매개 변수를 만들면 final코더가 원래 값으로 작업하고 있다고 생각하는 것보다 코드를 더 추가하는 것을 막을 수는 있지만 코드가 더 이상 사용 input하지 않을 수도 lowercaseInput있습니다. t은 범위를 꺼내 (또는 지정 nullinput그조차 어쨌든 도움이 될 경우).

'최종'으로 옵션 2 :

public void doSomething(final String input) {
    // do a few things with input.toLowerCase()
}

이제 더 많은 코드 노이즈가 생성되었으며 toLowerCase()n 번 호출해야하는 성능 저하가 발생 했습니다.

'최종'으로 옵션 3 :

public void doSomething(final String input) {
    doSomethingPrivate(input.toLowerCase());
}

/** @throws IllegalArgumentException if input not all lower case */
private void doSomethingPrivate(final String input) {
    if (!input.equals(input.toLowerCase())) {
        throw new IllegalArgumentException("input not lowercase");
    }
    // do a few things with input
}

코드 노이즈에 대해 이야기하십시오. 이것은 열차의 잔해입니다. 다른 코드가 잘못 호출 할 수 있기 때문에 필요한 예외 블록 인 새로운 메소드가 있습니다. 예외를 다루기 위해 더 많은 단위 테스트. 하나의 단순하고 IMHO가 바람직하고 무해한 라인을 피하십시오.

메서드가 너무 길어서 시각적으로 쉽게 받아 들여서 매개 변수에 대한 할당이 한 눈에 알 수없는 문제도 있습니다.

매개 변수에 할당하면 매번 메서드의 초기, 바람직하게는 기본 입력 확인 후 첫 번째 줄 또는 직선 으로 수행하여 전체 메서드에 대해 효과적으로 대체 하는 것이 좋은 습관 / 스타일이라고 생각합니다 . 방법. 독자들은 과제가 명확하고 (서명 선언 근처에) 일관된 위치에있을 것으로 기대하므로 final 추가가 피하려고하는 문제를 크게 완화 할 수 있습니다. 실제로 나는 매개 변수에 거의 할당하지 않지만, 그렇게하면 항상 메서드 상단에서 수행합니다.


참고 또한이 final실제로 당신이 처음에 같은 수 있습니다 보호하지 않습니다 같다 :

public void foo(final Date date) {
    date.setTime(0); 
    // code that uses date
}

final 매개 변수 유형이 원시적이거나 변경 불가능한 경우가 아니면 완전히 보호 할 수 없습니다.


마지막 경우, final동일한 Date인스턴스를 처리한다는 부분적 보증을 제공합니다 . 어떤 보증은 아무것도 아닌 것보다 낫습니다 (아무것도 당신은 처음부터 불변의 클래스를 주장하고 있습니다!). 어쨌든, 실제로 말한 것의 많은 부분은 기본 불변 언어에 영향을 주지만 그렇지 않은 언어이므로 문제가 아닙니다.
Andres F.

"추가 코드에서 입력을 사용할 수 있습니다"라는 위험을 지적하기 위해 +1. 여전히 final위의 경우에는 매개 변수를 비 최종으로 만들 수있는 매개 변수를 선호합니다 . 키워드로 서명을 스팸으로 분류하는 것은 가치가 없습니다.
maaartinus

7

final프로그램을 읽기 쉽도록 만들기 위해 각 로컬 변수 앞에 일식을 넣었 습니다. 나는 매개 변수 목록을 가능한 한 짧게 유지하기를 원하기 때문에 매개 변수로 만들지 않습니다. 이상적으로는 한 줄에 맞아야합니다.


2
또한 매개 변수의 경우 매개 변수가 지정된 경우 컴파일러에서 경고 또는 오류를 발행하도록 할 수 있습니다.
준수

3
정반대로, 코드가 복잡해지기 때문에 읽기가 더 어렵다는 것을 알게되었습니다.
Steve Kuo

3
@ Steve Kuo : 모든 변수를 빠르게 찾을 수 있습니다. 큰 이득은 아니지만 우발적 인 할당을 방지하면서 6 자의 가치가 있습니다. var비 최종 변수를 표시하는 것과 같은 것이 있다면 훨씬 더 기쁠 것 입니다. YMMV.
maaartinus

1
@maaartinus 님이 동의했습니다 var! 불행히도 Java의 기본값이 아니며 언어를 변경하기에는 너무 늦었습니다. 따라서, 나는 쓰기의 사소한 불편을 참아 기꺼이 final:)
안드레스 F.

1
@maaartinus 합의. 초기화 후 내 로컬 변수의 약 80-90 %를 수정할 필요가 없다는 것을 알았습니다. 따라서, 이들 80 ~ 90 %가이 final만 ~ 20 %가 필요한 것입니다 반면, 앞에 추가 키워드를 var...
JimmyB
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.