java - 지역변수 - 자바 주장 키워드는 무엇을하며 언제 사용해야합니까?




자바 final 변수 (12)

Java에서 assert 키워드는 무엇을합니까?

컴파일 된 바이트 코드를 살펴 보겠습니다.

결론은 다음과 같습니다.

public class Assert {
    public static void main(String[] args) {
        assert System.currentTimeMillis() == 0L;
    }
}

다음과 같이 거의 동일한 바이트 코드를 생성합니다.

public class Assert {
    static final boolean $assertionsDisabled =
        !Assert.class.desiredAssertionStatus();
    public static void main(String[] args) {
        if (!$assertionsDisabled) {
            if (System.currentTimeMillis() != 0L) {
                throw new AssertionError();
            }
        }
    }
}

여기서, Assert.class.desiredAssertionStatus()-ea 가 명령 행에서 전달 될 때 true 이고, 그렇지 않으면 false입니다.

우리는 System.currentTimeMillis() 를 사용하여 최적화되지 않도록합니다 ( assert true; ).

synthetic 필드는 생성 될 때 Java가 단지 Assert.class.desiredAssertionStatus() 를로드 할 때 한 번 호출하면되고 그 결과를 거기에 캐시합니다. 또한보십시오 : "static synthetic"의 의미는 무엇입니까?

다음과 같이 확인할 수 있습니다.

javac Assert.java
javap -c -constants -private -verbose Assert.class

Oracle JDK 1.8.0_45에서는 합성 정적 필드가 생성되었습니다 (참조 : "정적 합성"의 의미는 무엇입니까? ) :

static final boolean $assertionsDisabled;
  descriptor: Z
  flags: ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC

정적 이니셜 라이저와 함께 :

 0: ldc           #6                  // class Assert
 2: invokevirtual #7                  // Method java/lang Class.desiredAssertionStatus:()Z
 5: ifne          12
 8: iconst_1
 9: goto          13
12: iconst_0
13: putstatic     #2                  // Field $assertionsDisabled:Z
16: return

주요 방법은 다음과 같습니다.

 0: getstatic     #2                  // Field $assertionsDisabled:Z
 3: ifne          22
 6: invokestatic  #3                  // Method java/lang/System.currentTimeMillis:()J
 9: lconst_0
10: lcmp
11: ifeq          22
14: new           #4                  // class java/lang/AssertionError
17: dup
18: invokespecial #5                  // Method java/lang/AssertionError."<init>":()V
21: athrow
22: return

결론은 다음과 같습니다.

  • assert 위한 바이트 코드 수준의 지원이 없다 : 자바 언어 개념이다.
  • assert 는 시스템 속성에서 꽤 잘 에뮬레이트 될 수 있습니다. -Pcom.me.assert=true 명령 줄에서 -ea 를 바꾸고 throw new AssertionError() 합니다.

단언의 주요 역할을 이해하기위한 실제 사례 는 무엇입니까?


Assert는 개발할 때 매우 유용합니다. 코드가 올바르게 작동하면 무언가가 발생 하지 않을 때 사용합니다. 실생활에서 사용하지 않기 때문에 사용하기 쉽고 코드에 영원히 머무를 수 있습니다.

상황이 실제 생활에서 발생할 수있는 가능성이 있다면, 당신은 그것을 처리해야합니다.

나는 그것을 좋아하지만 Eclipse / Android / ADT에서 어떻게 켜는 지 모른다. 디버깅 할 때도 꺼져있는 것 같습니다. (여기에 스레드가 있지만 ADT 실행 구성에 나타나지 않는 'Java VM'을 참조합니다.)


다음은 Hibernate / SQL 프로젝트를 위해 서버에서 작성한 어설 션입니다. 엔티티 bean에는 isActive 및 isDefault라는 두 개의 유효 부울 속성이 있습니다. 각각은 "Y"또는 "N"값 또는 "N"으로 처리 된 널 값을 가질 수 있습니다. 우리는 브라우저 클라이언트가이 세 가지 값으로 제한되는지 확인하려고합니다. 그래서,이 두 속성에 대한 제 설정 자에서이 어설 션을 추가했습니다.

assert new HashSet<String>(Arrays.asList("Y", "N", null)).contains(value) : value;

