programing

메서드 파라미터와 로컬변수는 언제 final을 사용해야 합니까?

javaba 2022. 7. 5. 23:44
반응형

메서드 파라미터와 로컬변수는 언제 final을 사용해야 합니까?

(를 들어) 를 사용할 것을 제안하는 몇 가지 참고 자료를 찾았습니다.final는 주로 로컬 메서드나가 아닙니다.이는 주로 최종 메서드나 클래스가 아닌 메서드 파라미터와 로컬 변수의 컨텍스트에 있습니다.상수의 경우, 이는 명백하게 타당합니다.

한편으로 컴파일러는 최적화를 할 수 있어 프로그래머의 의도를 명확하게 합니다.한편, 장황함을 더하고 최적화는 사소한 것일 수 있습니다.

제가 기억하려고 노력해야 할 부분인가요?

다음 사항에 대한 집착:

  • Final 필드 - 필드를 final로 표시하면 필드 참조가 변경되지 않고 건설이 끝날 때까지 설정됩니다.이를 통해 필드를 안전하게 게시할 수 있으며 이후 읽을 때 동기화할 필요가 없습니다.(오브젝트 참조의 경우 필드 참조만 불변합니다.오브젝트 참조가 참조하는 것은 계속 변경될 수 있으며 불변성에 영향을 미칩니다).
  • 최종 정적 필드 - 정적 최종 필드를 사용하던 대부분의 경우 에넘을 사용합니다.

고려하되 신중하게 사용하십시오.

  • 파이널 클래스 - 프레임워크/API 설계만이 검토 대상입니다.
  • 최종 방법 - 기본적으로 최종 수업과 동일합니다.crazy 및 marking themple final과 같은 템플릿 방식 패턴을 사용하는 경우, 상속에는 너무 많이 의존하며 위임에는 충분하지 않을 수 있습니다.

항문이 느껴지지 않는 한 무시하십시오.

  • 메서드 파라미터와 로컬 변수 - 저는 게으르고 코드가 복잡하기 때문에 이 작업을 거의 하지 않습니다.수정하지 않을 파라미터 및 로컬 변수 마킹이 "더 큼"임을 완전히 인정합니다.디폴트였으면 좋겠어요.하지만 그렇지 않고 기말고사까지 겹치면서 코드를 이해하기가 더 어려워.내가 다른 사람의 코드에 있다면, 나는 그들을 끌어내지 않을 것이다. 하지만 만약 내가 새로운 코드를 쓰고 있다면, 나는 그들을 넣지 않을 것이다.한 가지 예외는 익명의 내부 클래스 내에서 액세스할 수 있도록 최종 표시를 해야 하는 경우입니다.

  • 편집: @adam-gent에서 설명한 바와 같이 최종 로컬 변수가 실제로 매우 유용한 사용 사례 중 하나는 값 할당 시if/else나뭇가지.

잊지 말고 해야 할 일인가요?

아니요, Eclipse를 사용하는 경우 이러한 최종 수정자를 자동으로 추가하도록 저장 작업을 구성할 수 있습니다.그러면 적은 노력으로 이점을 얻을 수 있습니다.

용 i i i i를 쓴다.final자바어(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컴파일러가 실패합니다.(변수를 설정한) 모든 경우를 중단하지 않으면 컴파일러도 실패합니다.를 통해 Lisp Java와 매우 유사한 수 .let표현식을 사용하여 (어휘 범위 지정 변수 때문에) 코드가 크게 들여쓰이지 않도록 합니다.

@지적한 , me) @Recurse는 @Recurse를 -1로 앞의 작업을 수행할 수 .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 ...함수, 즉 식과 같이 평가합니다.이치노

스킴(Racket 또는 Chicken)의 예를 다음에 나타냅니다.

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

"최종"의 개발 시간 편익은 런타임 편익만큼 중요합니다.미래의 코드 편집자에게 당신의 의도에 대해 알려줍니다.

