programing

컨스트럭터를 예외로 하는 것이 좋은 프랙티스입니까?

javaba 2022. 8. 8. 17:40
반응형

컨스트럭터를 예외로 하는 것이 좋은 프랙티스입니까?

컨스트럭터를 예외로 하는 것이 좋은 프랙티스입니까?를 들어, 저는 .Person가 가지고 있는 게 있어요.age일한한속속속속속, 이렇게 하겠습니다.

class Person{
  int age;
  Person(int age) throws Exception{
   if (age<0)
       throw new Exception("invalid age");
   this.age = age;
  }

  public void setAge(int age) throws Exception{
  if (age<0)
       throw new Exception("invalid age");
   this.age = age;
  }
}

컨스트럭터에 예외를 두는 것도 나쁘지 않습니다.실제로는 파라미터가 무효인 경우 등 문제가 있음을 나타내는 것은 컨스트럭터에게 있어서 유일한 합리적인 방법입니다.

또한 1) 체크된 예외가 선언된 경우, 2) 보고하는 문제에 고유한 경우, 3) 이에 대해2 발신자가 체크된 예외를 처리할 것으로 예상하는1 것이 타당하다고 생각합니다.

, 「」를 명시적으로 또는 투척하는 .java.lang.Exception거의 항상 나쁜 관행이다.

발생한 예외 조건과 일치하는 예외 클래스를 선택해야 합니다.Exception발신자가 이 예외를 선언된 예외 및 선언되지 않은 예외의 수에 관계없이 분리하는 것은 어렵습니다.이것에 의해, 에러 회복이 어려워져, 발신자가 예외를 전파하는 것을 선택했을 경우, 문제는 확산됩니다.


- 하지 않는 도 있을 수 이 를 던지는 경우 .1 IMO는 IMO입니다.체크된 표준과 체크되지 않은 조언은 두 경우 모두에 동일하게 적용됩니다.
- 2 - 을 사용합니다.FileInputStreamFileNotFoundException★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★♪FileNotFoundException체크된3 예외로 하려면 생성자가 해당 예외를 발생시키는 가장 적절한 장소입니다.우리가 던지면FileNotFoundException 하는 말read ★★★★★★★★★★★★★★★★★」write호출이 이루어졌기 때문에 애플리케이션 로직이 더 복잡해질 수 있습니다.
- 예외에 동기 예 중 에 이를 으로 모든 .3 - 네, 모든 예외는 체크되지 않아야 합니다....Java java java java 。


분이 사용하라고 해 주셨어요.assert인수의 체크에 사용합니다.은, 「 」의 가 되는 것입니다.assertJVM 명령줄 설정을 통해 어사션을 켜거나 끌 수 있습니다.내부 불변량을 체크하기 위해 어사션을 사용하는 것은 괜찮지만, javadoc에서 지정된 인수 체크를 구현하기 위해 어사션 체크를 사용하는 것은 좋은 생각이 아닙니다.이는 어사션 체크가 활성화되어 있을 때만 메서드가 사양을 엄격하게 구현한다는 것을 의미하기 때문입니다.

" "의 두 문제"assert, 어설션이 , 「어설션」은AssertionError던져질 것이고, 그리고 지혜는 잡으려고 시도하는 것은 나쁜 생각이라는 것이다.Error그리고 그 하위 유형 중 하나죠.

저는 항상 체크된 예외를 컨스트럭터에 던지는 것은 나쁜 관행이거나 최소한 피해야 할 일이라고 생각해 왔습니다.

그 이유는 이 작업을 수행할 수 없기 때문입니다.

private SomeObject foo = new SomeObject();

대신 다음을 수행해야 합니다.

private SomeObject foo;
public MyObject() {
    try {
        foo = new SomeObject()
    } Catch(PointlessCheckedException e) {
       throw new RuntimeException("ahhg",e);
    }
}

Some Object를 구성할 때 파라미터가 무엇인지 알고 있는데 왜 테스트 캐치로 묶어야 합니까?아, 하지만 만약 내가 동적 파라미터로 객체를 만들고 있다면 나는 그것들이 유효한지 아닌지 모르겠다.음, 당신은...파라미터를 컨스트럭터에 전달하기 전에 유효성을 확인합니다.그것은 좋은 연습이 될 것이다.파라미터가 유효한지에 대해서만 관심이 있는 경우 Ilgal Argument를 사용할 수 있습니다.예외.

체크된 예외를 던지는 대신

public SomeObject(final String param) {
    if (param==null) throw new NullPointerException("please stop");
    if (param.length()==0) throw new IllegalArgumentException("no really, please stop");
}

물론 체크 마크를 붙인 예외를 두는 것이 타당할 수도 있습니다.

public SomeObject() {
    if (todayIsWednesday) throw new YouKnowYouCannotDoThisOnAWednesday();
}

하지만 그게 얼마나 자주 일어날까?

여기의 다른 답변에서 설명한 바와 같이 Java Secure Coding Guidelines의 가이드라인 7-3에서 최종이 아닌 클래스의 컨스트럭터에 예외를 설정하면 잠재적인 공격 벡터가 열립니다.

