점프투자바

SUADI·2022년 5월 31일

종합문제

문제 10) 오류 해결(execute함수 끝내기)

import java.util.Random;

class OddException extends Exception {
}

public class Sample {
    static void execute(int n) throws OddException {
        System.out.printf("입력 숫자: %d\n", n);
        if (n % 2 == 1) {  // 홀수이면 OddException이 발생한다.
            throw new OddException();
        }
        System.out.println("짝수입니다.");
    }

    public static void main(String[] args) {
        Random r = new Random();
        try {
            for (int i = 0; i < 10; i++) {
                execute(r.nextInt(10));
            }
        } catch (OddException e) {
            e.printStackTrace();
        }
    }
}

0-10 중 한 숫자를 random 함수로 가져와 짝수이면 짝수라고 출력하고, 홀수이면 OddException 에러를 내도록 짠 코드이다. executive 함수를 10번 반복해야 하는데 도중에 홀수가 나오면 프로그램이 종료된다. 이를 해결하려면 두가지 방법이 있는데 첫번째 방법은 main 메소드에서 try-catch 구문을 for문 안으로 집어 넣어 홀수가 나와 OddException이 나더라도 10번을 계속 반복하도록 하는 방법이다.

import java.util.Random;

class OddException extends Exception {
}

public class Sample {
    static void execute(int n) throws OddException {
        System.out.printf("입력 숫자: %d\n", n);
        if (n % 2 == 1) {  // 홀수이면 OddException이 발생한다.
            throw new OddException();
        }
        System.out.println("짝수입니다.");
    }

    public static void main(String[] args) {
        Random r = new Random();
        for (int i = 0; i < 10; i++) {
            try {
                execute(r.nextInt(10));
            } catch (OddException e) {
                e.printStackTrace();
            }
        }
    }
}
  • 여기서 printStackTrace 함수는 에러 메세지의 발생 근원지를 찾아서 단계별로 에러를 출력해주는 함수이다.

  • 두번째 방법은 예외처리를 main 메소드에서 하는 것이 아닌 execute 함수 내에서 하는 방법이다. execute 함수에서 OddException을 main메소드로 던지지 말고, try-catch구문을 사용해서 함수 내에서 에러를 처리한다. 이렇게 하면 에러가 나도 for문으로 execute 함수가 10번이 정상적으로 실행될 것이다.

import java.util.Random;

class OddException extends Exception {
}

public class Sample {
    static void execute(int n) {
        System.out.printf("입력 숫자: %d\n", n);
        try {
            if (n % 2 == 1) {  // 홀수이면 OddException이 발생한다.
                throw new OddException();
            }
            System.out.println("짝수입니다.");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        Random r = new Random();
        for (int i = 0; i < 10; i++) {
            execute(r.nextInt(10));
        }
    }
}

문제 11) 연속된 홀수, 짝수 사이에 기호 넣기

import java.util.ArrayList;
import java.util.Arrays;

public class Sample {
    static String dashInsert(String data) {
        int[] numbers = Arrays.stream(data.split(""))
                .mapToInt(Integer::parseInt)
                .toArray();
        ArrayList<String> result = new ArrayList<>();
        for (int i=0; i< numbers.length; i++) {
            result.add("" + numbers[i]);
            if (i < numbers.length-1) {
                boolean isOdd = numbers[i] %2 ==1;
                boolean isNextOdd = numbers[i+1] %2 ==1;
                if (isOdd && isNextOdd) result.add("-");
                else if (!isOdd && !isNextOdd) result.add("*");
            }
        }
        return String.join("",result);
    }