클래스를 "최종"으로 표시하면 클래스를 설계하거나 구현하는 동안 확장을 정상적으로 처리하지 않았음을 나타냅니다.독서자가 클래스를 변경할 수 있고 "최종" 수식자를 삭제하려는 경우, 독자는 자신의 위험을 감수해야 합니다.그 수업이 연장을 잘 처리할 수 있도록 하는 것은 그들에게 달려 있다.

변수를 "최종"으로 표시(및 생성자에 할당)하면 종속성 주입에 유용합니다.변수의 "협력자" 특성을 나타냅니다.

메서드를 "최종"으로 표시하면 추상 클래스에서 유용합니다.확장점의 위치를 명확하게 나타냅니다.

음, 이건 모두 당신 스타일에 달렸어요.변수를 수정하지 않을 때 최종 결과를 보고 싶다면 변수를 사용하십시오.보기 싫으면...그럼 빼주세요.

저는 개인적으로 가능한 한 장황한 표현을 좋아하지 않기 때문에 불필요한 키워드를 사용하는 것을 피하는 경향이 있습니다.

하지만 저는 역동적인 언어를 선호하기 때문에 장황함을 피하는 것이 당연할 것입니다.

그래서 저는 그냥 당신이 원하는 방향을 선택하고 그대로 가라고 말하고 싶습니다(어떤 경우든 일관성을 가지도록 노력하세요.


덧붙여서, 그러한 패턴을 사용하는 프로젝트와 사용하지 않는 프로젝트를 실시해 왔습니다만, 버그나 에러의 수에는 차이가 없었습니다.버그 수를 크게 개선할 수 있는 패턴은 아니라고 생각합니다만, 역시 스타일입니다.변경을 하지 않겠다는 의사를 표현하고 싶다면 사용하세요.

방법 을 final문제의 방법이 몇 페이지나 되는 이해하기 어려운 혼란일 때 리팩터링 보조 도구로 도움이 됩니다.final자유롭게 컴파일러(또는 IDE)가 발생시키는 "최종 변수에 할당할 수 없음" 오류를 확인합니다.또, 몇개의 (최신) 코멘트가 발생할 수 없다고 해도, 「데이터」라고 불리는 변수가 null이 되는 이유를 알 수 있습니다.

그런 다음 재사용된 변수를 사용 지점에 가깝게 선언된 새 변수로 대체하여 일부 오류를 수정할 수 있습니다.그러면 메서드의 모든 부분을 범위 지정 중괄호로 묶을 수 있습니다.그러면 IDE 키를 한 번 누르면 "Extract Method"가 훨씬 더 이해하기 쉬워집니다.

만약 당신의 방법이 이미 유지 불가능한 난관이 아니라면, 나는 사람들이 그것을 파괴하는 것을 막기 위해 최종적인 것을 만드는 것이 가치가 있다고 생각한다. 하지만 만약 그것이 짧은 방법이라면, 당신은 많은 장황함을 더할 위험을 감수해야 한다.특히 Java 함수 시그니처는 인수당 6자를 추가하지 않고 그대로 80자를 입력할 수 있습니다.

파라미터에서 파라미터 값이 실수로 변경되는 것을 방지하고 미묘한 버그가 발생하는 것을 방지하기 위해 유용합니다.저는 이 권고를 무시하곤 했습니다만, 끔찍한 방법(수백 줄의 코드와 여러 개의 포스, 중첩된 if 및 모든 종류의 나쁜 관행)으로 4시간을 보낸 후, 그것을 추천합니다.

 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 ) { ...

 }

