반응형

 

문자열을 특정 구분자로 분리할 수 있는 StringTokenizer와 Splite을 사용하던 중
구체적인 차이점이 무엇인지 궁금하여 조사하게 되었다.
메모리에서 장점을 가진다고 하지만 정확히 어떤구조로 작용하는지 알아보자

 

StringTokenizer

StringTokenizer 클래스 내부를 살펴보면 다음과 같은 내용을 볼 수 있습니다.

    public StringTokenizer(String str, String delim, boolean returnDelims) {
        currentPosition = 0;
        newPosition = -1;
        delimsChanged = false;
        this.str = str;
        maxPosition = str.length();
        delimiters = delim;
        retDelims = returnDelims;
        setMaxDelimCodePoint();
    }
  • 생성자 3가지
생성자 설명
StringTokenizer(String str) 문자열(str)을 기본 구분자를 제외하고 문자열을 반환한다.
기본 구분자 : 공백( ), 탭(\t), 줄바꿈(\n), 캐리지 리턴(\r), 폼 피드(\f)
StringTokenizer(String str, String delim) 문자열(str)을 구분자(delim)를 제외하고 문자열을 반환한다.
StringTokenizer(String str, String delim, boolean returnDelims) 문자열(str)을 구분자(delim)을 제외할 것 인지(returnDelims)에 따라 true면 반환한다.
  • 주요 메서드
메서드 설명
hasMoreTokens() 더 읽을 토큰이 있는지 확인, true/flase 반환
nextToken() 다음 토큰 반환 및 포인터 이동
nextToken(String delim) 구분자를 새로 지정하여 다음 토큰 반환
countTokens() 남아있는 토큰 개수를 반환
hasMoreElements() hasMoreToken()와 동일
nextElement() nextToken()과 동일, 반환값이 Object 타입

 


1. StringTokenizer(String str)

public StringTokenizer(String str) {
        this(str, " \t\n\r\f", false);
}


