[java] 메소드 매개 변수 및 로컬 변수에 final을 언제 사용해야합니까?

가능한 한 많이 사용하도록 제안 하는 몇 가지 참조 ( :)를 찾았 final으며 그것이 얼마나 중요한지 궁금합니다. 이것은 주로 최종 메소드 나 클래스가 아니라 메소드 매개 변수 및 로컬 변수의 컨텍스트에 있습니다. 상수의 경우 분명히 의미가 있습니다.

한편으로, 컴파일러는 최적화를 수행 할 수 있으며 프로그래머의 의도를보다 명확하게합니다. 반면에 자세한 정보를 추가하면 최적화가 쉽지 않을 수 있습니다.

내가 기억하려고 노력해야합니까?



답변

집착 :

  • 최종 필드-필드를 최종으로 표시하면 구성이 끝날 때 필드를 강제 설정하여 해당 필드 참조를 변경할 수 없습니다. 이렇게하면 필드를 안전하게 게시 할 수 있으며 나중에 읽을 때 동기화 할 필요가 없습니다. (객체 참조의 경우 필드 참조 만 변경할 수 없습니다. 객체 참조가 참조하는 항목은 계속 변경 될 수 있으며 불변성에 영향을줍니다.)
  • 최종 정적 필드-정적 최종 필드를 사용했던 많은 경우에 지금 열거 형을 사용하지만.

신중하게 사용하십시오.

  • 최종 수업-프레임 워크 / API 디자인은 내가 생각하는 유일한 경우입니다.
  • 최종 방법-기본적으로 최종 클래스와 동일합니다. 미친 것과 같은 템플릿 방법 패턴을 사용하고 물건을 최종으로 표시하는 경우 상속에 너무 의존하고 위임에 충분하지 않을 수 있습니다.

항문 느낌이 없으면 무시하십시오.

  • 메소드 매개 변수 및 로컬 변수-게으르고 코드가 복잡해지기 때문에 거의하지 않습니다. 수정하지 않을 마킹 매개 변수와 로컬 변수가 “보다 옳다”는 것을 완전히 인정합니다. 이것이 기본값이기를 바랍니다. 그러나 코드가 아니며 최종 코드로 이해하기가 더 어렵다는 것을 알았습니다. 다른 사람의 코드를 사용하는 경우 코드를 꺼내지 않지만 새 코드를 작성하는 경우 입력하지 않을 것입니다. 예외는 최종적으로 무언가를 표시하여 액세스 할 수있는 경우입니다. 익명의 내부 클래스 내에서.

  • 편집 : @ adam-gent 가 언급 한 것처럼 최종 로컬 변수가 실제로 매우 유용한 유스 케이스 는 값이 if/ else분기 의 var에 할당되는 경우 입니다.


답변

내가 기억하기 위해 노력해야 할 일입니까?

아니오, Eclipse를 사용하는 경우 저장 조치를 구성하여 이러한 최종 수정자를 자동으로 추가 할 수 있습니다. 그러면 적은 노력으로 혜택을 얻을 수 있습니다.


답변

“최종”의 개발 시간 이점은 최소한 런타임 혜택만큼 중요합니다. 그것은 미래의 편집자들에게 당신의 의도에 관한 코드를 알려줍니다.

클래스를 “최종”으로 표시하면 클래스를 디자인하거나 구현하는 동안 확장을 정상적으로 처리하기 위해 노력하지 않았 음을 나타냅니다. 독자가 클래스를 변경하고 “최종”수정자를 제거하려는 경우 독자적인 위험 부담이 있습니다. 수업이 확장을 잘 처리하도록하는 것은 그들에게 달려 있습니다.

변수 “final”을 표시하고 생성자에서 변수를 지정하면 종속성 주입에 유용합니다. 변수의 “협업 자”특성을 나타냅니다.

메소드를 “final”로 표시하는 것은 추상 클래스에서 유용합니다. 확장 점이 어디에 있는지 명확하게 묘사합니다.


답변

finalJava를보다 표현 기반으로 만들기 위해 항상 사용 합니다. Java의 조건 ( if,else,switch)은 표현식 기반이 아니므로 특히 함수형 프로그래밍 (ML, Scala 또는 Lisp)에 익숙한 경우 항상 싫어했습니다.

따라서 조건을 사용할 때 항상 (IMHO) 최종 변수를 사용해야합니다.

예를 들어 보겠습니다.

    final String name;
    switch(pluginType) {
        case CANDIDATE_EXPORT:
            name = "Candidate Stuff";
            break;
        case JOB_POSTING_IMPORT:
            name = "Blah";
            break;
        default:
            throw new IllegalStateException();
    }

이제 다른 case명령문을 추가 하고 설정하지 않으면 name컴파일러가 실패합니다. 모든 경우에 변수를 설정하지 않으면 컴파일러가 실패합니다. 이를 통해 Java를 Lisp와 매우 유사하게 만들 수 있습니다.let 표현식과 하게 만들 수 있으며 (어휘 범위 변수 때문에) 코드가 크게 들여 쓰기되지 않도록합니다.

