RAID Array 구성요소

RAID Array는 여러 디스크 드라이브와 RAID를 구현하기 위한 하드웨어로 구성된다. RAID 어레이의 디스크를 그룹화해 RAID 집합 또는 RAID 그룹이라고 하는 논리적 어레이를 형성 할 수 있다.

RAID 기술

스트라이핑

데이터를 1개 이상의 드라이브에 저장해 병렬로 사용하는 기술. 여러 R/W 헤드가 동시에 일을 하기 때문에 1개의 디스크를 사용했을 때보다 좀 더 성능이 좋다.

RAID 집합의 각 디스크에서 정해진 개수의 연속적인 주소 디스크 블록을 스트립(strip)이라 한다. RAID 집합에 있는 모든 디스크의 같은 위치의 스트립을 스트라이프stripe이라고 한다.

스트립 크기(strip size) 혹은 스트라이프 깊이(stripe depth)는 스트립에 있는 블록의 갯수를 말한다. 스트라이프의 모든 스트립은 같은 개수의 블록을 갖는다.

스트라이프 너비(stripe width)는 스트라이프 안의 데이터 스트립 개수를 말한다.

parity나 미러링을 사용하지 않는 경우 스트라이프 RAID는 데이터 보호 기능이 없다.

미러링

같은 데이터를 2개 이상의 디스크에 저장에 데이터의 사본을 만드는 기술. 하나의 디스크가 고장나더라도 나머지 디스크를 사용해 데이터 요청을 처리 할 수 있다. 고장 난 디스크를 새 디스크로 교체하면 컨트롤러가 살아있는 디스크에서 데이터를 복사한다. 특정 시간의 데이터를 저장하는 백업과 달리 계속 변경사항을 감지한다.

데이터 중복을 발생시켜 비용이 많이 들어 데이터 손실을 감수할 수 없는 중요한 애플리케이션에서 사용된다.

읽기 요청은 여러 디스크에서 처리 할 수 있어 성능을 향상시킬 수 있다. 쓰기 요청은 여러 디스크에 써야 해 약간 성능이 감소 할 수 있다.

패리티

미러링 비용 없이 디스크 드라이브 고장으로부터 스트라핑된 데이터를 보호하기 위한 방법이다. 데이터의 패리티 비트를 저장할 디스크 드라이브가 추가된다. RAID 컨트롤러가 패리티를 계산한다. 패리티 정보는 전용 디스크 드라이브에 저장하거나 RAID 집합의 모든 드라이브에 분산 저장 할 수 있다.

미러링에 비해 비용이 저렴하지만, 데이터가 변경될 때 마다 패리티를 다시 계산해야 하므로 RAID Array의 성능에 영향을 준다.

728x90
반응형

'OS & Container > Storage' 카테고리의 다른 글

RAID와 디스크 성능  (0) 2022.03.16
RAID 레벨  (0) 2022.03.15
NCQ와 Flash Drive  (0) 2022.03.02
데이터 액세스와 DAS  (0) 2022.02.27
디스크 드라이브 성능  (0) 2022.02.27

NCQ와 Flash Drive

NCQ (Native Command Queuing)

수신된 I/O의 실행 순서를 정해 불필요한 헤드 움직임을 줄여 성능을 개선하려는 목적으로 사용되는 기술.

  • 탐색 시간 최적화 알고리즘: 헤드 움직임을 최적화 하는 방향으로 명령 실행
  • 액세스 시간 최적화 알고리즘: 탐색 시간과 회전 지연 시간으로 성능을 최적화

Flash Drive

플래시 드라이브의 일종인 SSD(solid state drive)는 반도체 기반 solid state memory를 사용해 데이터를 저장하고 추출한다.

기업용 플래시 드라이브(EFD, Enterprise Flash Drive)는 기존 디스크 드라이브와 비교해 30배 높은 데이터 처리량과 10분의 1정도의 응답속도를 제공하며, 전력 소모량도 적다.

flash drive component & architecture