다음 사항에 유의하십시오.

  1. 이 주장은 개발 단계에만 해당됩니다. 클라이언트가 나쁜 값을 보내는 경우, 우리가 생산에 도달하기 오래 전에 그것을 잡아서 고칠 것입니다. 어설 션은 사용자가 일찍 잡을 수있는 결함에 대한 것입니다.

  2. 이 단언은 느리고 비효율적이다. 괜찮아. 어설 션은 자유롭게 느려질 수 있습니다. 개발 전용 도구이기 때문에 상관 없습니다. 어설 션이 비활성화되므로 프로덕션 코드가 느려지지 않습니다. (이 점에 대해서는 약간의 불일치가 있는데, 나중에 설명하겠다.) 이것이 나의 다음 요점으로 이어진다.

  3. 이 단언은 부작용이 없습니다. 수정 불가능한 정적 최종 세트에 대해 내 가치를 테스트 할 수는 있었지만, 그 세트는 결코 사용되지 않을 생산 환경에서 머물러 있었을 것입니다.

  4. 이 어설 션은 클라이언트의 올바른 작동을 확인하기 위해 존재합니다. 따라서 프로덕션에 도달 할 때까지는 클라이언트가 제대로 작동하고 있으므로 어설 션을 안전하게 해제 할 수 있습니다.

  5. 어떤 사람들은 이것을 묻습니다 : 프로덕션에서 어설 션이 필요하지 않다면, 끝내면 그냥 꺼내지 않는 이유는 무엇입니까? 다음 버전 작업을 시작할 때 여전히 필요하기 때문입니다.

어떤 사람들은 모든 버그가 사라 졌는지 절대 확신 할 수 없으므로 어설 션을 사용해서는 안된다는 주장을 했으므로 프로덕션 환경에서도이를 유지해야합니다. assert 문을 사용하는 것은 아무런 의미가 없습니다. 단점은 assert 문을 끌 수 있다는 것입니다. 그러므로이 생각에 따르면, 당신은 (거의) 주장을 사용해서는 안됩니다. 나는 동의하지 않는다. 테스트가 프로덕션 환경에 속한 경우에는 어설 션을 사용하지 않아야합니다. 그러나이 테스트는 프로덕션에 속하지 않습니다 . 이 도구는 프로덕션에 도달하지 않을 가능성이있는 버그를 잡기위한 것입니다. 따라서 작업이 끝나면 안전하게 끌 수 있습니다.

BTW, 나는 이것을 다음과 같이 쓸 수 있었다 :

assert value == null || value.equals("Y") || value.equals("N") : value;

3 개의 값만 유효하지만, 가능한 값의 수가 커지면 HashSet 버전이보다 편리해진다. 저는 효율성에 대한 요점을 나타 내기 위해 HashSet 버전을 선택했습니다.


다음은 가장 일반적인 사용 사례입니다. 열거 형 값을 사용한다고 가정 해보십시오.

switch (fruit) {
  case apple:
    // do something
    break;
  case pear:
    // do something
    break;
  case banana:
    // do something
    break;
}

모든 사건을 처리하는 한 괜찮습니다. 하지만 언젠가는 누군가가 당신의 열거 형에 무화과를 추가하고 그것을 스위치 명세서에 추가하는 것을 잊어 버릴 것입니다. 스위치 문을 종료 할 때까지 효과가 느껴지지 않기 때문에 잡기가 까다로운 버그가 생성됩니다. 그러나 이와 같이 스위치를 작성하면 즉시 잡을 수 있습니다.

switch (fruit) {
  case apple:
    // do something
    break;
  case pear:
    // do something
    break;
  case banana:
    // do something
    break;
  default:
    assert false : "Missing enum value: " + fruit;
}

어설 션은 사후 조건을 확인하고 사전 조건을 "절대로 실패해서는 안됩니다"라는 데 사용됩니다. 올바른 코드가 어설 션을 실패해서는 안됩니다. 그들이 방아쇠를 당길 때, 그들은 버그 (문제의 실제 궤적이있는 곳과 가까운 곳에 있기를 바랍니다)를 나타내야합니다.

어설 션의 예는 특정 순서의 메서드 그룹이 올바른 순서로 호출 hasNext() 하는 것입니다 (예 : hasNext()Iterator 에서 next() 보다 먼저 호출 됨).


어설 션은 코드의 결함을 탐지 할 수있게합니다. 테스트 및 디버깅을 위해 어설 션을 켤 수 있으며 프로그램 생산 중에는 어설 션을 해제 할 수 있습니다.

