2026년 02월 07일

💾 비트와 불리언 연산

Java Spring Boot
Cover Image

💾 비트와 불리언 연산

컴퓨터가 생각하는 방식 - 0과 1로 모든 것을 표현하기

🔢 비트(Bit)란?

비트(Bit) = Binary digit (2진 숫자)

핵심 개념:

2진법의 표현

비트는 두 가지 상태로 표현됨:
├─ 0 (거짓, False, OFF, 낮음)
└─ 1 (참, True, ON, 높음)

물리적 구현:


🎯 불리언(Boolean) 값

정의

Boolean: 참(True) 또는 거짓(False) 두 가지 값만 가지는 데이터 타입

boolean isRaining = true;    // 비가 온다
boolean isCold = false;      // 춥지 않다

예/아니오 질문으로 표현 가능

질문Boolean 값
"비가 오는가?"true / false
"사용자가 로그인했는가?"true / false
"재고가 있는가?"true / false
"나이가 19세 이상인가?"true / false

표현 불가능한 질문:


🧮 불리언 연산자 4가지

1️⃣ NOT (논리 부정)

정의: 값을 반대로 뒤집음

boolean isRaining = true;
boolean isNotRaining = !isRaining;  // false

// 실무 예제
boolean isLoggedIn = true;
if (!isLoggedIn) {  // 로그인하지 않았다면
    return "로그인이 필요합니다";
}

진리표:

입력NOT 입력
TF
FT

2️⃣ AND (논리곱)

정의: 모든 조건이 참일 때만 참

boolean isCold = true;
boolean isRaining = true;
boolean wearCoat = isCold && isRaining;  // true

// 실무 예제: 주문 가능 여부
boolean hasStock = product.getStock() > 0;
boolean isPaid = order.getStatus() == OrderStatus.PAID;
boolean canShip = hasStock && isPaid;  // 둘 다 true여야 배송 가능

진리표:

ABA AND B
TTT
TFF
FTF
FFF

Java 연산자:

// Short-circuit: 첫 번째가 false면 두 번째 평가 안 함
if (user != null && user.isActive()) {  // NPE 방지
    // user가 null이면 isActive() 호출 안 함
}

// 비트 AND: 무조건 모두 평가
if (user != null & user.isActive()) {  // NPE 가능!
    // user가 null이어도 isActive() 호출 → NullPointerException
}

3️⃣ OR (논리합)

정의: 하나라도 참이면 참

boolean isCold = true;
boolean isRaining = false;
boolean wearCoat = isCold || isRaining;  // true

// 실무 예제: 할인 적용 가능 여부
boolean isVIP = user.getGrade() == Grade.VIP;
boolean hasEventCoupon = user.hasCoupon("EVENT2025");
boolean canDiscount = isVIP || hasEventCoupon;  // 둘 중 하나만 true면 할인

진리표:

ABA OR B
TTT
TFT
FTT
FFF

Java 연산자:

// Short-circuit: 첫 번째가 true면 두 번째 평가 안 함
if (user.isAdmin() || user.hasPermission("WRITE")) {
    // admin이면 hasPermission() 호출 안 함 (성능 최적화)
}

4️⃣ XOR (배타적 논리합)

정의: 두 값이 다를 때만

boolean a = true;
boolean b = false;
boolean result = a ^ b;  // true (서로 다름)

// 실무 예제: 토글 기능
boolean isLiked = post.isLikedByUser(userId);
post.setLiked(isLiked ^ true);  // 좋아요 상태 반전

진리표:

ABA XOR B
TTF
TFT
FTT
FFF

XOR의 특징:

// XOR은 다른 연산으로 표현 가능
boolean xor = (a || b) && !(a && b);

// 비트 연산에서 자주 사용
int encrypted = data ^ key;  // 암호화
int decrypted = encrypted ^ key;  // 복호화 (같은 key로 다시 XOR)

📊 진리표 (Truth Table)

진리표란?

모든 가능한 입력 조합에 대한 출력을 정리한 표

전체 연산자 비교

ABNOT AA AND BA OR BA XOR B
TTFTTF
TFFFTT
FTTFTT
FFTFFF

💡 실무 활용 예제

1️⃣ 조건문에서의 활용

@Service
public class OrderService {
    
    public boolean canPlaceOrder(User user, Product product, int quantity) {
        // 여러 조건을 AND로 결합
        boolean userValid = user != null && user.isActive();
        boolean productAvailable = product.getStock() >= quantity;
        boolean priceValid = product.getPrice() > 0;
        
        return userValid && productAvailable && priceValid;
    }
    
