Programing

Java 생성자 스타일 : 검사 매개 변수가 null이 아닙니다.

lottogame 2020. 11. 7. 08:56
반응형

Java 생성자 스타일 : 검사 매개 변수가 null이 아닙니다.


일부 매개 변수를 허용하지만 허용되지 않는 클래스가있는 경우 모범 사례는 무엇입니까 null?

다음은 분명하지만 예외는 약간 명확하지 않습니다.

public class SomeClass
{
     public SomeClass(Object one, Object two)
     {
        if (one == null || two == null)
        {
            throw new IllegalArgumentException("Parameters can't be null");
        }
        //...
     }
}

여기에서 예외를 통해 어떤 매개 변수가 null인지 알 수 있지만 생성자는 이제 매우보기 흉합니다.

public class SomeClass
{
     public SomeClass(Object one, Object two)
     {
        if (one == null)
        {
            throw new IllegalArgumentException("one can't be null");
        }           
        if (two == null)
        {
            throw new IllegalArgumentException("two can't be null");
        }
        //...
  }

여기서 생성자는 깔끔하지만 이제 생성자 코드는 실제로 생성자에 없습니다.

public class SomeClass
{
     public SomeClass(Object one, Object two)
     {
        setOne(one);
        setTwo(two);
     }


     public void setOne(Object one)
     {
        if (one == null)
        {
            throw new IllegalArgumentException("one can't be null");
        }           
        //...
     }

     public void setTwo(Object two)
     {
        if (two == null)
        {
            throw new IllegalArgumentException("two can't be null");
        }
        //...
     }
  }

다음 중 가장 좋은 스타일은 무엇입니까?

아니면 더 널리 받아 들여지는 대안이 있습니까?


두 번째 또는 세 번째.

API 사용자에게 정확히 무엇이 잘못되었는지 알려주기 때문입니다.

Validate.notNull(obj, message)commons-lang에서 덜 자세한 사용 위해 . 따라서 생성자는 다음과 같습니다.

public SomeClass(Object one, Object two) {
    Validate.notNull(one, "one can't be null");
    Validate.notNull(two, "two can't be null");
    ...
}

setter에 체크를 배치하는 것도 동일한 자세한 설명으로 허용됩니다. setter가 객체 일관성을 유지하는 역할도 가지고 있다면 세 번째도 선택할 수 있습니다.


사전 조건 검사를 용이하게하기 위해 설계된 많은 라이브러리 중 하나를 사용할 수 있습니다. Google Guava의 많은 코드 com.google.common.base.Preconditions

올바른 인수와 상태를 확인하기 위해 자체 메서드를 시작할 때 호출되는 간단한 정적 메서드입니다. 이것은 다음과 같은 구조를 허용합니다.

 if (count <= 0) {
   throw new IllegalArgumentException("must be positive: " + count);
 }

더 콤팩트하게 대체 될

 checkArgument(count > 0, "must be positive: %s", count);

그것은이 checkNotNull되는 구아바 내에서 광범위하게 사용 . 그런 다음 다음과 같이 작성할 수 있습니다.

 import static com.google.common.base.Preconditions.checkNotNull;
 //...

 public SomeClass(Object one, Object two) {
     this.one = checkNotNull(one);
     this.two = checkNotNull(two, "two can't be null!");
     //...
 }

대부분의 메서드는 오류 메시지가 없거나 수정 된 오류 메시지 또는 varargs가있는 템플릿 화 된 오류 메시지를 사용하도록 오버로드됩니다.


IllegalArgumentExceptionNullPointerException

원래 코드가 발생하는 동안 IllegalArgumentExceptionnull인수, 구아바의이 Preconditions.checkNotNull발생 NullPointerException대신.

다음은 Effective Java 2nd Edition 의 인용문입니다 . 항목 60 : 표준 예외 사용을 선호하십시오 .

틀림없이 모든 잘못된 메서드 호출은 불법 인수 또는 불법 상태로 귀결되지만 다른 예외는 특정 종류 의 불법 인수 및 상태에 대해 표준 적으로 사용됩니다 . 호출자가 nullnull 값이 금지 된 일부 매개 변수를 전달 하면 규칙 NullPointerException이 아닌 IllegalArgumentException.

A NullPointerExceptionnull참조 멤버에 액세스 할 때만 예약되지 않습니다 . 논쟁이 null불법적 인 가치 일 때 그것들을 던지는 것은 꽤 표준 입니다.

System.out.println("some string".split(null));
// throws NullPointerException

Old question; another new answer (already mentioned by another comment; but I think worth its own answer).

Java 7 added java.lang.Objects.requireNonNull() to the APIs everybody can use. So checking all arguments for null boils down to a short list like:

this.arg1 = Objects.requireNonNull(arg1, "arg1 must not be null");
this.arg2 = Objects.requireNonNull(arg2, "arg2 must not be null");

Side notes:

  • make sure to not reverse the two arguments - the second one is the message that will be used for the NPE which is thrown if the first argument is null (if you reverse them, well, then your check will never fail)
  • another best practice: if possible, make all your class members final (so you can be sure: when some object has been created successfully, all its members are not null; and they won't change over time)

I would have a utility method:

 public static <T> T checkNull(String message, T object) {
     if(object == null) {
       throw new NullPointerException(message);
     }
     return object;
  }

I would have it return the object so that you can use it in assignments like this:

 public Constructor(Object param) {
     this.param = checkNull("Param not allowed to be null", param);
 }

EDIT: Regarding the suggestions to use a third party library, the Google Preconditions in particular does the above even better than my code. However, if this is the only reasons to include the library in your project, I'd be hesitant. The method is too simple.


Apart from the answers given above which are all valid and reasonable, I think it's good to point out that maybe checking for null isn't necessary "good practice". (Assuming readers other than the OP might take the question as dogmatic)

From Misko Hevery blog on testability: To Assert or Not To Assert


Comparison of Ways to Check Preconditions in Java - Guava vs. Apache Commons vs. Spring Framework vs. Plain Java Asserts

public static void fooSpringFrameworkAssert(String name, int start, int end) {
        // Preconditions
        Assert.notNull(name, "Name must not be null");
        Assert.isTrue(start < end, "Start (" + start + ") must be smaller than end (" + end + ")");

        // Do something here ...
    }

    public static void fooApacheCommonsValidate(String name, int start, int end) {
        // Preconditions
        Validate.notNull(name, "Name must not be null");
        Validate.isTrue(start < end, "Start (%s) must be smaller than end (%s)", start, end);

        // Do something here ...
    }

    public static void fooGuavaPreconditions(String name, int start, int end) {
        // Preconditions
        Preconditions.checkNotNull(name, "Name must not be null");
        Preconditions.checkArgument(start < end, "Start (%s) must be smaller than end (%s)", start, end);

        // Do something here ...
    }

    public static void fooPlainJavaAsserts(String name, int start, int end) {
        // Preconditions
        assert null != name : "Name must not be null";
        assert start < end : "Start (" + start + ") must be smaller than end (" + end + ")";

        // Do something here ...
    }

this is summary of this article: http://www.sw-engineering-candies.com/blog-1/comparison-of-ways-to-check-preconditions-in-java


An alternative to throwing an unchecked exception would be the usage of assert. Otherwise I´d throw checked exceptions to make the caller aware of the fact, that the constructor will not work with illegal values.

The difference between your first two solutions - do you need a detailed error message, do you need to know which parameter failed or is it enough to know, that the instance couldn't have been created due to illegal arguments?

Note, that the second and third example can't report correctly that both parameters have been null.

BTW - I vote for a variation of (1):

if (one == null || two == null) {
    throw new IllegalArgumentException(
      String.format("Parameters can't be null: one=%s, two=%s", one, two));
}

Annotations for static analysis are also useful, either in-addition-to or in-place-of the run-time checks.

FindBugs, for example, provides an @NonNull annotation.

public SomeClass( @NonNull Object one, @NonNull Object two) {


You can simply have a method which takes all the constructor arguments that you need to validate. This method throws exception with specific message depending on which argument is not valid. Your constructor calls this method, and if it passes, it initialize values.


I assume that you talk about the built in assert in Java. In my opinion it's not a really good idea to use it. Since it can be turned on/off using command line parameters. Therefore some says it is only acceptable to use in private methods.

My mentors are telling me not to re-invent the wheel! Their advice is to use libraries. They are (probably) well designed and tested. Of course it is your responsibility to make sure you grab a good-quality library.

Others are telling me that Enterprise ppl - in some terms - are wrong and you introduce more dependency - for simple tasks - than required. I can accept that point too... But here is my latest experience:

First I wrote my own private method to check null parameters. It's boring and redundant. I know I should put it into a Utility class. But why should I write it at the first place, when someone has already has done it? I can save time not writing unit test and design an existing stuff. Unless you want to exercise or learn I wouldn't recommend to do so.

I recently started to use google's guava and I find that - along with apache commons - once you start to use them, you won't use just for that one single method. You'll discover and use it more and more. At the end, this'll make your code shorter, more readable, more consistent and more maintainable.

BTW.: Depending on your aims I would go with 2 or 3 using one of the mentioned library above...

참고URL : https://stackoverflow.com/questions/2997768/java-constructor-style-check-parameters-arent-null

반응형