StringTokenizer 기본 및 사용법

StringTokenizer 클래스는 문자열을 구분자를 이용하여 쪼갤 때 사용할 수 있다. (쪼갠다. = 파싱한다.)

예를 들어 "Hi I'm Yangs!!" 라는 문자열을 " "(공백)을 구분자로 "HI", "I'm", "Yangs!!" 이렇게 3개로 쪼개는 것이 가능하다.

Token을 구분자에 의해 쪼개진 단어라고 생각하면 된다.

 

StringTokenizer 생성

- StringTokenizer(String str) : 파싱 할 문자열을 인자로 받는다. 구분자를 지정하지 않았으므로 스페이스, 탭, 줄바꿈, 캐리지 리턴 등 기본 구분자가 적용된다.

- StringTokenizer(String str, String delim) : 파싱할 문자열과 구분자를 인자로 받는다.

- StringTokenizer(String str, String delim, boolean flag) : flag는 구분자 자체도 토큰으로 인식하게 할지 여부를 정한다. 예를 들어 true라면 "Hi I'm Yangs!!"는 공백을 포함하여"HI", " ", "I'm", " ", "Yangs!!" 이렇게 5개의 토큰으로 파싱 된다.

String source = "Hi I'm Yangs!!";

StringTokenizer tokenizer1 = new StringTokenizer(source);
while(tokenizer1.hasMoreTokens()){
    System.out.println("tokenizer1's token : " + tokenizer1.nextToken());
}

StringTokenizer tokenizer2 = new StringTokenizer(source, " ");
while(tokenizer2.hasMoreTokens()){
    System.out.println("tokenizer2's token : " + tokenizer2.nextToken());
}

StringTokenizer tokenizer3 = new StringTokenizer(source, " ", true);
while(tokenizer3.hasMoreTokens()){
    System.out.println("tokenizer3's token : " + tokenizer3.nextToken());
}
// 출력결과
tokenizer1's token : Hi
tokenizer1's token : I'm
tokenizer1's token : Yangs!!

tokenizer2's token : Hi
tokenizer2's token : I'm
tokenizer2's token : Yangs!!

tokenizer3's token : Hi
tokenizer3's token :  
tokenizer3's token : I'm
tokenizer3's token :  
tokenizer3's token : Yangs!!

StringTokenizer 사용법

StringTokenizer를 이용하여 문자열 -> 배열로 파싱하기

가장 많이 사용되는 문자열을 파싱하여 배열에 담는 예제이다.

hasMoreTokens()로 총토큰의 개수를 구하고, nextToken()으로 한 토큰씩 꺼낼 수 있다.

StringTokenizer는 구분자에 의해서 파싱 후 빈 토큰은 버리는 동작을 확인할 수 있다.

String source = "|문자열||에서|배열로|갑니다|";

// StringTokenizer 생성
StringTokenizer tokenizer = new StringTokenizer(source, "|");
System.out.println("총 토큰 갯수 : " + tokenizer.countTokens()); // 총 토큰 갯수 : 4

String[] arr = new String[4]; // 결과 배열
int idx = 0;
while (tokenizer.hasMoreTokens()){
    arr[idx] = tokenizer.nextToken(); // 배열에 한 토큰씩 담기
    idx++;
}

System.out.println(Arrays.toString(arr)); // [문자열, 에서, 배열로, 갑니다]

 

 

여러 구분자로 파싱하기

StringTokenizer 생성자 구분자를 여러 개 지정하면 된다. > new StringTokenizer(source, ",|;!")

String source = "|문자열,,에서|배열로;갑니다!";

StringTokenizer tokenizer = new StringTokenizer(source, ",|;!");
System.out.println("총 토큰 갯수 : " + tokenizer.countTokens()); // 총 토큰 갯수 : 4

String[] arr = new String[4];
int idx = 0;
while (tokenizer.hasMoreTokens()){
    arr[idx] = tokenizer.nextToken();
    idx++;
}

System.out.println(Arrays.toString(arr)); // [문자열, 에서, 배열로, 갑니다]

 

 


 

 

[Java] File 클래스 기본

Java.io.File 클래스는 자바에서 파일시스템의 파일이나 디렉터리(폴더)를 추상화 한 클래스이다.

즉, File 클래스를 통하여 파일시스템의 파일이나 디렉터리를 조작(삭제, 파일명변경 등)을 할 수 있다.

 

File 클래스를 통해 할 수 있는 작업이 많은 만큼 제공되는 메소드들도 다양하다. File 클래스의 생성과 케이스별 사용법에 대해 정리한다.

 


File 객체 생성

아래 경로처럼 Test.txt 파일을 생성하고 이 파일의 File 객체를 생성한다.

D:\MyWork\Test.txt