가이드라인 7-3 / OBJECT-3: 비최종 클래스의 부분적으로 초기화된 인스턴스로부터 보호 비최종 클래스의 생성자가 예외를 발생시키면 공격자는 해당 클래스의 부분적으로 초기화된 인스턴스에 대한 액세스를 시도할 수 있습니다.최종 클래스가 아닌 클래스는 생성자가 정상적으로 완료될 때까지 완전히 사용할 수 없는 상태로 유지하십시오.

JDK 6부터는 오브젝트 컨스트럭터가 완료되기 전에 예외를 발생시킴으로써 서브클래스 구축을 방지할 수 있습니다.이를 수행하려면 this() 또는 super() 호출로 평가되는 식에서 체크를 수행합니다.

    // non-final java.lang.ClassLoader
    public abstract class ClassLoader {
        protected ClassLoader() {
            this(securityManagerCheck());
        }
        private ClassLoader(Void ignored) {
            // ... continue initialization ...
        }
        private static Void securityManagerCheck() {
            SecurityManager security = System.getSecurityManager();
            if (security != null) {
                security.checkCreateClassLoader();
            }
            return null;
        }
    }

이전 릴리스와의 호환성을 위해 초기화된 플래그를 사용해야 합니다.성공적으로 돌아가기 전에 플래그를 생성자의 마지막 작업으로 설정하십시오.기밀 조작의 게이트웨이를 제공하는 모든 메서드는, 속행하기 전에, 우선 플래그를 참조할 필요가 있습니다.

    public abstract class ClassLoader {

        private volatile boolean initialized;

        protected ClassLoader() {
            // permission needed to create ClassLoader
            securityManagerCheck();
            init();

            // Last action of constructor.
            this.initialized = true;
        }
        protected final Class defineClass(...) {
            checkInitialized();

            // regular logic follows
            ...
        }

        private void checkInitialized() {
            if (!initialized) {
                throw new SecurityException(
                    "NonFinal not initialized"
                );
            }
        }
    }

또, 이러한 클래스의 시큐러티에 민감한 사용에서는, 초기화 플래그 상태를 확인할 필요가 있습니다.ClassLoader 구성의 경우 부모 클래스 로더가 초기화되었는지 확인해야 합니다.

비최종 클래스의 부분적으로 초기화된 인스턴스는 파이널라이저 공격을 통해 액세스할 수 있습니다.공격자는 서브클래스의 보호된 최종 메서드를 덮어쓰고 해당 서브클래스의 새 인스턴스를 작성하려고 합니다.이 시도는 실패하지만(위의 예에서는 ClassLoader의 컨스트럭터에서 SecurityManager 체크가 보안 예외를 발생시킵니다), 공격자는 예외를 무시하고 가상 머신이 부분적으로 초기화된 개체에 대해 완료를 수행할 때까지 기다립니다.이 경우 악의적인 최종 결정 메서드 구현이 호출되어 공격자가 최종 결정 중인 개체에 대한 참조를 액세스할 수 있습니다.오브젝트가 부분적으로만 초기화되어 있어도 공격자는 오브젝트에서 메서드를 호출할 수 있기 때문에 Security Manager 체크를 회피할 수 있습니다.초기화 플래그가 부분적으로 초기화된 개체에 대한 액세스를 차단하지는 않지만 해당 개체의 메서드가 공격자에게 유용한 작업을 수행하는 것은 방지합니다.

초기화 플래그를 사용하는 것은 안전하지만 번거로울 수 있습니다.오브젝트 초기화가 정상적으로 완료될 때까지 퍼블릭비최종 클래스의 모든 필드에 안전한 값(null 등)이 포함되어 있는지 확인하는 것만으로 보안에 영향을 받지 않는 클래스에서 적절한 대안이 될 수 있습니다.

보다 견고하지만 보다 상세한 접근방식은 "구현 포인터"(또는 "pimpl")를 사용하는 것입니다.클래스의 코어는 인터페이스 클래스 전송 방식 호출에 의해 비퍼블릭클래스로 이동됩니다.완전히 초기화되기 전에 클래스를 사용하려고 하면 Null Pointer가 생성됩니다.예외.이 접근방식은 클론 공격 및 역직렬화 공격에 대한 대처에도 적합합니다.

    public abstract class ClassLoader {

        private final ClassLoaderImpl impl;

        protected ClassLoader() {
            this.impl = new ClassLoaderImpl();
        }
        protected final Class defineClass(...) {
            return impl.defineClass(...);
        }
    }

    /* pp */ class ClassLoaderImpl {
        /* pp */ ClassLoaderImpl() {
            // permission needed to create ClassLoader
            securityManagerCheck();
            init();
        }

        /* pp */ Class defineClass(...) {
            // regular logic follows
            ...
        }
    }

선택된 예외를 발생시킬 필요는 없습니다.이는 프로그램 제어 범위 내의 버그이므로 체크되지 않은 예외를 발생시키고자 합니다.Java 언어에서 이미 제공되는 다음과 같은 선택되지 않은 예외 중 하나를 사용합니다.IllegalArgumentException,IllegalStateException ★★★★★★★★★★★★★★★★★」NullPointerException