물론 완벽한 세상이라면 이런 일은 없겠지만..글쎄요. 가끔은 다른 코드를 지원해야 할 때도 있습니다. : (

예를 들어, 1년 후에 코드를 읽어야 하는 어플리케이션을 작성할 경우 항상 수정해서는 안 되는 변수에 대해 final on variable을 사용합니다.이렇게 하면 코드가 더 "자기 문서화"되고 로컬 임시 변수로 로컬 상수를 사용하는 것과 같은 어리석은 일을 다른 개발자가 수행할 기회도 줄어듭니다.

만약 당신이 일회용 코드를 쓰고 있다면, 아니, 모든 상수를 알아내서 최종적으로 만들 필요는 없습니다.

나는 가능한 한 final을 사용할 것이다.이렇게 하면 필드를 실수로 변경할 경우 플래그가 표시됩니다.Method 파라미터도 final로 설정합니다.그렇게 함으로써 나는 그들이 자바가 값에 의해 전달되는 것을 잊어버리고 파라미터를 설정하려고 할 때 넘겨받은 코드에서 몇 가지 버그를 발견했다.

이것이 명백한지는 질문에서 분명하지 않지만, 방법 매개 변수를 최종으로 만드는 것은 방법 본문에만 영향을 미칩니다.메서드의 의도에 대한 흥미로운 정보를 호출자에게 전달하지 않습니다.전달되는 객체는 메서드 내에서 계속 변환될 수 있으며(최종값은 상수 아님), 변수의 범위는 메서드 내에 있습니다.

정확한 질문에 답하기 위해 필요한 코드(예를 들어 변수가 내부 클래스에서 참조됨)가 아니면 인스턴스 또는 로컬 변수(메서드 매개 변수 포함)를 최종화할 필요가 없습니다.

예를 들어 변수가 논리 상수라면 최종 변수라고 할 수 있습니다.

.final

최종 상수

 public static class CircleToolsBetter {
     public final static double PI = 3.141;
        public double getCircleArea(final double radius) {
          return (Math.pow(radius, 2) * PI);
        }
    }

이 값은 코드의 다른 부분에 사용하거나 다른 클래스에서 액세스할 수 있으므로 값을 변경할 때마다 변경할 필요가 없습니다.

최종 변수

public static String someMethod(final String environmentKey) {
    final String key = "env." + environmentKey;
    System.out.println("Key is: " + key);
    return (System.getProperty(key));

  }

}

이 클래스에서는 파라미터 environmentKey에 Prefix를 추가하는 범위의 최종 변수를 작성합니다.이 경우 최종 변수는 실행 범위 내에서만 최종 변수이며, 메서드의 각 실행마다 다릅니다.메서드를 입력할 때마다 최종값이 재구성됩니다.메서드 실행 범위에서는 구성 즉시 변경할 수 없습니다.그러면 메서드 기간 동안 메서드의 변수를 수정할 수 있습니다.이하를 참조해 주세요.

public class FinalVariables {


  public final static void main(final String[] args) {
    System.out.println("Note how the key variable is changed.");
    someMethod("JAVA_HOME");
    someMethod("ANT_HOME");
  }
}

최종 상수