public class File_Practice {
    public static void main(String[] args) {
        String parentPath = "D:/MyWork";
        String filePath = "D:/MyWork/Test.txt";
        String fileNm = "Test.txt";

        // File(File parent, String child) 생성자
        File file1 = new File(parentPath, fileNm);

        // File(String pathname) 생성자
        File file2 = new File(filePath);

        // File(String parent, String child) 생성자
        File parent = new File(parentPath);
        File file3 = new File(parent, fileNm);

        if(file1.exists() && file2.exists() && file3.exists()){
            System.out.println("모두 생성 완료!");
        }
    }
}

file.exist() 는 파일의 존재여부를 검사하는 메소드를 이처럼 File 클래스에서는 파일에 관한 여러 편리한 메소드를 제공하도 있다.

아래부터는 이런 메소드들을 활용하여 어떤 작업을 할 수 있는지 케이스별로 살펴본다.


File 객체 활용

아래 소스코드를 실행하기 위한 디폴트 폴더/파일 구성은 아래와 같습니다.

D:/MyWork (Dir)
D:/MyWork/Test.txt (File)
D:/MyWork/MyDirectory (Dir)

1. 파일 또는 디렉터리의 존재유무 확인 및 기본정보 출력

public class Check_Default_Info {
    public static void main(String[] args) {
        String rootPath = "D:/MyWork";

        File rootDir = new File(rootPath);

        // 파일명
        System.out.println(rootDir.getName()); // MyWork

        // 절대경로
        System.out.println(rootDir.getAbsolutePath()); // D:\MyWork

        // 경로
        System.out.println(rootDir.getPath()); // D:\MyWork

        // 존재여부
        System.out.println(rootDir.exists()); // true

        // 읽기/쓰기/실행 가능여부
        if (rootDir.exists()) { // 존재하면
            System.out.println(rootDir.canRead()); // true
            System.out.println(rootDir.canWrite()); // true
            System.out.println(rootDir.canExecute()); // true
        }
    }
}

 


2. 디렉터리의 내부 내용물(파일, 디렉터리) 출력

디렉터리의 경우 listFiles() 메소드로 내부 파일(디렉터리 포함) 목록을 가져올 수 있으며 for문으로 순회하며 작업을 할 수 있다.

public class Check_DirectoryContents_Info {
    public static void main(String[] args) {
        String rootPath = "D:/MyWork";
        File rootDir = new File(rootPath);

        if(rootDir.isDirectory()){ // 디렉터리면
            File[] contents = rootDir.listFiles(); // 파일목록을 가져온다.
            for(File file : contents){
                System.out.println("파일명 : " + file.getName());
                System.out.println("절대경로 : " + file.getAbsolutePath());
                System.out.println("파일여부 : " + file.isFile());
                System.out.println("------------------------------");
            }
        }
    }
}
// 출력결과
파일명 : MyDirectory
절대경로 : D:\MyWork\MyDirectory
파일여부 : false
------------------------------
파일명 : Test.txt
절대경로 : D:\MyWork\Test.txt
파일여부 : true
------------------------------

3. 디렉터리 및 파일 생성

mkdir() 메소드를 사용하여 디렉터리를 생성한다. mkdirs() 메소드도 제공되며 차이점은 mkdirs()는 필요한 상위의 디렉터리가 없으면 같이 만든다는 것에 있다.

createNewFile() 메소드는 신규 파일을 생성할 수 있다. 

length() 메소드는 파일의 용량을 체크할 수 있으며 신규 파일의 경우 빈 파일이므로 0이 출력된다.

public class Mkdir {
    public static void main(String[] args) {
        String rootPath = "D:/MyWork";
        File rootDir = new File(rootPath);

        // 디렉터리 생성시작
        File newDir = new File(rootDir, "newDir"); // 생성할 디렉터리
        System.out.println("신규 디렉터리 생성여부 : " + newDir.exists()); // false

        boolean isMake = newDir.mkdir(); // 디렉터리 생성
        System.out.println("신규 디렉터리 생성결과 : " + isMake); // true
        System.out.println("신규 디렉터리 생성여부1 : " + newDir.exists()); // true
        System.out.println("신규 디렉터리 생성여부2 : " + newDir.isDirectory()); // true

        // 파일 생성시작
        File newFile = new File(newDir, "newFile");
        System.out.println("신규 파일 생성여부 : " + newFile.exists()); // false

        try {
            newFile.createNewFile(); // 파일생성
        } catch (IOException e) {
            e.printStackTrace();
        }

        System.out.println("신규 파일 생성여부 : " + newFile.exists()); // true
        System.out.println("신규 파일 용량 : " + newFile.length()); // 0
        System.out.println("신규 파일 경로 : " + newFile.getAbsolutePath()); // D:\MyWork\newDir\newFile
    }
}

 


4. 파일명 변경 및 삭제

createNewFile()로 새로운 파일 생성 후 delete() 메소드로 삭제한다.