기존 디스크 드라이브와 호환을 위해 같은 커넥터를 사용한다.

구성요소

  • 컨트롤러 - 드라이브 동작 관리.
  • I/O 인터페이스 - 전력, 데이터 액세스 제공.
  • Mass Storage - 비휘발성 NAND 메모리 칩 배열. 데이터 저장.
  • Cache - data transaction의 임시 공간 혹은 버퍼.

채널

플래시 드라이브는 컨트롤러와 플래시 메모리 칩 사이에 다중 병렬 I/O 채널을 사용한다. 메모리 칩과 채널을 많이 사용할 수록 드라이브 내부 대역폭이 증가하여 성능이 좋아진다. 보통 8~24 채널을 사용한다.

메모리 칩

논리적 블록과 페이지 단위로 구성된다.

  • page

플래시 드라이브에서 읽거나 쓰는 가장 작은 object이다. 표준 크기는 없지만 일반적으로 4KB, 8KB, 16KB를 사용한다. LBA(logical block address)를 사용하는 디스크 드라이브와 같은 방식을 제공하기 위해 여러 데이터 블록 위에 연속적으로 걸쳐 있게 된다. 8 x 512B = 4KB 이므로, 4KB page는 연속된 주소의 8개의 데이터 블록을 가진다.

  • block

전통적인 하드 디스크 드라이브의 섹터에 있는 블록과 다른 개념이다. 여러 page를 그룹으로 묶어 block을 만든다. 한 block 당 32, 64, 혹은 128개의 page를 갖는다.

주요 특징

NAND Flash Memory

랜덤 데이터 액세스에 유리하다. 잘못된 블록이 탐지되면 ECC(Error Correcting Code)를 사용해서 데이터 무결성을 유지한다.

SLC(Single Level Cell)

MLC(multi-level cell)은 셀당 여러 비트를 저장할 수 있고, single-level cell은 한 비트만 저장할 수 있다. 하지만 SLC가 성능과 지속성 면에서 우수하다. 읽기 속도는 SLC가 MLC보다 두배 정도 빠르고, 쓰기 속도는 4배 정도 빠르다.

쓰기 레벨링

플래시 드라이브의 수명을 최대화 하기 위해 각 메모리 셀을 균일하게 사용하는 것이 좋다. 자주 업데이트 되는 데이터를 각각 다른 위치해 기록해 같은 셀을 계속 사용하는 것을 방지하는 것이 좋다.

728x90
반응형

'OS & Container > Storage' 카테고리의 다른 글

RAID 레벨  (0) 2022.03.15
RAID Array 구성요소, 기술  (0) 2022.03.08
데이터 액세스와 DAS  (0) 2022.02.27
디스크 드라이브 성능  (0) 2022.02.27
논리적 볼륨 매니저(LVM, Logical Volume Manager)  (0) 2022.02.26

호스트에서 데이터 액세스

스토리지 디바이스는 호스트 내부에 있거나 외부에 있을 수 있지만, 어떠한 경우든 호스트 컨트롤라 카드가 IDE/ATA나 SCSI, 파이버 채널같은 정의된 프로토콜을 이용해 스토리지에 접근한다. 파이버 채널과 iSCSI는 외부 스토리지 디바이스의 데이터에 접근하는데 사용된다. 외부 스토리지 디바이스는 호스트에 직접 연결하거나 스토리지 네트워크를 사용해 연결할 수 있다. 호스트에 직접 연결한 스토리지를 DAS(Direct Attached Storage)라고 한다.

일반적으로 애플리케이션이 파일 시스템의 데이터를 요청하면, 파일 시스템은 파일 속성을 논리적 블록 주소(LBA)로 변환해 스토리지 디바이스에 요청한다. 스토리지 디바이스는 LBA를 실린더-헤드-섹터(CHS) 주소로 변환해 데이터를 가져온다.