public double equation2Better(final double inputValue) {
    final double K = 1.414;
    final double X = 45.0;

double result = (((Math.pow(inputValue, 3.0d) * K) + X) * M);
double powInputValue = 0;         
if (result > 360) {
  powInputValue = X * Math.sin(result); 
} else {
  inputValue = K * Math.sin(result);   // <= Compiler error   
}

이것은 특히 코드 행이 매우 긴 경우에 편리합니다.또한 컴파일러 에러가 발생하기 때문에 다른 사람이 실수로 변경해서는 안 되는 변수를 변경해도 논리 오류나 비즈니스 오류가 발생하지 않습니다.

최종 컬렉션

컬렉션에 대해 설명할 때는 수정할 수 없는 것으로 설정해야 합니다.

 public final static Set VALID_COLORS; 
    static {
      Set temp = new HashSet( );
      temp.add(Color.red);
      temp.add(Color.orange);
      temp.add(Color.yellow);
      temp.add(Color.green);
      temp.add(Color.blue);
      temp.add(Color.decode("#4B0082")); // indigo
      temp.add(Color.decode("#8A2BE2")); // violet
      VALID_COLORS = Collections.unmodifiableSet(temp);
    }

그렇지 않으면 수정할 수 없는 것으로 설정하지 않으면 다음과 같이 됩니다.

Set colors = Rainbow.VALID_COLORS;
colors.add(Color.black); // <= logic error but allowed by compiler

Final Classes와 Final Method는 각각 확장 또는 덮어쓸 수 없습니다.

편집: 캡슐화에 관한 최종 클래스 문제에 대처하려면:

한 반을 기말고사로 만드는 방법은 두 가지가 있다.첫 번째 방법은 클래스 선언에서 final 키워드를 사용하는 것입니다.

public final class SomeClass {
  //  . . . Class contents
}

클래스를 최종화하는 두 번째 방법은 모든 컨스트럭터를 비공개로 선언하는 것입니다.

public class SomeClass {
  public final static SOME_INSTANCE = new SomeClass(5);
  private SomeClass(final int value) {
  }

결승으로 표시하면 실제 결승이라는 것을 알게 되었을 때 이 테스트 클래스를 살펴보기 위해 번거로움을 덜 수 있습니다.언뜻 보면 공공연해 보인다.

public class Test{
  private Test(Class beanClass, Class stopClass, int flags)
    throws Exception{
    //  . . . snip . . . 
  }
}

안타깝게도 클래스의 유일한 생성자가 개인이기 때문에 이 클래스를 확장하는 것은 불가능합니다.시험 수업의 경우, 수업이 기말고사여야 할 이유가 없습니다.테스트 클래스는 암묵적인 최종 클래스가 어떻게 문제를 일으킬 수 있는지를 보여주는 좋은 예입니다.

따라서 컨스트럭터를 비공개로 하여 암묵적으로 클래스를 최종화할 때는 최종 마크를 붙여야 합니다.

말씀하신 것처럼 일종의 트레이드오프입니다만, 암묵적인 사용보다는 명시적인 사용을 선호합니다.이렇게 하면 사용자만 사용하더라도 향후 코드 유지 관리자에 대한 애매한 부분을 제거할 수 있습니다.

내부(익명) 클래스가 있고 메서드가 포함된 메서드의 변수에 액세스해야 하는 경우 해당 변수를 최종 값으로 지정해야 합니다.

그 외에는 당신이 한 말이 맞아요.

final할 수 있습니다.immutable

변수를 최종 변수라고 선언함으로써 개발자는 고도로 멀티 스레드화된 환경에서 변수의 가능한 수정 문제를 배제할 수 있습니다.

Java 8 릴리즈에서는 ""라는 effectively final variable컨셉이 하나 더 생겼습니다.최종 변수가 아닌 변수가 최종 변수로 히브될 수 있습니다.

람다 식에서 참조되는 로컬 변수는 최종 변수이거나 사실상 최종 변수여야 합니다.

변수는 로컬 블록에서 초기화된 후 변경되지 않으면 유효한 최종변수간주됩니다.즉, 이제 익명 클래스나 람다 식에서 최종 키워드 없이 로컬 변수를 사용할 수 있습니다. 단, 로컬 변수는 사실상 최종이어야 합니다.

Java 7까지는 익명 클래스 내에서 비최종 로컬 변수를 사용할 수 없지만 Java 8부터는 사용할 수 있습니다.

기사를 보세요.

우선 final 키워드를 사용하여 변수를 일정하게 한다.상수는 변하지 않음을 의미합니다.예를 들어 다음과 같습니다.

final int CM_PER_INCH = 2.54;

인치당 1센티미터는 변경되지 않으므로 변수를 최종으로 선언합니다.

최종값을 덮어쓰려고 하면 변수는 처음에 선언된 값이 됩니다.예를 들어 다음과 같습니다.

final String helloworld = "Hello World";
helloworld = "A String"; //helloworld still equals "Hello World"

다음과 같은 컴파일 오류가 있습니다.

local variable is accessed from inner class, must be declared final

변수를 최종으로 선언할 수 없거나 최종으로 선언하지 않으려면 다음을 수행하십시오.

final String[] helloworld = new String[1];
helloworld[0] = "Hello World!";
System.out.println(helloworld[0]);
helloworld[0] = "A String";
System.out.println(helloworld[0]);

인쇄:

Hello World!
A String

언급URL : https://stackoverflow.com/questions/154314/when-should-one-use-final-for-method-parameters-and-local-variables

반응형