StringTokenizer stringtokenizer = new StringTokenizer("Hello World\tJAVA");
	while (tokenizer.hasMoreTokens()) {
    		System.out.println(tokenizer.nextToken();
    	}
Hello
world
JAVA
  • 기본 구분자 : 공백( ),(\t), 줄바꿈(\n), 캐리지 리턴(\r), 폼 피드(\f)
  • returnDelims는 기본적으로 false

2. StringTokenizer(String str, String delim)

  public StringTokenizer(String str, String delim) {
        this(str, delim, false);
 }

StringTokenizer stringTokenizer = new StringTokenizer("A,B|C", ",|");

while (stringTokenizer.hasMoreTokens()) {
	System.out.println(stringTokenizer.nextToken());
}

 

A
,
B
|
C

3. StringTokenizer(String str, String delim, boolean returnDelims)

public StringTokenizer(String str, String delim, boolean returnDelims) {
        currentPosition = 0;
        newPosition = -1;
        delimsChanged = false;
        this.str = str;
        maxPosition = str.length();
        delimiters = delim;
        retDelims = returnDelims;
        setMaxDelimCodePoint();
}

StringTokenizer stringTokenizer = new StringTokenizer("A,B|C", ",|", true);

while (stringTokenizer.hasMoreTokens()) {
    System.out.println(stringTokenizer.nextToken());
}

 

A
,
B
| C

 

다음과 같은 생성자를 가지고 있는데 코드를 살펴보면 단 하나의 구분자로만 사용되는 것으로 보인다.

즉, 구분자 문자가 개별로 작용하여 하지만 String 클래스의 split은 ,| 를 하나의 구분자로 사용할 수 있다.

 


Split

split 메드는 문자열을 특정 정규식(regex)을 기준으로 나눈다.

다음은 String 클래스에 있는 split 메서드이다.

    public String[] split(String regex) {
        return split(regex, 0);
    }
    
    
    public String[] split(String regex, int limit) {
        char ch = 0;
        if (((regex.length() == 1 &&
             ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||
             (regex.length() == 2 &&
              regex.charAt(0) == '\\' &&
              (((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 &&
              ((ch-'a')|('z'-ch)) < 0 &&
              ((ch-'A')|('Z'-ch)) < 0)) &&
            (ch < Character.MIN_HIGH_SURROGATE ||
             ch > Character.MAX_LOW_SURROGATE))
        {
            int off = 0;
            int next = 0;
            boolean limited = limit > 0;
            ArrayList<String> list = new ArrayList<>();
            while ((next = indexOf(ch, off)) != -1) {
                if (!limited || list.size() < limit - 1) {
                    list.add(substring(off, next));
                    off = next + 1;
                } else {    // last one
                    //assert (list.size() == limit - 1);
                    int last = length();
                    list.add(substring(off, last));
                    off = last;
                    break;
                }
            }
            // If no match was found, return this
            if (off == 0)
                return new String[]{this};

            // Add remaining segment
            if (!limited || list.size() < limit)
                list.add(substring(off, length()));

            // Construct result
            int resultSize = list.size();
            if (limit == 0) {
                while (resultSize > 0 && list.get(resultSize - 1).isEmpty()) {
                    resultSize--;
                }
            }
            String[] result = new String[resultSize];
            return list.subList(0, resultSize).toArray(result);
        }
        return Pattern.compile(regex).split(this, limit);
    }

 

위를 보면 limit을 통해 배열의 길이를 조절할 수 있다.

로직을 보기 전까지는 사실 어떻게 작동하는 지 헷갈릴 수 있다.

A, B, C와 2를 대입하여 사용한다면 A와 B인지 A와 B,C 인지...

그것을 보여주는 코드예시이다.

public class SplitExample {
    public static void main(String[] args) {
        String str = "apple,banana,cherry,orange,grape";

        String[] result = str.split(",", 3);

        for (String token : result) {
            System.out.println(token);
        }
    }
}

 

apple
banana
cherry,orange,grape

 

split은 구분자를 찾아 subString으로 분리반복하고 결과 배열을 생성하는 것을 볼 수 있다.

그리고 빈 문자열, 구분자 사이에 문자가 없는 경우

,,

StringTokenizer는 이를 무시하지만 split은 빈 문자열로 간주한다.

StringTokenizer와 split의 차이는 다음과 같다.

 

특징 String.split() StringTokenizer
구분자 정규식 지원 ( 복잡한 패턴 가능 ) 단순한 문자 집합( 정규식 미지원 ) 
결과 형태 String [] 배열  각 토큰으로 개별 반
구분자 반환 지원하지 않음 returenDelims 설정을 통한 반환 옵션 제공 
동작 방식 정규식으로 문자열 분리
빠른 최적화 코드 포함
빈 문자열도 인식
구분자 위치계산
내부 위치 포인터로 하나씩 반환
빈 문자열은 인식하지 않음
유연성 졍규식으로 높은 유연성 제한적
사용성 결과를 한 번에 반환 각 토큰으로 분리하여 하나씩 처리

 

둘 중 누가 성능이 좋은가?

정규식이나 복잡한 패턴이 아닌 두 메서드 모두 가능한 구분자로 진행하였을 때, 어느 때 어떤 메서드가 성능이 좋은지 4가지 기준으로 분류했다. 4가지 기준은 다음과 같다

  • 유니코드를 사용한 경우
  • 긴 문자열과 한 가지 구분자를 사용한 경우
  • 짧은 문자열과 한 가지 구분자를 사용한 경우
  • 짧은 문자열과 여러 구분자를 동시에 사용한 경우

StringTokenizer 한 가지 구분자로 이루어진 문자열을 사용한 경우는 문자열이 길든 짧든 항상 빨랐다.

split() 여러 구분자 유니코드를 사용한 경우에 빨랐다. 


StringTokenizer

StringTokenizer 클래스의 내부를 살펴보면 구분자에 따라 성능이 좌우된다.

 

StringTokenizer 클래스 scanToken 메서드

    private int scanToken(int startPos) {
        int position = startPos;
        while (position < maxPosition) {
            if (!hasSurrogates) {
                char c = str.charAt(position);
                if ((c <= maxDelimCodePoint) && (delimiters.indexOf(c) >= 0))
                    break;
                position++;
            } else {
                int c = str.codePointAt(position);
                if ((c <= maxDelimCodePoint) && isDelimiter(c))
                    break;
                position += Character.charCount(c);
            }
        }
        if (retDelims && (startPos == position)) {
            if (!hasSurrogates) {
                char c = str.charAt(position);
                if ((c <= maxDelimCodePoint) && (delimiters.indexOf(c) >= 0))
                    position++;
            } else {
                int c = str.codePointAt(position);
                if ((c <= maxDelimCodePoint) && isDelimiter(c))
                    position += Character.charCount(c);
            }
        }
        return position;
    }

( hasSurrogates는 유니코드인지 확인하는 것이고 indexOf와 isDelimiter 메서드는 같은 로직이다. )

 

여기서 성능에 영향을 끼치는 것은 indexOf() 메서드 이다. 이는 순차탐색으로 최악의 경우 O(|delimiter|)의 시간이 걸린다.

모든 문자에 이 코드를 작동된다고 생각한다면 성능은 구분자의 개 수에 따라 달라진다. 다음 예시를 보자

 

@ , < -

아스키 코드 값

@ : 64

, : 44

< : 60

{ : 123

 

@ , < {

@ 찾는 경우

 

 

@ , < {

< 찾는 경우

 

 

@ , < {

} ( 없는 구분자 ) 를 찾는 경우

}  는 아스키 코드 값이 125이기 때문에 maxDelimCodePoint ( 123 ) 보다 크다.

때문에 탐색되지 않는다.

 

 

@ , < {

구분자가 아닌 문자 A인 경우

A( 65 ) < maxDelimCodePoint (125)

때문에 모두 탐색해본다.

 


 

이처럼 단순 문자일 경우도 모두 탐색한다. 그래서 구분자가 많으면 많을수록 괴랄하게 탐색시간이 늘어난다.

유니코드라면 두 개의 char 를 쓰기 때문에 더욱 더 심각해진다.

split()

  • split 메서드는 정규식을 사용하여 구분자를 기준으로 문자열을 나눈다.
  • Pattern 클래스(정규 표현식 엔진)를 활용해 문장열을 순회, 구분자를 매칭한다.
  • 그 구분자 자리를 기억하고 문자열을 자른다.

다음과 같이 표현할 수 있다.

String input = "apple,banana,grape";
String[] result = input.split(",");

 

매칭 과정

  1. 구분자 ,를 문자열에서 찾기 시작.
    • 첫 번째 ,의 위치: 5.
    • 두 번째 ,의 위치: 12.
  2. 매칭된 위치: [5, 12].

자르는 위치 계산

구분자의 위치를 기반으로 문자열을 나눕니다:

  • 첫 번째 구분자의 앞부분 → 0~5 ("apple").
  • 첫 번째 구분자와 두 번째 구분자의 사이 → 6~12 ("banana").
  • 마지막 구분자 이후 → 13~끝 ("grape").

 

때문에  StringTokenizer가 많은 구분자나 유니코드를 문자마다 확인하는 경우에 정규 표현식 엔진으로 보다 빠르게 비교할 수 있고 문자열을 자르기 때문에 split() 성능이 좋지만, 정규 표현식 엔진의 기본 처리 시간이 StringTokenizer가 한 개의 구분자를 비교하는 것보다는 느린 경우가 많다. 또한 긴 문자열일 때 종종 같은 구분자라도 split() 빠른 경우가 있는데.. 같은 문자열을 길게 복사한 것이라서 모든 문자가 구분자의 코드 포인트보다 낮아 코드를 끝까지 읽어서 느린 경우가 아닌 찾아보니 split()은 JVM 메모리 관리 측면에서 같은 문자를 나누는 기준은 캐싱되어 성능이 최적화될 수 있다고 한다.

 

그렇다면 무엇을 사용해야 할까?
자바에서는 다음과 같이 설명하고 있다.

 

사실  StringTokenizer는 레거시 클래스이다?

StringTokenizer is a legacy class that is retained for compatibility reasons although its use is discouraged in new code. It is recommended that anyone seeking this functionality use the split method of String or the java.util.regex package instead.

호환성 이유로 유지되는 레거시 클래스이며 새로운 코드에서는 사용이 권장되지 않음. 대신 Split이나 java.util.regex 패키지를 사용하는 것이 좋다.

출처 : JAVA StringTokenizer

 

StringTokenizer는 사용하면 안될까?

결론적으로는 그렇다고 생각한다. JDK가 업데이트 됨에 따라 레거시 클래스는 삭제될 수도 있다.

JDK가 업데이트 되었다고 해서 사용하던 JDK를 바로 당장 전부 업데이트하지 않겠지만,

미래 지향적으로 본다면 그렇다고 생각한다.

반응형
반응형
이번 글에서는 백준 23881번 문제를 통해 선택 정렬 동작 원리를 확인, 활용해 보겠습니다.
선택 정렬에 대한 정리는 다음 게시글에 있습니다.

https://p-coding.tistory.com/100

 

[ 알고리즘 ] 선택 정렬

요즘 다시 알고리즘 공부를 시작하려고 하여 백준에서 문제를 풀어나가며 알고리즘을 따로 정리, 기술하는 방향으로 계획하고 있다.그 중 정렬 알고리즘을 먼저 살펴보려고 하며, 오늘은 기본

p-coding.tistory.com

 

문제 핵심

  • 선택 정렬 알고리즘을 사용하여 주어진 배열을 정렬한다.
  • 이 과정에서 K 번째 교환이 이루어질 때 교환되는 두 수를 반환하며, K번 미만일 때 특정 결과인 -1을 반환한다.
  • N : 배열의 길이
  • K : 목표 교환 횟수

풀이과정

먼저 BufferedReader를 통해 값을 받습니다. Scanner를 사용할 수 있으나 하나씩 처리하는 방식은 시간 제한에 걸릴 수 있으므로 Buffer를 활용한 클래스를 사용하는 것을 추천드립니다.

        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer stringTokenizer = new StringTokenizer(bufferedReader.readLine());

        int N = Integer.parseInt(stringTokenizer.nextToken());
        swapCount = Integer.parseInt(stringTokenizer.nextToken());

        arr = new int[N];

        stringTokenizer = new StringTokenizer(bufferedReader.readLine());
        for (int i = 0; i < N; i++) {
            arr[i] = Integer.parseInt(stringTokenizer.nextToken());
        }
  • N과 K(swapCount) 값을 저장
  • 배열의 원소들을 받고, tokenizer를 통해 받은 값을 분리하여 저장
        int count = -1;
        if (arr.length < 2) {
            System.out.println(count);
        }

        int maxIndex;
        for (int i = arr.length - 1; i > 0; i--) {
            maxIndex = i;

            for (int j = i - 1; j >= 0; j--) {
                if (arr[j] > arr[maxIndex]) {
                    maxIndex = j;
                }
            }

            if (maxIndex != i) {
                count++;
                if (swapCount == (count + 1)) {
                    System.out.println(arr[i] + " " + arr[maxIndex]);
                    return;
                }
                int temp = arr[maxIndex];
                arr[maxIndex] = arr[i];
                arr[i] = temp;

            }
        }

        System.out.println(-1);
  • count는 -1로 시작 ( 0으로 시작할 때와 값이 1차이 )
  • 교환이 이루어지지 않는다면 -1 출력
  • 기준점을 마지막 원소로 잡고 maxIndex에 저장한다
  • j ( 마지막 원소 - 1 ) 부터 1씩 감소하여 비교 후 높은 값이 있다면 위치를 기억해 둔다.
  • maxIndex와 i 값이 다르다면 위치 변경과 변경 횟수를 1 증가한다.
  • 반복하며 K(교환 횟수)에 도달했는지 체크한다.

전체 코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {
    private static int[] arr;
    private static int swapCount;

    public static void main(String[] args) {
        try {
            prepare();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        selection_sort();

    }

    private static void prepare() throws IOException {
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer stringTokenizer = new StringTokenizer(bufferedReader.readLine());

        int N = Integer.parseInt(stringTokenizer.nextToken());
        swapCount = Integer.parseInt(stringTokenizer.nextToken());

        arr = new int[N];

        stringTokenizer = new StringTokenizer(bufferedReader.readLine());
        for (int i = 0; i < N; i++) {
            arr[i] = Integer.parseInt(stringTokenizer.nextToken());
        }

    }

    private static void selection_sort() {
        int count = -1;
        if (arr.length < 2) {
            System.out.println(count);
        }

        int maxIndex;
        for (int i = arr.length - 1; i > 0; i--) {
            maxIndex = i;

            for (int j = i - 1; j >= 0; j--) {
                if (arr[j] > arr[maxIndex]) {
                    maxIndex = j;
                }
            }

            if (maxIndex != i) {
                count++;
                if (swapCount == (count + 1)) {
                    System.out.println(arr[i] + " " + arr[maxIndex]);
                    return;
                }
                int temp = arr[maxIndex];
                arr[maxIndex] = arr[i];
                arr[i] = temp;

            }
        }

        System.out.println(-1);

    }
}

 

선택 정렬 활용의 기초단계로 시험해보기 좋은 문제이다.
반응형
반응형
요즘 다시 알고리즘 공부를 시작하려고 하여
백준에서 문제를 풀어나가며 알고리즘을 따로 정리, 기술하는 방향으로 계획하고 있다.
그 중 정렬 알고리즘을 먼저 살펴보려고 하며,
오늘은 기본 중 하나인 선택 정렬를 알아보고자 한다.

선택 정렬 ( Selection Sort )

 

선택 정렬은 간단하지만 비효율적인 정렬 알고리즘 중 하나로, 배열에서 가장 큰 or 가장 작은 값을 찾아 현재 위치에 배치하는 과정을 반복하여 정렬된다.

 

순서는 다음과 같다.

 

1. 정렬되지 않은 부분에서 최솟값 or 최댓값 찾기

 

2. 현재 위치와 최솟 값 or 최대 값 교환

 

3. 다음 위치로 이동하며 반복


 

다음 그림과 같이 예시로 알아보자

5개의 정수 값을 가진 배열 Array가 존재한다.

이를 오름차순으로 왼쪽부터 최솟값을 찾아 정렬하고자 한다.

 


 

기본 형태

4 5 3 1 2

 


1회차

 

첫번 째 위치인 4를 기준

4 5 3 1 2

 

 

차례로 5, 3, 1, 2 와 비교

4 5 3 1 2

 

 

최솟값을 찾아 위치를 교환

4 5 3 1 2

 

 

1회차 완료

1 5 3 4 2

 


 

2회차

 

두번 째 위치인 5를 기준

1 5 3 4 2

 

 

차례로 3, 4, 2 와 비교

1 5 3 4 2

 

 

최솟값을 찾아 위치를 교환

1 5 3 4 2

 

 

2회차 완료

1 2 3 4 5

 

 

2회차만에 정렬되어 정렬된 배열은 다음과 같다.

1 2 3 4 5

전체 코드

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int [] arr = {6,4,2,1,3,5};
        selectionSort(arr);
        Arrays.stream(arr).forEach(System.out::println);
    }

    private static void selectionSort(int[] arr) {
        if(arr == null || arr.length < 2) {
            return;
        }

        int minIndex;
        for(int i = 0; i < arr.length - 1; i++) {
            minIndex = i;
            for(int j = i + 1; j < arr.length; j++) {
                if(arr[j] < arr[minIndex]) {
                    minIndex = j;
                }
            }

            if(minIndex != i) {
                int temp = arr[minIndex];
                arr[minIndex] = arr[i];
                arr[i] = temp;
            }
        }
    }
}

 

 

구현은 쉽고 직관적이긴 하나,  선택 정렬은 앞서 말했듯 입력 배열에 관계없이(2회차에 정렬이 되었더라도)
외부 반복문에서 n -1 회, 내부 루프에서 n - 1, n - 2, ..., 1번 비교함으로
시간복잡도는 항상 O(n^2) 으로 비효율적이다. 

 

반응형
반응형

 

새로운 개발 환경에서 시작하는 일이 잦다 보니
개발 필수 도구들을 설치하는 것에 대한 가이드라인을 작성해보려고 한다.
간단한 설치와 환경 변수 설정까지 단계별로 다루겠다.

1. JAVA 다운로드 및 설치 준비

1-1. 설치 파일 다운로드

  • 오라클 홈페이지에서 JDK(JAVA Development Kit) 버전과 운영체제에 맞는 파일을 다운로드 해줍니다.
  • 윈도우 11부터는 32비트 지원을 제공하지 않기 때문에 윈도우 최신 자바 버전도 64비트만 존재합니다.

특징 Compressed Archive Installer MSI Installer
설치 과정 수동 설치 GUI 설치 마법사 Windows Installer
환경 변수 설정 여부 수동 설정 자동 설정 자동 설정
운영체제 지원 Windows, macOS, Linux Windows, macOS, Linux Windows 전용

 

어떤 것을 다운로드 해도 상관없으나

Windows 환경 기준으로 MSI 설치파일을 사용하면 환경변수까지 자동으로 설정해주기 때문에 MSI Installer를 추천한다.

+

기본적으로 Installer, MSI Installer는 C:\Program\Files\Java 파일경로에 설치되고

Compressed Archive는 직접 파일 경로를 설정하고 설치한다.

 

 

Download the Latest Java LTS Free

Subscribe to Java SE and get the most comprehensive Java support available, with 24/7 global access to the experts.

www.oracle.com

 

1-2. 설치 완료 후 확인

  • 아래 작업표시줄 검색에 명령 터미널, 프롬포트나 cmd를 검색해 실행한다.
  • 다음 명령어를 통해 자바가 설치되었는지 확인한다.

java -version

 

다음과 같이 버전 정보가 표시되면 설치가 성공적으로 완료되었다. 

하지만 version이 확인 되지 않는다면 환경 변수가 설정되지 않았기 때문이다. 

다음 환경 변수 설정을 보자


2. 환경 변수 설정 (Windows 기준)

2 - 1. 작업 표시줄 검색창에 "환경 변수 편집"을 입력하고 선택

2 - 2. "환경 변수" 클릭

2 - 3. 새로 만들기 클릭하고 다음과 같이 입력 ( 파일 위치에 맞게 되어있는지 검토하셔야 합니다. )

C:\Program Files\Java\jdk-23

2 - 4. "Path" 찾아서 더블 클릭

새로만들기를 통해 다음과 같은 항목을 추가해 준다.

%JAVA_HOME%\bin

 

 

3. VS Code 설치

3 - 1. Visual Code 설치

 

Visual Studio Code - Code Editing. Redefined

Visual Studio Code is a code editor redefined and optimized for building and debugging modern web and cloud applications. Visual Studio Code is free and available on your favorite platform - Linux, macOS, and Windows.

code.visualstudio.com

다음 사이트를 통해 VS Code를 다운 받아준다.

3 - 2. 유용한 Extensions (확장 프로그램) 추가

다음과 같은 확장 프로그램을 검색을 통해 추가해 주면 좋다.

필수 확장 프로그램

1. Language Support for Java(TM) by Red Hat

  • 기본 Java 언어 지원 (코드 완성, 오류 탐지, 문법 강조 등).

2. Debugger for Java

  • Java 애플리케이션 디버깅 지원

3. Java Extension Pack

  • Red Hat Java 확장과 관련된 모든 패키지 한번에 설치 가능

 

Java 개발에 유용한 확장 프로그램은 다양하지만,
중복되거나 너무 많은 확장 프로그램을 설치하면 혼란을 야기할 수 있다.
따라서 본인의 개발 환경과 필요에 따라 적절한 확장 프로그램을 선택하고 사용하는 것이 중요하다

필수적인 도구만 설치하여 효율적이고 깔끔한 개발 환경을 유지하는 것을 추천한다.

  1.  
반응형
반응형

 

JAVA 에서는 System.out과 System.err는 출력 스트림(Output Stream)으로 각각 특정 목적과 동작 방식에 맞게 사용됩니다. 그 두가지에는 무슨 차이점이 있는지 알아보겠습니다.

 

System.out 특징

  • 일반 출력용 스트림으로, 프로그램의 정상적인 실행 결과를 출력
  • 출력 내용을 버퍼(buffer)에 임시 저장 후 특정 조건에 한 번에 출력
  • 이로 인해 출력 순서가 보장되지 않을 수 있습니다.

 

System.err 특징

  • 에러 출력용 스트림으로 에러나 크리티컬한 상황에 대한 기록
  • 중요한 메시지를 즉각적으로 보여주기 위해 자동으로 출력
  • 따라서 실행 중 바로 확인 가능하며, 디버깅 시 유용하게 사용될 수 있습니다.

 

예시

코드

System.out.println("3 x 3 = ");
System.out.err("9");

 

출력 예시

9
3 x 3 =

 

 


 

구분 System.out System.err
역할 일반적인 출력용 스트림 오류 및 예외 상황을 위한 출력용 스트림
의미 프로그램의 정상적인 실행 결과를 보여줌 에러 상황을 사용자나 개발자에게 전달
사용 목적 결과 메시지, 정보 출력 오류 로그, 경고 메세지 출력
출력 시 지연 출력 즉시 출력

 

반응형
반응형
TPM ( Total Productive Maintenance )

생산 현장의 효율성과 생산성을 최대한 높이기 위한 관리 기법

고장 및 결함을 줄이고 '무사고, 무고장, 무불량' 을 목표로 하는 활동을 중심으로 합니다.

이는 일본의 도요타에서 시작, 전 세계로 확산된 방식입니다.
이를 지탱하는 기둥 중 하나가 5S 이며 소프트웨어라는 공장을 빗대어 표현할 수 있겠습니다.


5S

1. 정리 Seiri ▶조직

적절한 명명법 등과 같은 방법을 사용하여, 클래스, 메서드, 변수 등 무엇이 어디에 사용되고 위치해 있는지 알아야 한다.
( NHN Academy 당시 학장님 말씀으로  '저는 개발 당시 대부분 변수 이름 짓는 것에 시간을 보냈습니다. 그만큼 심사숙고하여 이름을 지어야 합니다.' 라고 하셨다. )

 

2. 정돈 Seiton ▶ 단정함

물건마다 제자리가 있다. 코드 또한 누구나 예상할 수 있는 위치에 알아야 한다.

 

3. 청소 Seiso ▶ 정리

TODO와 같이 주석이 달린 코드가 처리되었다면, 지워야 한다. 불필요한 쓰레기는 작업공간을 혼란스럽게 만든다.

 

4. 청결 Seiketsu ▶ 표준화

그룹 내의 스타일을 정하고 따라야 한다.

 

5. 생활화 Shutsuke 규율

관례를 따르고, 자신의 코드를 돌아보며 변경할 수 있는 마음을 가져야 한다.

 

'도요타' 자동차 처럼 소프트웨어도 엔진오일 등 자동차 상태를 매번 체크하고,
부품을 교체하여 고장을 미리 방지한다. 

즉,
우리가 만드는 소프트웨어 또한 주기적인 코드리뷰와 불필요한 코드를 과감히 제거하고, 교체하는 등 지속적인 리팩터링을 통해 만들어가야 한다.
반응형
반응형
코드나 컴퓨터를 사용하다 보면 ₩ 써야할 때가 있습니다.
근데 기존 키보드에서는 Enter키 위에를 아무리 눌러도 
\ , |
로 작성됩니다.

그럴 땐 ALT + = 를 누르면 ₩ 가 입력됩니다.
 

 

반응형
반응형

 

"더블클릭은 상관없어~" 하고 잘 알아보지도 않고
G502 hero 벌크제품을 2022년도 쯤에 구매해서 사용했습니다.
얼마 지나지 않아서 더블클릭 증상이 찾아왔습니다.
오랫동안(3일) 컴퓨터를 사용하지 않거나 종료하지 않절전모드만 자주 사용하면
종종 더블클릭에 당첨되고 합니다.

근데 최근에 문제가 터졌습니다. 이제 클릭이 되지 않습니다....
오른쪽 마우스 클릭이 오락가락합니다.

여러 해결 방법을 찾아보았습니다.
1. 잔류 전기가 남아 그렇다 선을 뽑고 막 클릭해서 방전 시켜라
2. 스위치 부품이 녹슬어서 그렇다. 스위치를 바꿔라
3. 마우스 클릭하는 부분 틈사이로 바람을 불어주면 된다.

모두 임시 방편일 뿐 다시 돌아왔고 결국에 클릭이 되지않는 상태가 되어버렸습니다.
그래서 수리점에 맡길려다가 아두이노, 라즈베리파이 조금 봤다고 자신감이 생겨 이참에 분해해서 수리 하자.
바로 진행해 보았습니다.


준비물
1. 인두기와 납 (다이소에서 구매했습니다.)
2. 마우스 스위치
3. 수리할 마우스
4. 집게 (이것도 다이소에서.. 없으셔도 됩니다.)
5. 목장갑

 

1. 먼저 마우스 커버를 분리해줍니다.

추가로 사이드 버튼 기판도 분리해줍니다.

 

2.  보이는 모든 나사와 휠을 분리해 줍니다.

잘 기억해주세요

 

3. 이 부분을 제거해 줍니다.

어느 영상에서 번갈아가면서 인두로 작업하면 된다고 한다는데

세 개라서 금방 굳습니다.

때문에 인두기를 가로로 눕혀서 한번에 작업하는 것이 좋겠습니다. 

4. 다음 제품을 납땜해 줍니다.

기존은 중국 제품 50M (5000만회 보장) 입니다.

저는 많이 사용하기도하고 묵직한 느낌을 좋아하기 때문에 골드 80M 사용하였습니다.

취향에 맞는 부품을 골라 사용하시면 됩니다.

 

 

 

마우스 수리 스위치 TTC 실버 골드 방진골드 30M 60M 80M - 유선마우스 | 쿠팡

쿠팡에서 5.0 구매하고 더 많은 혜택을 받으세요! 지금 할인중인 다른 7 제품도 바로 쿠팡에서 확인할 수 있습니다.

www.coupang.com

 

5. 납땜 완료

기판은 좀 탔지만 납땜 완료한 모습입니다.

 

 

5. 재조립

분해의 역순으로 조립하면 되겠습니다.

가끔 이렇게 수리할 때가 있는데 귀찮아서 미루다 작업해 보았는데요.
확실히 골드 제품이 묵직하고 클릭감이 좋지만 너무 많이 사용하면 피로도가 있을 것 같습니다.
그래도 중국이나 일본제품의 클릭문제 때문에 저는 앞으로도 골드 제품 사용할 것  같습니다.

 

반응형
반응형
Android Studio를 통해 Emulator로 Debug 하던 중에 반복되는 이 에러를 보았다.
[ Incorrect use of ParentDataWidget ]

 

이 에러는 Expanded Widget Column, Row, Flew 와 같은 부모 위젯에서 사용해야 하지만,

그 이외에 위젯에서 사용될 경우 발생한다.

 

따라서 Expanded를 세 개의 부모 위젯에서 사용하거나 제거해주면 해결된다.

반응형
반응형

 

에라토스테네스의 체 는 소수를 찾는 쉽고 빠르게 찾을 수 있는 방법이다.

( 고대 그리수 수학자 에라토스테네스가 발견 )

 

알고리즘

다음과 같은 알고리즘을 따른다.

0 ~ 50 까지의 수를 찾고자 할때, 0과 1을 제외

 

1.  2부터 시작하여 2를 제외한 2의 배수를 모두 지운다.

  2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30
31 32 33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48 49 50

 

2. 지워지지 않은 다음 숫자부터 1번과 같이 반복한다. ( 3을 제외한 3의 배수 지우기 )

  2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30
31 32 33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48 49 50

 

3.  √50 = 7.071 이므로 구하는 수의 제곱근 이하의 소수, 즉, 7의 배수까지 제외하면 된다.

  2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30
31 32 33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48 49 50

 

4. 제외 되지 않은 숫자가 소수

 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47

 

Code

자바를 통해 다음과 같이 구현할 수 있다.

Boolean[] primeNumbers = new Boolean[number + 1]; // N이 0일 때, 0 ~ 100 까지 101개의 수
        primeNumbers[0] = false; // 1
        primeNumbers[1] = false; // 2

먼저 0 ~ 100까지의 101개의 배열을 생성해주고 0, 1은 제외 시킨다.

 

 // 모두 true로 초기화
 for (int i = 2; i <= number; i++) {
 	primeNumbers[i] = true;
 }

2부터 모두 소수라 가정하고 true로 지정한다. 

 

for (int i = 2; i <= Math.sqrt(number); i++) {
	if (primeNumbers[i] == false)
    	continue;
    for (int j = i + i; j <= number; j += i) {
    	primeNumbers[j] = false;
    }
}

에라토스테네스의 체 공식으로

1. 이미 제외시킨 숫자라면 다음 숫자

2. 제외시킨 숫자가 아니라면 그 수를 제외하고 배수를 false로 변환한다.

 

다음과 같은 결과를 얻을 수 있다.

 

전체 코드

import java.util.Scanner;

public class eratos {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.print("2이상의 숫자를 입력해 주세요 : ");
        int N = scanner.nextInt();

        fintPrimeNumber(N);
    }

        private static void fintPrimeNumber(int number) {
        Boolean[] primeNumbers = new Boolean[number + 1]; // N이 0일 때, 0 ~ 100 까지 101개의 수
        primeNumbers[0] = false; // 1
        primeNumbers[1] = false; // 2

        // 모두 true로 초기화
        for (int i = 2; i <= number; i++) {
            primeNumbers[i] = true;
        }

        for (int i = 2; i <= Math.sqrt(number); i++) {
            if (primeNumbers[i] == false)
                continue;
            for (int j = i + i; j <= number; j += i) {
                primeNumbers[j] = false;
            }
        }

        System.out.println();
        System.out.println(number + "이하의 소수 입니다.");
        
        for (int i = 0; i < primeNumbers.length; i++) {
            if (primeNumbers[i]) {
                System.out.print(i + " ");
            }
        }
    }
}
반응형

'알고리즘' 카테고리의 다른 글

[ 알고리즘 ] 병합 정렬 - JAVA  (2) 2025.03.17
플라비우스 요세푸스 순열  (2) 2025.02.28
[ 자료구조 ] 큐 ( Queue ) - JAVA  (0) 2025.02.26
스택 ( 자료구조 ) - JAVA  (0) 2025.02.04
[ 알고리즘 ] 선택 정렬  (2) 2024.12.12

+ Recent posts