또한 세터를 제거하는 것이 좋습니다.은 이미 해 주셨습니다.age컨스트럭터를 경유합니다.스턴스화 데데? ?데? ????그렇지 않으면 세터를 건너뜁니다.좋은 규칙은 필요 이상으로 사물을 공개하지 않는 것이다.default로 하고, 「」로 .final .Person이치노안심하고 사용할 수 있습니다.

가장 중요한 것은 다음과 같습니다.

class Person { 

  private final int age;   

  Person(int age) {    

    if (age < 0) 
       throw new IllegalArgumentException("age less than zero: " + age); 

    this.age = age;   
  }

  // setter removed

이건 완전히 유효해, 난 항상 그래.파라미터 체크 결과인 경우 Ilgonal Argemnt Exception을 사용합니다.

이 경우 단언은 권장하지 않습니다.왜냐하면 도입 빌드에서 단언은 해제되어 있기 때문입니다.또, 단언은 유효합니다.단, 단언은 유효합니다.다만, 실행시에 파라미터의 문제를 놓치는 것이, 예외의 발생보다 가능성이 높다고 생각되는 경우는 유효합니다.실행 시 크래시를 일으킵니다.

또, 어설션은 발신자가 트랩 하는 것이 더 어려워집니다.이것은 간단합니다.

발신자가 놀라지 않도록 메서드의 javadoc에 "throws"로 표시할 수 있습니다.

나는 컨스트럭터에 예외를 두는 것이 나쁜 관행이라고 생각해 본 적이 없다.클래스가 설계되면 해당 클래스의 구조가 무엇인지에 대한 특정 생각을 하게 됩니다.다른 사람이 다른 아이디어를 가지고 그 아이디어를 실행하려고 할 경우, 사용자는 그에 따라 오류에 대한 피드백을 사용자에게 제공해야 합니다.당신의 경우, 당신은 다음과 같은 것을 고려할 수 있습니다.

if (age < 0) throw new NegativeAgeException("The person you attempted " +
                       "to construct must be given a positive age.");

서 ''는NegativeAgeException는 사용자가이며, 에 따라서는 '예외', '예외하다', '예외하다', '예외하다'와 같은 다른 할 수 있습니다.IndexOutOfBoundsException뭐 비슷한 거.

코드의 버그를 발견하려고 하지 않기 때문에, 어설션도 그다지 좋은 방법은 아닌 것 같습니다.예외적으로 종료하는 것이 전적으로 옳은 일이라고 생각합니다.

예외를 던지는 것은 잘못된 관행입니다.그러면 컨스트럭터를 호출하는 모든 사용자가 예외를 잡아야 합니다.이것은 잘못된 관행입니다.

컨스트럭터(또는 어떤 메서드)가 예외를 슬로우하도록 하는 것이 좋습니다.일반적으로 Ilgal Argument를 말합니다.예외는 선택 해제되어 있기 때문에 컴파일러가 강제로 검출하지 않습니다.

선택한 예외(예외에서 확장되지만 런타임에서는 확장되지 않음)를 슬로우해야 합니다.예외) 발신자가 수신할 필요가 있는 경우.

저는 예외사항을 컨스트럭터에 넣는 것을 찬성하지 않습니다. 왜냐하면 저는 이것이 깨끗하지 않다고 생각하기 때문입니다.내 의견에는 몇 가지 이유가 있다.

  1. Richard가 언급했듯이 인스턴스를 쉽게 초기화할 수 없습니다.특히 테스트에서는 초기화 중에 테스트 전체에 걸친 오브젝트를 테스트 캐치로 둘러싸는 것만으로 작성하는 것이 매우 귀찮습니다.

  2. 생성자는 논리가 없어야 합니다.항상 우려의 분리 및 단일 책임 원칙을 지향하기 때문에 컨스트럭터에 논리를 캡슐화할 이유가 전혀 없습니다.컨스트럭터의 관심사는 "개체를 구성하는 것"이기 때문에 이 접근방식을 따를 경우 예외 처리를 캡슐화해서는 안 됩니다.

  3. 디자인이 안 좋은 것 같아요.임호 내가 어쩔 수 없이 컨스트럭터에서 예외처리를 하게 된다면, 나는 처음에 내가 우리 반에서 디자인 사기를 당하지 않았는지 자문하게 된다.때로는 필요하지만, 건설업자나 공장에 아웃소싱하여 건설업자를 최대한 심플하게 합니다.

따라서 컨스트럭터에서 예외 처리를 수행해야 하는 경우 이 로직을 공장 빌더에게 아웃소싱하지 않는 이유는 무엇입니까?코드 행이 몇 줄 더 늘어날 수 있지만 예외 처리를 위해 로직을 아웃소싱할 수 있고 컨스트럭터에 고착되지 않기 때문에 훨씬 더 강력하고 적합한 예외 처리를 구현할 수 있습니다.또한 예외 처리를 적절히 위임하면 클라이언트는 구성 로직에 대해 아무것도 알 필요가 없습니다.

언급URL : https://stackoverflow.com/questions/6086334/is-it-good-practice-to-make-the-constructor-throw-an-exception

반응형