public class Rename_Delete {
    public static void main(String[] args) throws IOException {
        String rootPath = "D:/MyWork";
        File rootDir = new File(rootPath);

        File file = new File(rootDir, "tmpFile");
        file.createNewFile();
        System.out.println("삭제전 파일 존재여부 : " + file.exists()); // true

        // 파일삭제 시작
        boolean isDel = file.delete();
        System.out.println("파일 삭제 여부 : " + isDel); // true
        System.out.println("삭제후 파일 존재여부 : " + file.exists()); // false
    }
}

 


 


Cannot find symbol 원인 및 해결방법(Cannot resolve symbol, Symbol not found 등)

 

개발 중 종종 마주치는 에러인 Cannot find symbol에 대해 정리한다. (Cannot resolve symbol과 Symbol not found과 같은 의미이다.)


1. Cannot find symbol 의미

포괄적인 에러로 작성한 소스코드에 문제가 숨어있거나 컴파일 하는 방식에 문제가 있을 때 발생한다.

자바의 소스코드는 아래와 같은 구성요소 이루어져 있다.

 

1. 키워드 : true, false, class, while 등

2. 리터럴 : "Hello", 'H', 33 등

3. 오퍼레이터나 알파벳, 숫자가 아닌 문자 : +, ", { 등

4. 식별자 : 클래스명(Integer 등), 변수명(i 등), 함수명(toString 등)

5. 주석 및 공백

 

이 때 cannot find symbol 은 식별자와 관련된 오류이다.

코드가 컴파일될 때 컴파일러는 소스코드의 식별자들이 각각 어떤 의미가 있는지 해석한다. 이 작업을 할 수 없는 경우(= 컴파일러가 소스코드를 해석할 수 없음) cannot find symbol 에러가 출력된다.


2. Cannot find symbol 원인

굉장히 다양한 원인이 때로는 복합적으로 있을 수 있다. 

 

1. 스펠링 오작성 : 예를들어 StringBuffer를 SpringBuffer로 작성. SpringBuffer 클래스가 없어 코드를 컴파일할 수 없다. 

StringBuffer sb = new SpringBuffer();
Error:(5, 31) java: cannot find symbol
symbol: class SpringBuffer
location: class com.example.demo.cannotfindsymbol.Test

 

2. 대소문자 오작성 : StringBuffer -> Stringbuffer로 작성.

 

3. 변수 선언을 하지않고 사용

System.out.println(str); // 선언하지 않은 str 변수 사용

 

4. 다른 영역에 선언한 변수를 사용하는 오류 : for문 영역의 변수를 외부에서 접근.

for(int i=0; i<2; i++){
    System.out.println(i);
}

System.out.println(i); // i를 찾을 수 없어 오류

 

5. 객체가 가지고 있지 않은 변수나 함수에 접근하는 경우

String str = "123";
str.reverse(); // String 객체는 reverse() 메소드가 없다.

 

6. new 키워드를 작성하지 않은 경우

StringBuffer sb = StringBuffer();

 

7. 같은 클래스명의 다른 패키지 클래스가 import 된 경우 : IDE의 자동 임포트 기능을 이용하다 보면 종종 발생한다. 사용하고자 하는 패키지의 클래스가 임포트 되었는지 확인한다.

 

 

8. 세미콜론(;)이 잘못 작성된 경우 : 아래는 없어야 될 세미콜론이 중간에 작성되었다.

세미콜론에 의해 for(~~~) 와 코드블럭{ }이 분리되며 코드블럭{ }에서 i는 선언되지 않았으므로 오류가 발생한다.

for (int i = 0; i < 100; i++); {
    System.out.println("i : " + i);
}

 

9. 오퍼레이터가 오작성 된 경우 : 아래에서는 *를 생략함으로써 i라는 메소드를 찾으나 없으므로 오류가 발생한다.

int a = 1;
int b = 2;
int i = 1;

int result = i(a+b); // i*(a+b) 에서 *를 작성하지 않음

 

cannot find symbol 해결

발생할 수 있는 원인이 워낙 다양하고 복합적이다 보니, 오류가 발생한 부분을 중심으로 작성한 코드를 주의 깊게 디버깅하는 수밖에 없다.

개발자가 코드를 잘못 작성한 것 외에도 의도한 것과 다른 버전의 라이브러리를 사용했다던가(의존성 에러), IDE에서 문제가 있다던가, 특정 소스를 컴파일하지 않았던가 등의 다양한 원인이 있으므로 단계별로 살펴봐야 한다.

 


참고

stackoverflow.com/questions/25706216/what-does-a-cannot-find-symbol-or-cannot-resolve-symbol-error-mean

 

What does a "Cannot find symbol" or "Cannot resolve symbol" error mean?

Please explain the following about "Cannot find symbol", "Cannot resolve symbol" or "Symbol not found" errors: What do they mean? What things can cause them? How does...

stackoverflow.com

 

 


 

 

+ Recent posts