그것이 사실임을 알 때 왜 뭔가를 주장합니까? 모든 것이 제대로 작동 할 때만 사실입니다. 프로그램에 결함이있는 경우 사실이 아닐 수도 있습니다. 이 과정의 초기 단계에서이를 감지하면 잘못된 점을 알 수 있습니다.

assert 문은이 문을 선택적 String 메시지와 함께 포함합니다.

assert 문의 구문에는 다음과 같은 두 가지 형식이 있습니다.

assert boolean_expression;
assert boolean_expression: error_message;

다음은 어설 션을 사용해야하는 위치와 사용하지 말아야 할 위치를 제어하는 ​​몇 가지 기본 규칙입니다. 어설 션 다음 용도로 사용 되어야 합니다.

  1. 개인 메소드의 입력 매개 변수를 검증합니다. 공개 메소드가 아닙니다 . public 메소드는 잘못된 매개 변수를 전달할 때 일반 예외를 throw해야합니다.

  2. 거의 확실하게 사실의 타당성을 보장하는 프로그램의 어느 곳에서나.

예를 들어, 그것이 1 또는 2 중 하나 일 것이라는 확신이 들면 다음과 같은 어설 션을 사용할 수 있습니다.

...
if (i == 1)    {
    ...
}
else if (i == 2)    {
    ...
} else {
    assert false : "cannot happen. i is " + i;
}
...
  1. 모든 메소드의 끝에서 사후 조건 검증. 즉, 비즈니스 로직을 실행 한 후에 어설 션을 사용하여 변수 또는 결과의 내부 상태가 예상 한 것과 일치하는지 확인할 수 있습니다. 예를 들어, 소켓 또는 파일을 여는 메소드는 끝에 어설 션을 사용하여 소켓 또는 파일이 실제로 열려 있는지 확인할 수 있습니다.

어설 션 다음 용도로 사용 하면 안됩니다 .

  1. 공용 메소드의 입력 매개 변수를 검증합니다. 어설 션은 항상 실행되지 않을 수 있기 때문에 규칙적인 예외 메커니즘을 사용해야합니다.

  2. 사용자가 입력 한 것에 대한 제약 조건을 검증합니다. 같은 상기와.

  3. 부작용으로 사용되어서는 안됩니다.

예를 들어 여기에서는 doSomething() 메서드 호출의 부작용에 어설 션을 사용하기 때문에 적절하지 않습니다.

public boolean doSomething() {
...    
}
public void someMethod() {       
assert doSomething(); 
}

이것이 정당화 될 수있는 유일한 경우는 코드에서 어설 션을 사용할 수 있는지 여부를 알아 내려고 할 때입니다.

boolean enabled = false;    
assert enabled = true;    
if (enabled) {
    System.out.println("Assertions are enabled");
} else {
    System.out.println("Assertions are disabled");
}

여기에 제공된 모든 위대한 답변 외에도 공식 Java SE 7 프로그래밍 가이드에는 assert 사용에 대한 매우 간결한 설명서가 있습니다. 어설 션을 사용하는 것이 좋은 (그리고 중요한 것은 나쁜) 아이디어 일 때와 예외를 던지는 것과 다른 점이 몇 가지 있습니다.

Link


요점을 되짚어 보자. (그리고 이것은 자바 뿐만이 아니라 많은 언어에서 가능하다.)

"assert"는 주로 디버깅 프로세스 중에 소프트웨어 개발자가 디버깅을 돕는 데 사용됩니다. 어설 션 메시지는 절대 나타나서는 안됩니다. 많은 언어가 "생산"코드를 생성하는 데 사용하기 위해 모든 "주장"을 무시하도록하는 컴파일 타임 옵션을 제공합니다.

"예외"는 논리 오류를 나타내는 지 여부와 상관없이 모든 종류의 오류 조건을 처리 할 수있는 편리한 방법입니다. 오류 상태가되어 계속 진행할 수 없으면 단순히 " "당신이있는 곳이면 어디든지 다른 사람이 그들을"붙잡을 "준비가되어 있다고 기대합니다. 컨트롤은 예외를 던진 코드에서 곧바로 포수의 미트에게 한 단계로 전달됩니다. (그리고 포수는 일어난 전화의 완전한 백 트레이스를 볼 수 있습니다.)

게다가 서브 루틴을 호출 한 사람은 서브 루틴이 성공했는지 여부를 확인하지 않아도됩니다. "우리가 지금 여기 있으면 성공했을 것입니다. 그렇지 않으면 예외가 발생했을 것이고 지금은 여기에 없을 것입니다!" 이 간단한 전략은 코드 디자인과 디버깅을 훨씬 더 쉽게 만듭니다.