블록 레벨 액세스에서는 호스트에 파일 시스템을 생성하고 네트워크를 통해 블록 레벨로 데이터에 접근한다. 이 경우 raw 디스크나 논리적 볼륨이 파일 시스템을 만들기 위해 호스트에 할당된다.

파일 레벨 액세스에서 파일 시스템은 별도의 파일 서버나 스토리지 사이드에 생성되고, 파일 레벨 요청이 네트워크를 통해 전달된다. 파일 레벨에서 데이터를 접근하므로 블록 레벨 접근보다 오버헤드가 크다.

객체 레벨 액세스에서는 고유 식별자를 가진 객체 단위로 데이터에 접근한다.

직접 연결 스토리지(DAS)

DAS는 스토리지가 직접 호스트에 연결된 구성이다. 호스트 관점에서의 스토리지 위치에 따라 내부와 외부로 나뉜다.

내부 DAS

스토리지 디바이스가 직렬 또는 병렬 버스로 호스트에 연결된다. 물리적 버스는 길이에 제한이 있으며, 길이가 짧을수록 높은 연결 속도가 나온다. 대부분의 내부 버스는 제한된 개수의 디바이스만을 지원하고, 공간을 차지한다는 단점이 있다.

외부 DAS

호스트를 외부 스토리지 디바이스에 직접 연결하고, 데이터는 블록 레벨로 접근한다. 통신 프로토콜은 주로 SCSI나 FC를 사용한다. 호스트 외부에서 디바이스를 중앙 집중형식으로 관리할 수 있는 장점이 있다.

DAS의 장점과 한계

DAS는 네트워킹 구성보다 초기 투자 비용이 낮고, 쉽고 빠르다는 장점이 있다. 하지만 확장성이 좋지 않다는 단점이 있으며, 프론트엔드 포트를 공유하기 때문에 리소스를 최적으로 사용하기 어렵다. 사용하지 않는 리소스를 쉽게 재할당 할 수 없으므로 스토리지 풀마다 사용량에 차이가 발생한다.

728x90
반응형

'OS & Container > Storage' 카테고리의 다른 글

RAID 레벨  (0) 2022.03.15
RAID Array 구성요소, 기술  (0) 2022.03.08
NCQ와 Flash Drive  (0) 2022.03.02
디스크 드라이브 성능  (0) 2022.02.27
논리적 볼륨 매니저(LVM, Logical Volume Manager)  (0) 2022.02.26

디스크 드라이브 성능

디스크 서비스 시간

디스크 서비스 시간(disk service time): I/O 요청을 완료하는 데 걸리는 시간. 탐색 시간(seek time)과 회전 지연 시간(rotational latency), 데이터 전송 속도(data transfer rate)에 영향을 받는다.

탐색 시간

탐색 시간(seek time)은 엑세스 시간(access time)이라고도 하며, R/W 헤드를 지름 방향(접선과 수직인 방향)으로 움직여 위치시키는 것을 말한다.

탐색 시간 스펙으로 다음과 같이 있다.

  • 풀 스트로크(full stroke): R/W head를 0번에서 마지막으로 움직이는데 걸리는 시간
  • 평균: 랜덤 트랙으로 R/W head를 움직이는데 걸리는 시간. 보통 풀 스트로크의 1/3이다.
  • 트랙에서 트랙: 인접한 트랙으로 R/W 헤드를 이동하는데 걸리는 시간

각 스펙은 밀리초 단위로 측정하며, 제작사에서 명시한다. 최신 디스크의 경우 평균은 3~15 밀리초이다.

short-stroking

적은 실린더를 사용하여 용량을 줄이고 탐색 시간을 줄이는 방법.

회전 지연 시간

플래터가 회전하여 R/W헤드 아래에 요청한 데이터가 위치하기까지의 시간. 스핀들의 회전 속도에 영향을 받으며 밀리초 단위로 측정된다. 평균 지연 시간은 한 바퀴를 회전하는 시간의 1/2이다.

15,000 rpm(250rps) 드라이브의 평균 회전 시간은 1 / 250 / 2 = 2 밀리초이다.