    public static void main(String[] args) {
        String data = "4546793";
        String result = dashInsert(data);
        System.out.println(result);  // 454*67-9-3 출력
    }
}
  • dashInsert 메소드를 선언하는데 static으로 선언하여 main메소드에서 객체 생성없이 사용할 수 있도록 했고, 인풋값과 리턴값을 String 자료형을 사용하였다. 인풋값, 리턴값이 정수인데 String으로 받는 이유는 각 숫자를 String[] 자료형 변수로 넣어서 조건에 따라 기호(- , * )를 넣어야 하기 때문이다.
  • String으로 입력값을 받긴 했지만 홀수인지 짝수인지를 구분하기 위해 int[] 변수에 따로 입력값을 저장한다. 저장을 위한 방법으로 람다함수를 사용해서 일단 data를 split으로 나눈 다음 이 수들이 String이므로 mapToInt 함수를 사용해서 Integer::parseInt로 정수형으로 바꾼다. 그다음 toArray 함수를 이용해서 각각의 수를 배열에 저장한다.
  • 그리고 또 하나의 변수를 사용해야 한다. String 자료형으로 리턴하기 위해 ArrayList(result)를 만들어 놓는다.
  • for 문을 사용해서 result에 ""+ numbers[i]를 add한다. 여기서 좀 헷갈렸던게 왜 빈 문자열을 넣는지 몰랐는데 추측컨데 number[i]이 정수형이니까 빈 문자인 ""를 함께 넣으면 String 자료형으로 바뀌는게 아닌가 싶다.
  • 그 다음 numbers에서 홀수가 연속되는지 짝수가 연속되는지를 판단하기 위해 if문을 사용한다. i가 data.length -1 보다 작아야만 붙어있는 수가 연속되는지 알 수 있을 것이다.
  • 그다음 boolean 자료형으로 붙어있는 수가 둘다 홀수인지 짝수인지를 판단하는 변수를 두개 만든다.
  • 또 다시 if문을 사용해서 둘다 홀수이면 -를 add하고, 둘다 짝수이면 *를 add하도록 한다.
  • String 자료형으로 result를 리턴해야 하기때문에 String.join 함수를 사용해서 ArrayList를 String 자료형으로 바꾸어서 리턴한다.

문제 12) 연속된 수 압축

public class Sample {
    static String compressNum(String data) {
        String[] c = data.split("");
        String result = "";
        int count = 0;
        for (int i=0; i<data.length()-1; i++) {
            if (c[i].equals(c[i+1])) {
                count++;
            } else {
                result += c[i];
                result += count + 1;
                count = 0;
            }
        }
        return result;
    }

    public static void main(String[] args) {
        String data = "aaabbcccccca";
        System.out.println(compressNum(data)); // a3b2c6 출력
    }
}
public class Sample {
    static String compressNum(String data) {
        String result = "";
        String temp = "";
        int count = 0;
        for (String c : data.split("")) {
            if (!c.equals(temp)) {
                temp = c;
                if (count > 0) {
                    result += "" + count;
                }
                result += c;
                count = 1;
            } else {
                count++;
            }
        }
        if (count > 0) {
            result += "" + count;
        }
        return result;
    }

    public static void main(String[] args) {
        String result = compressNum("aaabbcccccca");
        System.out.println(result);  // a3b2c6a1 출력
    }
}
  • 첫번째 코드는 내가 직접 짠 코드이고 결과적으로는 틀렸다. 비슷한 결과가 나오기는 하는데 마지막 문자인 a가 출력이 되질 않는다. 아직까지도 이유는 잘모르겠고, 해답을 봐도 잘 모르겠다.. 그래서 일단 내 코드만 리뷰해 보려고 한다.
  • 먼저 compressNum 메소드를 static으로 선언했고, 입력값과 리턴값 모두 String 자료형으로 했다.
  • 먼저 String 배열인 c를 선언한 후 data를 split해서 저장한다. 그리고 연속된 수가 몇개인지 파악할 수 있게끔 count 변수를 int형으로 선언해서 0을 저장한다.
  • c 변수에서 i번째와 (i+1)번째 element가 같다면 count++를 하고 다르다면 result에 c[i]를 저장하고, (count+1)값을 저장한 후 count를 0으로 바꿔놓는다. 그다음 result값을 리턴하면 마지막 문자만 빼고 맞게 출력된다. 해설지를 봐도 코드가 무슨 내용인지를 잘 모르겠어서 답답하다..ㅠㅠ

