비교와 논리 연산
조건문에 들어가는 표현식은 결국 하나의 boolean 값을 만듭니다.
숫자 비교와 객체 비교는 같은 == 기호를 사용해도 의미가 다릅니다.
논리 연산자는 여러 조건을 조합하며 단락 평가를 통해 뒤 조건을 실행하지 않을 수 있습니다.
이 특성은 성능 최적화보다 안전한 접근 순서를 만드는 데 더 중요합니다.
여기서는 조건을 읽는 순서와 비교 대상의 정체를 함께 확인합니다.
값 비교와 참조 비교를 나눈다
기본 타입의 ==는 값을 비교하지만 객체 참조의 ==는 같은 객체인지 비교합니다.
문자열 내용은 equals를 사용해야 합니다.
&&와 ||는 필요한 만큼만 평가한다
&&는 앞 조건이 거짓이면 뒤를 평가하지 않고 ||는 앞 조건이 참이면 멈춥니다.
null 검사 뒤에 메서드 호출을 두는 순서가 안전한 이유입니다.
LogicalChecks.java는 null 검사 뒤의 메서드 호출과 같은 글자를 가진 두 문자열의 비교를 한 번에 보여 줍니다. 어떤 식은 호출조차 되지 않고 어떤 비교는 거짓이 되는지 이유를 나누어 봅니다.
public class LogicalChecks {
public static void main(String[] args) {
String input = null;
boolean usable = input != null && !input.isBlank();
System.out.println("usable=" + usable);
String left = new String("java");
String right = "java";
System.out.println("same object=" + (left == right));
System.out.println("same text=" + left.equals(right));
// boolean broken = input != null & !input.isBlank(); // 실행 시 NPE: 단락 평가 안 함
}
}오른쪽 조건이 호출되지 않는 출력은 단락 평가가 단순 최적화가 아니라 실행 의미라는 증거입니다. value != null && !value.isBlank()처럼 안전 조건을 먼저 두면 두 번째 식은 첫 번째가 참일 때만 평가됩니다.
usable=false
same object=false
same text=true&&는 첫 조건이 거짓이면 뒤 메서드를 호출하지 않아 null 접근을 막습니다.
&&와 || 모두 왼쪽 피연산자부터 계산합니다. 이 식이 전체 결과를 확정할 수 있는지가 다음 호출의 실행 여부를 결정합니다.
&&는 왼쪽이 거짓이면 멈추고 ||는 왼쪽이 참이면 멈춥니다. null 검사나 비용이 큰 호출은 이 순서를 의도적으로 사용합니다.
필요한 피연산자만 평가한 결과가 하나의 boolean이 되어 if에 전달됩니다. 오른쪽 식의 부작용에 기대면 조건 순서를 바꾸기 어려워지므로 피합니다.
부정은 조건 전체에 적용한다
복합 조건을 부정할 때 드모르간 법칙으로 연산자가 함께 바뀝니다.
긴 부정식은 긍정적인 이름의 불리언 변수로 분리하면 읽기 쉽습니다.
!(age >= 18 && hasTicket)은 age < 18 || !hasTicket과 같습니다. 부정을 바깥에 둔 식과 드모르간 법칙으로 풀어 쓴 식에 경계값 17, 18, 19를 넣어 보면 연산자뿐 아니라 비교 방향도 함께 바뀌어야 함을 확인할 수 있습니다.
int age = 18;
boolean adult = age >= 18;
boolean outside = age < 0 || age > 130;
boolean inside = !outside;double value = Double.NaN;
System.out.println(value == value); // false
System.out.println(Double.isNaN(value)); // true조건의 경계값을 직접 써 본다
미만과 이하, 초과와 이상의 차이는 경계 하나에서만 드러납니다.
최소값, 바로 아래, 최대값, 바로 위를 대입해 조건을 확인하면 실수를 줄일 수 있습니다.
부동소수점 동등 비교에는 허용 오차가 필요하다
계산 결과 double은 표현 오차가 있으므로 a == b 대신 문제 영역에 맞는 허용 오차를 비교합니다.
NaN은 자기 자신과도 같지 않다는 규칙도 확인합니다.
허용 오차는 무조건 0.000001로 고정하는 값이 아니라 데이터 규모와 요구 정밀도에서 정해야 합니다. 매우 큰 수나 매우 작은 수를 비교할 때는 절대 오차와 상대 오차 가운데 어떤 기준이 문제 계약에 맞는지 먼저 결정합니다.
좋은 조건식은 비교 대상, 단락 평가 순서, 경계값을 코드만 보고도 설명할 수 있습니다.