데이터 전송 속도

단위 시간동안 드라이브가 HBA(Host Bus Adapter)로 전송할 수 있는 데이터의 양

읽기 연산에서는 플래터 -> R/W헤드 -> 드라이브 내부 버퍼 -> 드라이브 인터페이스 -> HBA로 이동한다. 쓰기 연산에서는 HBA -> 드라이브 인터페이스 -> 드라이브 내부 버퍼 -> R/W헤드 -> 플래터로 이동한다.

R/W연산에서 데이터 전송 속도는 드라이브 내부와 외부 전송 속도로 측정된다. 내부 전송 속도는 플래터에서 R/W헤드를 거처 디스크 내부 버퍼(캐시)로 이동하는 속도다. 내부 전송 속도는 탐색 시간과 회전 지연 시간의 영향을 받는다. 외부 전송 속도는 인터페이스에서 HBA로 이동하는 속도다. 보통 ATA의 133MB/s로 볼 수 있다.

디스크 I/O 컨트롤러 사용률

디스크 I/O 컨트롤러의 사용률은 I/O 반응 속도에 영향을 준다.

컨트롤러 평균 응답 시간 = 서비스 시간 / (1 - 컨트롤러 사용률)

컨트롤러 사용률이 100%가 되면, 컨트롤러의 응답 시간은 무한대에 가까워진다. 컨트롤러의 부하가 증가하여 70%가 넘으면 급격히 응답시간이 늘어난다.

728x90
반응형

'OS & Container > Storage' 카테고리의 다른 글

RAID 레벨  (0) 2022.03.15
RAID Array 구성요소, 기술  (0) 2022.03.08
NCQ와 Flash Drive  (0) 2022.03.02
데이터 액세스와 DAS  (0) 2022.02.27
논리적 볼륨 매니저(LVM, Logical Volume Manager)  (0) 2022.02.26

논리적 볼륨 매니저(LVM, Logical VOlume Manager)

파일 시스템 용량을 동적으로 확장하고, 스토리지를 효율적으로 관리하는 LVM은 시스템에서 동작하는 소프트웨어로, 논리적, 물리적 스토리지를 관리한다.

LVM은 파일 시스템과 물리 디스크 사이의 레이어(Layer)다. 디스크를 좀 더 작은 가상 볼륨으로 파티셔닝(partitioning) 하거나 작은 디스크를 합쳐 큰 가상 볼륨을 컨캐터네이션(concatenation) 할 수 있다.

파티셔닝 partitioning

큰 디스크 드라이브를 여러개의 논리적 볼륨(LV, Logical Volume)으로 나눌 수 있다. 디스크 드라이브를 호스트에 처음 설치 할 때, 여러 실린더를 그룹화해 파티션을 만든다. 호스트 파일 시스템은 파티셔닝과 디스크의 구조를 모르는 상태에서 논리적 볼륨에 접근한다.

컨캐터네이션 concatenation

여러 물리 드라이브를 그룹화해 하나의 논리 볼륨으로 만드는 것이다. LVM이 최적화된 스토리지 액세스를 제공하며 리소스 관리를 한다. 사용자는 물리적 디스크 개수나 데이터의 위치를 몰라도 된다.

LVM 구성

물리적 볼륨 PV, physical volume

LVM에서 호스트 시스템에 연결된 각 물리 디스크를 물리적 볼륨이라고 한다. LVM은 물리적 볼륨이 제공하는 물리적 스토리지를 OS나 애플리케이션이 사용하는 논리적 뷰로 변환한다.

볼륨 그룹 volume group

1개 이상의 물리 볼륨을 그룹화해 볼륨 그룹을 만든다. 각 볼륨을 초기화 할 때, LVM이 사용할 고유 물리적 볼륨 아이디(PVID, physical volume identifier)를 할당한다.

볼륨 그룹에 동적으로 물리적 볼륨을 추가하거나 삭제할 수 있지만, 하나의 물리적 볼륨을 여러 볼륨 그룹간에 공유할 수는 없다. 하나의 물리적 볼륨을 나눠 여러 볼륨 그룹이 사용할 수도 없다.