문제 13) 0-9 숫자가 각각 한번씩만 사용됐는지 확인

import java.util.HashSet;

public class Sample {
    static boolean chkDupNum(String data) {
        HashSet<String> chk = new HashSet<>();
        for (String c : data.split("")) {
            chk.add(c);
        }
        if (chk.size() < data.length()) return false;
        else return data.length() == 10;
    }

    public static void main(String[] args) {
        System.out.println(chkDupNum("0123456789"));      // true
        System.out.println(chkDupNum("01234"));           // false
        System.out.println(chkDupNum("01234567890"));     // false
        System.out.println(chkDupNum("6789012345"));      // true
        System.out.println(chkDupNum("012322456789"));    // false
    }
}
  • 이 코드는 내가 짠 코드이고, 해답과는 다르다. 어떤게 더 좋은 코드인지는 잘 모르겠지만 결과는 다행히도 똑같이 나왔다.
  • chkDupNum 메소드를 생성하여 입력값으로 String 자료형을 사용했고, 리턴값은 booleaan 자료형을 사용했다.
  • 중복되는 값이 있으면 제거하는 특성이 있는 HashSet을 이용해서 for 문으로 data를 split하여 HashSet에 넣어서 중복되는 값을 없앴다.
  • 그리고 if문을 이용해서 HashSet의 크기가 data의 길이보다 작으면 중복되는 값이 사라졌다는 의미이므로 false를 리턴하도록 했다.
  • else 문을 사용하여 0-9가 모두 사용됐는지 확인하기 위해 data의 길이가 10이면 true를 리턴하도록 했다.
import java.util.ArrayList;

public class Sample {
    static boolean chkDupNum(String data) {
        ArrayList<String> result = new ArrayList<>();
        for (String c : data.split("")) {
            if (result.contains(c)) {
                return false;  // 중복된 숫자가 있으면 false
            } else {
                result.add(c);
            }
        }
        return result.size() == 10;  // 0~9 모두 10개의 숫자인지 확인
    }

    public static void main(String[] args) {
        System.out.println(chkDupNum("0123456789"));      // true
        System.out.println(chkDupNum("01234"));           // false
        System.out.println(chkDupNum("01234567890"));     // false
        System.out.println(chkDupNum("6789012345"));      // true
        System.out.println(chkDupNum("012322456789"));    // false
    }
}
  • 해답의 풀이는 data를 split하여 각 element가 ArrayList에 포함되어있으면 false를 리턴하고 포함되어있지 않으면 result에 그 element를 넣는 방식으로 코드를 짰다.

문제 14) 모스 부호 해독(단어 " ", 문자 " ")

import java.util.ArrayList;
import java.util.HashMap;

public class Sample {
    static String morse(String data) {
        HashMap<String, String> info = new HashMap<String, String>() {{
            put(".-", "A");
            put("-...", "B");
            put("-.-.", "C");
            put("-..", "D");
            put(".", "E");
            put("..-.", "F");
            put("--.", "G");
            put("....", "H");
            put("..", "I");
            put(".---", "J");
            put("-.-", "K");
            put(".-..", "L");
            put("--", "M");
            put("-.", "N");
            put("---", "O");
            put(".--.", "P");
            put("--.-", "Q");
            put(".-.", "R");
            put("...", "S");
            put("-", "T");
            put("..-", "U");
            put("...-", "V");
            put(".--", "W");
            put("-..-", "X");
            put("-.--", "Y");
            put("--..", "Z");
        }};
        ArrayList<String> result = new ArrayList<>();
        for (String word : data.split("  ")) {
            for (String c : word.split(" ")) {
                result.add(info.get(c));
            }
            result.add(" ");
        }
        return String.join("", result);
    }
    public static void main(String[] args) {
        System.out.println(morse(".... .  ... .-.. . . .--. ...  . .- .-. .-.. -.--"));  // HE SLEEPS EARLY
    }
}
  • HashMap을 이용해서 각 문자를 value값으로 두고 문자에 해당하는 모스부호를 key값으로 둔다. 여기서 HashSet에 데이터를 저장할때 put 함수를 이용하는데 원래는 set이름.put(...) 이렇게 사용해야 하지만 중괄호 두개를 이용해서 put(..)으로 작성할 수 있다. 그리고 원래 오른쪽 제네릭스에는 자료형을 생략하곤 하는데 이렇게 중괄호를 이용할 경우에는 오른쪽에도 자료형을 적어준다.
  • 이중 for문을 사용한다. 단어와 단어사이는 띄어쓰기가 두 번되어있고, 문자와 문자 사이에는 한 번되어있는데 먼저 단어 단위로 for문을 만든 후 단어마다 띄어쓰기를 한번하도록 하고 그 안에 문자 단위로 for문을 만들어 HashSet에서 key값에 해당하는 value값을 result에 저장하도록 코드를 짰다.