    public boolean isEligibleForDiscount(User user) {
        // 여러 조건을 OR로 결합
        boolean isVIP = user.getGrade() == Grade.VIP;
        boolean isFirstPurchase = user.getOrderCount() == 0;
        boolean hasEventCoupon = user.hasCoupon("WELCOME");
        
        return isVIP || isFirstPurchase || hasEventCoupon;
    }
}

2️⃣ 권한 체크

@RestController
public class AdminController {
    
    @GetMapping("/admin/users")
    public ResponseEntity<List<User>> getUsers(
        @AuthenticationPrincipal User currentUser
    ) {
        // AND: 둘 다 충족해야 함
        if (currentUser.isAdmin() && currentUser.isActive()) {
            return ResponseEntity.ok(userService.getAllUsers());
        }
        
        return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
    }
    
    @PostMapping("/posts/{id}/delete")
    public ResponseEntity<Void> deletePost(
        @PathVariable Long id,
        @AuthenticationPrincipal User currentUser
    ) {
        Post post = postService.findById(id);
        
        // OR: 둘 중 하나만 충족하면 됨
        boolean canDelete = currentUser.isAdmin() 
                         || post.getAuthorId().equals(currentUser.getId());
        
        if (canDelete) {
            postService.delete(id);
            return ResponseEntity.ok().build();
        }
        
        return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
    }
}

3️⃣ 유효성 검사

@Service
public class ValidationService {
    
    public boolean isValidUser(UserRequest request) {
        // 모든 조건이 true여야 유효한 사용자
        boolean hasEmail = request.getEmail() != null 
                        && !request.getEmail().isEmpty();
        boolean hasPassword = request.getPassword() != null 
                           && request.getPassword().length() >= 8;
        boolean hasName = request.getName() != null 
                       && !request.getName().isEmpty();
        boolean isAdult = request.getAge() >= 19;
        
        return hasEmail && hasPassword && hasName && isAdult;
    }
    
    public boolean canAccessContent(User user, Content content) {
        // NOT 활용
        boolean isNotBlocked = !user.isBlocked();
        boolean isNotExpired = !content.isExpired();
        
        // OR + NOT 조합
        boolean hasPermission = content.isPublic() 
                             || content.getAuthorId().equals(user.getId());
        
        return isNotBlocked && isNotExpired && hasPermission;
    }
}

🎭 드모르간의 법칙 (De Morgan's Law)

법칙 정의

NOT (A AND B) = (NOT A) OR (NOT B)
NOT (A OR B)  = (NOT A) AND (NOT B)

진리표로 증명

ABA AND BNOT(A AND B)NOT ANOT B(NOT A) OR (NOT B)
TTTFFFF
TFFTFTT
FTFTTFT
FFFTTTT

마지막 두 열이 동일함을 확인!

실무 활용

// 원본 조건: 코트를 입어야 하는 경우
boolean shouldWearCoat = isCold || isRaining;

// 드모르간의 법칙 적용
// "코트를 입지 않아도 되는 경우"로 변환
boolean shouldNotWearCoat = !isCold && !isRaining;
boolean shouldWearCoat2 = !shouldNotWearCoat;

// 실제 사용 예제
@Service
public class AccessControlService {
    
    // 긍정 논리 (Positive Logic)
    public boolean canAccess(User user, Resource resource) {
        return user.isAdmin() || resource.isPublic();
    }
    
    // 부정 논리 (Negative Logic) - 드모르간 적용
    public boolean cannotAccess(User user, Resource resource) {
        // NOT(admin OR public) = (NOT admin) AND (NOT public)
        return !user.isAdmin() && !resource.isPublic();
    }
    
    // 활용
    public void checkAccess(User user, Resource resource) {
        if (cannotAccess(user, resource)) {
            throw new AccessDeniedException("접근 권한이 없습니다");
        }
    }
}

조건문 단순화

// ❌ 복잡한 조건
if (!(user.isActive() && user.isVerified())) {
    return "사용자 계정에 문제가 있습니다";
}

// ✅ 드모르간 적용으로 단순화
if (!user.isActive() || !user.isVerified()) {
    return "사용자 계정에 문제가 있습니다";
}

// ❌ 중첩된 NOT
if (!(product.isOutOfStock() || product.isDiscontinued())) {
    return "구매 가능";
}

// ✅ 드모르간 적용
if (!product.isOutOfStock() && !product.isDiscontinued()) {
    return "구매 가능";
}

🔧 비트 연산자 (Bitwise Operators)

정수에 대한 비트 연산

int a = 5;   // 0101 (2진수)
int b = 3;   // 0011 (2진수)

int and = a & b;   // 0001 = 1 (AND)
int or  = a | b;   // 0111 = 7 (OR)
int xor = a ^ b;   // 0110 = 6 (XOR)
int not = ~a;      // 1010 = -6 (NOT, 2의 보수)

// 시프트 연산
int left  = a << 1;  // 1010 = 10 (왼쪽으로 1비트 = *2)
int right = a >> 1;  // 0010 = 2  (오른쪽으로 1비트 = /2)

실무 활용: 플래그(Flag) 관리

public class Permission {
    // 비트 플래그로 권한 표현
    public static final int READ   = 1;  // 0001
    public static final int WRITE  = 2;  // 0010
    public static final int DELETE = 4;  // 0100
    public static final int ADMIN  = 8;  // 1000
    
    private int permissions = 0;
    
    // 권한 추가 (OR)
    public void grant(int permission) {
        permissions |= permission;
    }
    
    // 권한 제거 (AND + NOT)
    public void revoke(int permission) {
        permissions &= ~permission;
    }
    
    // 권한 확인 (AND)
    public boolean hasPermission(int permission) {
        return (permissions & permission) == permission;
    }
    
    // 사용 예제
    public static void main(String[] args) {
        Permission perm = new Permission();
        
        perm.grant(READ);         // 읽기 권한 부여
        perm.grant(WRITE);        // 쓰기 권한 부여
        
        System.out.println(perm.hasPermission(READ));   // true
        System.out.println(perm.hasPermission(DELETE)); // false
        
        perm.revoke(WRITE);       // 쓰기 권한 제거
        System.out.println(perm.hasPermission(WRITE));  // false
    }
}

💼 Spring Security에서의 불리언 연산

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) {
        http.authorizeHttpRequests(auth -> auth
            // AND: 인증되고 AND ADMIN 역할
            .requestMatchers("/admin/**")
                .access((authentication, context) -> 
                    new AuthorizationDecision(
                        authentication.get().isAuthenticated() 
                        && hasRole(authentication.get(), "ADMIN")
                    ))
            
            // OR: PUBLIC이거나 OR 인증됨
            .requestMatchers("/api/**")
                .access((authentication, context) ->
                    new AuthorizationDecision(
                        isPublicEndpoint(context) 
                        || authentication.get().isAuthenticated()
                    ))
            
            .anyRequest().authenticated()
        );
        
        return http.build();
    }
}