각 볼륨 그룹을 만들 때는 물리적 익스텐트(physical extent) 라고 하는 같은 크기의 데이터 블록 집합으로 파티셔닝한다.

논리적 볼륨 LV, logical volume

볼륨 그룹에서 만들어진다. 논리적 볼륨은 디스크 파티션으로 생각할 수 있으며 볼륨 그룹 자체는 디스크로 볼 수 있다.

728x90
반응형

'OS & Container > Storage' 카테고리의 다른 글

RAID 레벨  (0) 2022.03.15
RAID Array 구성요소, 기술  (0) 2022.03.08
NCQ와 Flash Drive  (0) 2022.03.02
데이터 액세스와 DAS  (0) 2022.02.27
디스크 드라이브 성능  (0) 2022.02.27

문제설명

https://leetcode.com/problems/count-complete-tree-nodes/

 

Count Complete Tree Nodes - LeetCode

Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.

leetcode.com

Given the root of a complete binary tree, return the number of the nodes in the tree.

According to Wikipedia, every level, except possibly the last, is completely filled in a complete binary tree, and all nodes in the last level are as far left as possible. It can have between 1 and 2h nodes inclusive at the last level h.

Design an algorithm that runs in less than O(n) time complexity.

 

complete binary tree의 노드 수를 반환하세요.

문제에서 complete binary tree란, 마지막 level을 제외하고 모든 노드가 채워진 binary tree를 의미합니다. 그리고 마지막 level은 가능한 왼쪽에 있습니다.

 

아이디어

1. 마지막 노드를 찾아서 1 + 2^h + 마지막 level의 노드 수를 계산한다.

2. 모든 노드를 방문해서 수를 센다.

2번이 간단하여 2번으로 해결했습니다.

 

Solution

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    int nodeCnt = 0;
    private int searchTree(TreeNode treeNode){
        nodeCnt++;
        if(treeNode.left != null){
            nodeCnt = searchTree(treeNode.left);
        } else {
            return nodeCnt;
        }
        if(treeNode.right != null){
            nodeCnt = searchTree(treeNode.right);
        }
        return nodeCnt;
    }

    public int countNodes(TreeNode root) {
        if(root == null) return 0;
        return searchTree(root);
    }
}

Result

 

728x90
반응형

문제설명

https://leetcode.com/problems/sort-characters-by-frequency/

 

Sort Characters By Frequency - LeetCode

Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.

leetcode.com

Given a string s, sort it in decreasing order based on the frequency of the characters. The frequency of a character is the number of times it appears in the string.

Return the sorted string. If there are multiple answers, return any of them.

 

string s에 대해, character의 빈도(출현 수)에 따라 내림차순으로 정렬하세요. 빈도(출현 수)는 string에 나타난 횟수입니다. 다수의 정답이 있으면 그 중 아무거나 return하면 됩니다.

 

아이디어

문자의 빈도를 알기 위해 String을 한 글자씩 모두 탐색하였으며 Collection을 사용해 정렬했습니다.

https://81shinez.tistory.com/10 포스팅을 참고했습니다.

 

Solution

class Solution {
    private class Pair<L, R>{
        L left;
        R right;
        private Pair(L left, R right){
            this.left = left;
            this.right = right;
        }
    }

    public String frequencySort(String s) {
        char[] charArray = s.toCharArray();

        HashMap<Character, Integer> hashMap = new HashMap<>();

        for(char character : charArray){
            if(hashMap.containsKey(character)){
                hashMap.put(character, hashMap.get(character) + 1);
            } else {
                hashMap.put(character, 1);
            }
        }

        ArrayList<Pair<Character, Integer>> pairList = new ArrayList<>();

        for(char key : hashMap.keySet()){
            pairList.add(new Pair<>(key, hashMap.get(key)));
        }

        Collections.sort(pairList, (o1, o2) -> o2.right.compareTo(o1.right));

        StringBuffer sb = new StringBuffer();

        for(Pair<Character, Integer> pair : pairList){
            for(int i = 0; i < pair.right; i++){
                sb.append(pair.left);
            }
        }

        return sb.toString();
    }
}