문제 15) 시저 암호 풀기

import java.util.ArrayList;

public class Sample {
    static String caesar(String data, int n) {
        String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        ArrayList<String> result = new ArrayList<>();
        for (String c : data.split("")) {
            int position = alphabet.indexOf(c);
            int newPosition = position + n;
            newPosition = newPosition % alphabet.length();
            result.add(alphabet.substring(newPosition, newPosition+1));
        }
        return String.join("",result);
    }
    
        public static void main(String[] args) {
        System.out.println(caesar("CAT", 5));  // HFY
        System.out.println(caesar("XYZ", 3));  // ABC
    }
}
  • 입력값은 String 자료형의 data와 알파벳 순서를 미룰 int 자료형의 n 이렇게 두개로 하고, 리턴값으로 String 자료형을 이용한다.
  • alphabet을 순서대로 String 자료형 변수에 저장을 하고, 결과값을 담을 ArrayList를 생성한다.
  • data를 split해서 각 문자마다 for문을 돌린다. 그 안에 data 안의 각 문자가 몇번째 알파벳인지 indecof 함수를 이용해서 그 순서를 int 자료형의 변수에 넣는다.
  • 그 다음 몇번 미룰 지를 알려주는 변수인 n을 position에 더해서 새로운 변수를 생성해서 저장한다.
  • 만약 26번째 알파벳인 z 이후로 넘어가면 다시 a부터 시작되도록 newPosition을 26으로 나눈 나머지를 새로 저장한다.
  • 그다음 substring함수를 이용하는데 substring함수는 문자열에서 몇번째부터 몇번째까지의 문자열을 빼내는 함수이다. result함수에 미뤄진 알파벳을 저장하기 위해 substring 함수로 newposition 값을 빼내서 저장한다.

드디어 점프투자바가 끝이 났다. 생각보다 너무 오래 걸렸다. 꾸준히 공부를 했으면 이것보다는 일찍 끝났을텐데 조금 아쉬움이 남는다. 이것만이 공부의 끝은 아니기 때문에, 이제 훨씬 할 공부가 많아지기 때문에 앞으로 꾸준히 하면 이런 아쉬움은 남지 않을 것이다. 이 다음으로는 '자바의 정석' 책으로 조금 더 깊이 공부할 생각이다. 내가 효율적으로 공부하고 있는지는 잘 모르겠지만 언어를 확실히 마스터하는게 결코 잘못된 방법은 아닐 것이다. 점프투자바에서 이해가 되지 않았던 개념을 자바의 정석을 통해서 조금 더 공부하고, 그 이외의 부분은 예제를 위주로 공부한 후 빠르게 넘어갈 예정이다. 자바의 정석 이후에는 인프런 사이트에서 스프링 강의를 들을 예정이고, 그 이후에 시간이 남는다면 토이 프로젝트도 진행해 보고 싶다.

0개의 댓글