📚 복합 조건문 Best Practices

1️⃣ 명확한 변수명 사용

// ❌ 나쁜 예
if (u.a && (u.b || !u.c)) { }

// ✅ 좋은 예
boolean isActive = user.isActive();
boolean isPremium = user.isPremium();
boolean isNotBlocked = !user.isBlocked();

if (isActive && (isPremium || isNotBlocked)) { }

2️⃣ Early Return으로 단순화

// ❌ 복잡한 중첩
public void processOrder(Order order) {
    if (order != null) {
        if (order.isPaid()) {
            if (order.hasStock()) {
                // 처리 로직
            }
        }
    }
}

// ✅ Early Return
public void processOrder(Order order) {
    if (order == null) {
        return;
    }
    if (!order.isPaid()) {
        return;
    }
    if (!order.hasStock()) {
        return;
    }
    
    // 처리 로직 (들여쓰기 최소화)
}

3️⃣ 메서드 추출로 가독성 향상

// ❌ 조건이 너무 길어서 읽기 어려움
if (user.getAge() >= 19 
    && user.isActive() 
    && !user.isBlocked() 
    && (user.isPremium() || user.hasEventCoupon())) {
    // ...
}

// ✅ 의미 있는 메서드로 분리
if (canAccessAdultContent(user)) {
    // ...
}

private boolean canAccessAdultContent(User user) {
    boolean isAdult = user.getAge() >= 19;
    boolean hasAccess = user.isActive() && !user.isBlocked();
    boolean hasPrivilege = user.isPremium() || user.hasEventCoupon();
    
    return isAdult && hasAccess && hasPrivilege;
}

🎯 핵심 요약

연산자기호의미Java 예제
NOT!반대!isActive
AND&&모두 참a && b
OR||하나라도 참a \|\| b
XOR^다를 때 참a ^ b

드모르간의 법칙

!(A && B) == !A || !B
!(A || B) == !A && !B

Short-circuit 평가

// && : 왼쪽이 false면 오른쪽 평가 안 함
if (user != null && user.isActive()) { }

// || : 왼쪽이 true면 오른쪽 평가 안 함
if (isAdmin() || hasPermission()) { }

💡 마무리

"불리언 연산은 프로그래밍의 기초이자 핵심"

Backend 개발자라면:

불리언 연산을 제대로 이해하면 복잡한 비즈니스 로직도 명확하게 표현할 수 있습니다! 💪

← 목록으로 돌아가기