Result

728x90
반응형

단항 연산자

증감 연산자 (++, --)

피연산자에 저장된 값을 1 증가 또는 감소시킨다.

정수와 실수는 가능하지만, 상수는 불가능하다.

타입 설명 사용 예시
전위형 (prefix) 값이 참조되기 전에 증감시킨다. j = ++i;
후위형 (postfix) 값이 참조된 후에 증감시킨다. j = i++;

부호 연산자 (+, -)

부호 연산자 '-'는 피연산자의 부호를 반대로 변경한 결과를 반환한다.

boolean형과 char형을 제외한 기본형에만 사용 할 수 있다.

산술 연산자

산술 연산자에는 사칙연산자(+, -, *, /)와 나머지 연산자(%)가 있다.

사칙연산자 (+, _, *, /)

덧셈과 뺄셈보다 곱셈과 나눗셈의 우선순위가 높다.

나누기 연산

피연산자가 정수형인 경우, 나누는 수로 0을 사용 할 수 없다.

나누기 연산자의 피연산자가 모두 int 타입인 경우, 연산결과 역시 int 타입이 되며, 소수점 이하는 반올림 되지 않고 버려진다.

피연산자 중 어느 한쪽을 실수형으로 형변환 하게 되면 나머지 한 쪽도 실수형으로 자동 형변환이 되어 실수형의 값을 결과로 얻을 수 있다.

피연산자가 정수인 경우, 나누는 수로 0을 사용 할 수 없다. 하지만, 피연산자 중 한쪽이라도 실수형으로 바꾸게 되면, 결과는 Infinity가 된다.

자동 형변환

int형보다 작은 크기의 type으로 + 연산을 수행하게 되면 자료형을 자동으로 int로 변환 후 연산을 수행한다.

따라서 byte형 + byte형 연산의 수행 결과는 int형이 된다. byte 타입의 변수에 byte형 + byte형 의 연산결과를 저장하려 한다면, 에러가 발생한다.

또한, byte형 + byte형 연산의 수행 결과가 byte형의 표현 범위를 넘어서는 경우, 데이터 손실이 발생하게 된다.

마찬가지로 int형 * int형 연산 수행 결과는 int형이므로 int형의 표현 범위를 넘어서는 경우 long으로 형변환이 되었다 하더라도 데이터 손실이 발생한다.

문자형(char)의 연산

문자(char)형 변수는 부호없는 정수인 유니코드로 저장되므로, 연산이 가능하다.

char c2 = c1 + 1; // '+'연산의 결과는 int형이므로 char형 변수에 담을 수 없다.
char c2 = 'a' + 1; // 변수가 아닌 리터럴 간의 연산은 컴파일시 컴파일러가 미리 계산하여 오류가 없다.

리터럴 간 연산은 컴파일시 컴파일러가 미리 알 수 있는 값이기 때문에 컴파일 후 변환되게 된다.

ex. 60 * 60 → 360, 'a' + 1 → 'b'

하지만 변수가 포함된 연산은 컴파일시 계산 할 수 없으므로 런타임에 형변환이 발생하여 오류가 발생하게 된다.

런타임에 연산이 되지 않음으로 360을 60 * 60과 같이 표기하였다 하여 런타임 성능에 영향을 주지도 않는다.

나머지 연산자 (%)

왼쪽 피연산자를 오른쪽 피연산자로 나누고 난 나머지.

오른쪽 피연산자로 0을 사용 할 수 없다.

나누는 수로 음수도 허용하지만, 부호는 무시된다. 결과는 음수의 절대값으로 나눈 나머지와 결과가 같다.

실행결과는 왼쪽 피연산자의 부호를 따른다.

비교 연산자