그리고 @Recurse가 지적했듯이 (그러나 분명히 -1 me) String name final컴파일러 오류를 얻지 않고 위의 작업을 수행 할 수는 있지만 (전혀 말할 수는 없었습니다) 스위치 후에 컴파일러 오류를 쉽게 설정할 수 있습니다. break을 사용하지 않고 표현 의미론을 버리거나 오류를 유발할 수없는 것을 잊어 버리는 문장 (@Recurse의 말에도 불구하고) final:

    String name;
    switch(pluginType) {
        case CANDIDATE_EXPORT:
            name = "Candidate Stuff";
            //break; whoops forgot break.. 
            //this will cause a compile error for final ;P @Recurse
        case JOB_POSTING_IMPORT:
            name = "Blah";
            break;
    }
    // code, code, code
    // Below is not possible with final
    name = "Whoops bug";

버그 설정 이름으로 인해 ( break다른 버그를 잊어 버리는 것 외에도 ) 우연히 이것을 할 수 있습니다.

    String name;
    switch(pluginType) {
        case CANDIDATE_EXPORT:
            name = "Candidate Stuff";
            break;
        //should have handled all the cases for pluginType
    }
    // code, code, code
    // Below is not possible with final
    name = "Whoops bug";

최종 변수는 어떤 이름이어야하는지에 대한 단일 평가를 강제합니다. 반환 값이있는 함수가 항상 예외를 무시하고 값을 반환해야하는 방식과 유사하게 이름 스위치 블록은 이름을 확인해야하므로 해당 스위치 블록에 바인딩되어 코드 덩어리를 쉽게 리팩토링 할 수 있습니다 (예 : Eclipe refactor : extract 메소드) .

위의 OCaml :

type plugin = CandidateExport | JobPostingImport

let p = CandidateExport

let name = match p with
    | CandidateExport -> "Candidate Stuff"
    | JobPostingImport -> "Blah" ;;

match ... with ...함수 즉, 표현과 같은 평가합니다. switch 문처럼 보이는지 확인하십시오.

다음은 스킴 (라켓 또는 치킨)의 예입니다.

(define name
    (match b
      ['CandidateExport "Candidate Stuff"]
      ['JobPostingImport "Blah"]))


답변

final문제의 방법이 몇 페이지 길이의 이해할 수없는 혼란 일 때 리팩토링 보조 도구로 유용한 메소드 매개 변수 및 지역 표시를 발견했습니다 . 소량final자유롭게 , 컴파일러 (또는 IDE)에서 발생하는 “최종 변수에 할당 할 수 없음”오류가 무엇인지 확인하고, “데이타”라는 변수가 여러 개의 (오래된) 주석이 맹세하더라도 왜 끝나는지를 발견 할 수 있습니다. 일어나지 않습니다.

그런 다음 재사용 된 변수를 사용 지점에 더 가깝게 선언 된 새 변수로 대체하여 일부 오류를 수정할 수 있습니다. 그런 다음 괄호 범위를 지정하여 방법의 전체 부분을 감쌀 수 있으며 갑자기 “추출 방법”에서 IDE 키를 한 번 누르면 괴물이 더 이해하기 쉬워집니다.

만약 당신의 방법이 아직 유지 불가능한 난파선 이 아니라면 , 사람들이 그 난파선으로 변하는 것을 막기 위해 물건을 최종적으로 만드는 것이 가치가있을 것입니다. 그러나 그것이 짧은 방법이라면 (유지 불가능한 참조), 당신은 많은 정보를 추가 할 위험이 있습니다. 특히 Java 함수 시그니처는 인수 당 6 개를 더 추가하지 않고도 80 자로 들어갈 수있을만큼 어렵습니다!


답변

글쎄, 이것은 모두 당신의 스타일에 달려 있습니다 … 변수를 수정하지 않을 때 최종 결과를 보는 것을 좋아한다면 그것을 사용하십시오. 보고 싶지 않다면 … 그대로 두십시오.

나는 개인적으로 가능한 한 작은 표현을 좋아하므로 실제로 필요하지 않은 추가 키워드를 사용하지 않는 경향이 있습니다.

나는 동적 언어를 선호하므로, 자세한 표현을 피하고 싶어하는 것은 놀라운 일이 아닙니다.

그래서, 나는 당신이 기울고있는 방향을 고르고 그냥 따라 가십시오 (어쨌든 일관되게 노력하십시오).


부수적으로, 나는 그러한 패턴을 사용하고 사용하지 않는 프로젝트를 연구했으며 버그 나 오류의 양에는 차이가 없었습니다 … 버그 수 또는 기타 사항을 개선하지만 다시 한 번 스타일입니다. 수정하지 않으려는 의도를 표현하고 싶다면 계속 사용하십시오.


답변

실수로 매개 변수 값을 변경하지 않고 미묘한 버그를 유발하는 것이 매개 변수에 유용합니다. 이 권장 사항을 무시하지만 약 4 시간을 소비 한 후 사용합니다. 끔찍한 방법 (수백 줄의 코드와 여러 개의 for, 중첩 된 if 및 모든 종류의 나쁜 습관)을 사용하는 것이 좋습니다.

 public int processSomethingCritical( final int x, final int y ){
 // hundreds of lines here 
     // for loop here...
         int x2 = 0;
        x++; // bug aarrgg...
 // hundreds of lines there
 // if( x == 0 ) { ...

 }

물론 완벽한 세상에서는 이런 일은 일어나지 않을 것입니다.하지만 .. 때로는 다른 코드를 지원해야합니다. 🙁