예외는 치명적 오류 조건을 "규칙 예외"로 편리하게 허용합니다. 그리고 그들도 "규칙의 예외"인 코드 경로에 의해 처리되어야합니다 ... "공을!"


Assertions ( assert 키워드를 통해)이 Java 1.4에 추가되었습니다. 이들은 코드에서 불변의 정확성을 검증하는 데 사용됩니다. 프로덕션 코드에서 절대로 트리거해서는 안되며 코드 경로의 버그 또는 오용을 나타냅니다. java 명령에서 -ea 옵션을 사용하여 런타임에 활성화 할 수 있지만 기본적으로 활성화되지는 않습니다.

예 :

public Foo acquireFoo(int id) {
  Foo result = null;
  if (id > 50) {
    result = fooService.read(id);
  } else {
    result = new Foo(id);
  }
  assert result != null;

  return result;
}

assert 키워드가 무엇인지 설명하는 좋은 답변이 많지만 "실제 키워드에서 assert 키워드를 사용해야하는시기는 언제입니까?"

은 거의 없습니다 .

어설 션은 개념으로서 훌륭합니다. 좋은 코드에는 if (...) throw ... 문 (및 Objects.requireNonNullMath.addExact 와 같은 친척)이 많이 있습니다. 그러나 특정 디자인 결정은 assert 키워드 자체의 유용성을 크게 제한합니다.

assert 키워드 뒤에있는 아이디어는 시기상조의 최적화이며, 주요 기능은 모든 검사를 쉽게 끌 수 있다는 것입니다. 사실, assert 검사는 기본적으로 해제되어 있습니다.

그러나 불변 수표가 생산에서 계속 수행되는 것이 매우 중요합니다. 이는 완벽한 테스트 커버리지가 불가능하고 모든 프로덕션 코드에 어설 션이 진단 및 완화에 도움이되는 버그를 가지고 있기 때문입니다.

따라서 public 메서드의 매개 변수 값을 확인하고 IllegalArgumentException 을 throw 할 때와 마찬가지로 if (...) throw ... 를 사용하는 것이 바람직합니다.

때로는 불필요하게 오랜 시간이 걸리는 불변 수표를 쓰기를 원할 수도 있습니다. 그러나 그러한 검사는 시험을 느리게 할 수있어 바람직하지 않습니다. 그러한 시간을 소비하는 수표는 대개 단위 테스트로 작성됩니다. 그럼에도 불구하고 때때로 이러한 이유로 assert 를 사용 assert 것이 의미가있을 수 있습니다.

assert 단순히 if (...) throw ... 보다 깨끗하고 예쁘기 때문에 사용하지 마십시오 if (...) throw ... (나는 깨끗하고 예쁜 것을 좋아하기 때문에 큰 고통으로 말합니다). 자신을 도울 수없고 응용 프로그램이 시작되는 방법을 제어 할 수 있다면 assert 자유롭게 사용할 있지만 항상 프로덕션에서 assertion을 활성화하십시오. 틀림없이, 이것은 내가하는 경향이 있습니다. 나는 if (...) throw ... 와 같이 더 많은 행동을하는 어썰트를 유발할 롬복 주석을 요구하고있다. 여기에 투표하십시오.

(Rant : JVM 개발자들은 조만간 코드 작성기를 조기에 최적화했기 때문에 Java Plugin과 JVM에서 많은 보안 문제를 듣고 있으며 기본적인 코드와 어설 션을 프로덕션 코드에 포함시키지 않고 계속해서 가격을 지불하십시오.)


어설 션은 기본적으로 응용 프로그램을 디버그하는 데 사용되거나 일부 응용 프로그램의 예외 처리를 대체하여 응용 프로그램의 유효성을 검사하는 데 사용됩니다.

어설 션은 런타임에 작동합니다. 전체 개념을 매우 간단하게 설명 할 수있는 간단한 예가 여기에 있습니다. - assert 키워드는 Java에서 무엇을합니까? (WikiAnswers).


기본적으로 "assert true"는 통과하고 "false assert"는 실패합니다. 이것이 어떻게 작동하는지 살펴 보겠습니다.

public static void main(String[] args)
{
    String s1 = "Hello";
    assert checkInteger(s1);
}

private static boolean checkInteger(String s)
{
    try {
        Integer.parseInt(s);
        return true;
    }
    catch(Exception e)
    {
        return false;
    }
}




assertions