두 피연산자를 비교하는 데 사용된다. 연산결과는 오직 true와 false 둘 중 하나.

비교하는 피연산자의 타입이 서로 다른 경우, 자동 형변환이 발생한다.

대소비교 연산자 (<, >, <=, >=)

두 피연산자의 값의 크기를 비교하는 연산자.

기본형 변수 중에서는 boolean을 제외한 모든 자료형에 사용 할 수 있다.

참조형 변수에는 사용 할 수 없다.

등가비교 연산자 (==, !=)

두 피연산자가 같은지, 다른지 비교하는 연산자.

모든 변수형에 사용 할 수 있다. 기본형의 경우 변수에 저장된 값을 비교 할 수 있고, 참조형의 경우 객체의 주소값을 비교한다.

서로 다른 기본형에 사용될 경우, 형변환이 수행된다.

ex.

10.0 == 10.0f true
0.1==0.1f false // 0.1f는 0.10000000149011612, 0.1은 0.10000000000000001으로 저장된다.

double과 float타입을 비교하기 위해서는 double 타입을 float으로 형변환 한 후 비교해야 한다.

문자열의 비교

문자열은 equals() 메소드로 비교한다. '==' 연산자로 비교할때는 같은 객체인지 비교하게 된다.

String str1 = "abc";
String str2 = new String("abc");
String str3 = "abc";
System.out.printf("str1 == str2 ? %b%n", str1 == str2); // false
System.out.printf("str1 == str3 ? %b%n", str1 == str3); // true
System.out.printf("str1.equals(\"abc\") ? %b%n", str1.equals("abc")); // true
System.out.printf("str2.equals(\"abc\") ? %b%n", str2.equals("abc")); // true
System.out.printf("str2.equals(\"ABC\") ? %b%n", str2.equals("ABC")); // false
System.out.printf("str2.equalsIgnoreCase(\"ABC\") ? %b%n", str2.equalsIgnoreCase("abc")); // true

대소문자를 구분하고 싶지 않다면 equalsIgnoreCase() 메서드를 사용한다.

논리 연산자

둘 이상의 조건을 그리고(AND)나 또는(OR)로 연결하여 하나의 식으로 표현 할 때 사용한다.

논리 연산자 (&&, ||, !)

'&&': 그리고(AND)

'||': 또는(OR)

1) x는 10보다 크고 20보다 작다.

x > 10 && x < 20

2) i는 2의 배수 또는 3의 배수다.

i % 2 == 0 || i % 3 == 0

3) i는 2의 배수 또는 3의 배수지만 6의 배수는 아니다.

(i % 2 == 0 || i % 3 == 0) && (i % 6 != 0) // '&&'연산은 '||' 연산보다 우선순위가 높다.

4) 문자 ch는 숫자 '0'~'9'이다.

'0' <= ch && ch <= '9' // 유니코드에서 문자 '0'(48)~'9'(57)가 연속적이므로 가능하다.

5) 문자 ch는 대문자 알파벳 또는 소문자 알파벳이다.

('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') // 유니코드에서 알파벳이 연속적으로 배열되므로 가능하다.

효율적인 연산

연산 OR(||)의 경우, 피연산자 중 어느 한쪽만 true여도 연산결과가 true가 되므로 좌측 피연산자가 true인 경우 우측 피연산자의 값은 평가하지 않는다.

AND(&&)연산도 마찬가지고 좌측 피연산자가 false인 경우 우측 피연산자의 값을 평가하지 않는다.

그래서 같은 조건식이라도 피연산자의 위치에 따라서 연산속도가 달라질 수 있다.

논리 부정 연산자 (!)

피연산자가 true이면 false를, false이면 true를 반환한다.

// ch는 소문자가 아니다.
(ch < 'a' || ch > 'z')
!('a' <= ch && ch <= 'z') // 이해하기 쉽다.

비트 연산자

비트 연산자 (& | ^ ~ << >>)

비트단위의 논리 연산. 피연산자를 이진수로 표현했을 때의 연산. 피연산자로 실수는 허용하지 않는다. 정수(문자 포함)만 허용.

|(OR) 피연산자 중 한쪽의 값이 1이면, 1을 결과로 얻는다. 그 외에는 0을 얻는다.

&(AND) 피연산자 양 쪽이 모두 1이어야만 1을 결과로 얻는다. 그 외에는 0을 얻는다.

^(XOR) 피연산자의 값이 서로 다를때만 1을 결과로 얻는다. 같을 때는 0을 얻는다.

'|'연산자는 특정 비트의 값을 변경할 때, '&'연산자는 특정 비트의 값을 뽑아낼 때 사용한다.

'^'연산자는 간단한 암호화에 사용된다.

비트 연산에도 피연산자의 타입을 일치시키는 '산술 변환'이 일어날 수 있다.

비트 전환 연산자 (~)

피연산자를 2진수로 표현했을 때, 0은 1로, 1은 0으로 바꾼다.

피연산자의 '1의 보수'를 얻을 수 있다. 1의 보수에 1을 더하면 음수가 된다.

비트 전환 연산자의 피연산자의 타입이 int보다 작으면 int로 자동 형변환이 된 값을 얻는다.

쉬프트 연산자 (<< >>)

피연산자를 2진수로 표현했을 때 각 자리를 오른쪽 또는 왼쪽으로 이동한다.

저장범위를 벗어난 값들은 버려지고, 빈자리는 0으로 채워진다.

'>>'연산자는 부호있는 정수는 부호를 유지하기 위해 왼쪽 피연산자가 음수인경우 빈자리를 1로 채운다.

쉬프트 연산자의 좌측 피연산자는 산술변환이 적용되어 int보다 작은 타입은 int타입으로 자동 변환되고 연산결과 역시 int타입이 된다. 우측 피연산자의 경우 산술변환이 적용되지 않는다.

2진수 n자리를 왼쪽으로 이동하면 피연산자에 2ⁿ을 곱한 결과를, 오른쪽으로 이동하면 2ⁿ을 나눈 결과를 얻는다. 2진수이기 때문.

'x << n' 또는 'x >> n'에서 n의 값이 자료형의 bit수 보다 크면, 자료형의 bit수로 나눈 나머지만큼만 이동한다.

ex) '8 >> 32': 아무일도 하지 않음. '8>>34' == '8>>2'

n은 정수만 가능하며, 음수인경우 부호없는 정수로 변환된다.

2의 배수로 곱하거나 나누는 연산에서 '*', '/' 연산보다 속도가 빠르지만 가독성이 떨어지기 때문에 속도에 민감할 경우에 사용된다.

그 외 연산자

조건 연산자 (? :)

조건연산자는 조건식, 식1, 식2를 필요로 하는 삼항연산자이며 삼항 연산자는 하나뿐이다.

result = (조건식 ? 식1 : 식2)

if(조건식){
    result = 식1
} else{
    result = 식2
}

조건식이 true일 때, 연산 결과는 식1이 되며 조건식이 false일 때, 연산 결과는 식2가 된다.

조건 연산자의 식1과 식2의 피연산자의 타입이 다른 경우, 산술변환이 발생한다.

대입연산자

대입연산자 (=)

변수와 같은 저장공간에 값 또는 수식의 연산결과를 저장한다.

가장 낮은 우선순위를 갖고 있다.

연산 진행방향이 오른쪽에서 왼쪽이다.

리터럴이나 상수같이 값을 저장 할 수없으면 왼쪽 피연산자가 될 수 없다.

복합 대입연산자 (op=)

i += 3; 
i = i +3;

i *= 10 + j;
i = i * (10 + j);
728x90
반응형

'Language > JAVA' 카테고리의 다른 글

연산자 (1)  (0) 2021.07.11
형변환  (0) 2021.06.24
기본형  (0) 2021.06.24
변수  (0) 2021.06.21
JAVA란?  (0) 2021.06.17

+ Recent posts