본문 바로가기
Blog/TIL

[240526] API 개발하기

by 코젼 2024. 5. 26.
728x90
반응형

🔶Stream

🔶코딩테스트

🔶CS 기초 복습

🔶Annotation


목차

    / 오늘의 TIL /


    Stream

    range vs rangeClosed

    range rangeClosed
    • startInclusive: 시작값(포함).
    • endExclusive: 끝값(포함하지 않음).
    • 즉, 시작값은 포함되지만 끝값은 포함되지 않는 스트림을 생성합니다.
    • startInclusive: 시작값(포함).
    • endInclusive: 끝값(포함).
    • 즉, 시작값과 끝값이 모두 포함되는 스트림을
      생성합니다.
    //fail이 int[]일 경우 처리 방식
    
    int[] nums = IntStream.range(0, fail.length) //0~fail.length-1 stream 생성
            .map(i -> Arrays.stream(fail, i, fail.length).sum()) //fail 배열의 i~fail.length 까지의 부분 배열 stream 만든 후 합계 반환
            .toArray(); //int[]로 변환

    Map key, value로 각각 내림차순, 오름차순을 진행할 수도 있다.

    더보기

    참고 문제 https://school.programmers.co.kr/learn/courses/30/lessons/42889

    import java.util.HashMap;
    
    public class Solution {
        /**
         * @param N 스테이지의 개수
         * @param stages 게임을 이용하는 사용자가 현재 멈춰있는 스테이지의 번호가 담긴 배열
         * @return 실패율이 높은 스테이지부터 내림차순으로 스테이지의 번호가 담겨있는 배열
         *
         * 시간복잡도: N^2 불가 (stages)
         * 실패율: 스테이지에 도달했으나 아직 클리어하지 못한 플레이어의 수 / 스테이지에 도달한 플레이어 수
         * 실패율이 같은 스테이지: 작은 번호의 스테이지가 먼저 오도록 작성
         * 스테이지에 도달한 유저가 없는 경우 실패율: 0
         *
         * 인원 수, 실패율을 저장할 배열 생성
         * 인덱스에 따라 인원 수가 달라지므로 반복문 진행
         * 실패율을 구하고 나면 배열에 그대로 담는다.
         * Comparator를 통해 내림차순으로 정렬하고, 동일한 경우는 스테이지 번호 오름차순으로 정렬한다.
         * int[] 로 반환한다.
         */
        public static int[] solution(int N, int[] stages) {
    
            //인원 수
            int[] challenger = new int[N+2];
            //각 스테이지 별 인원 수 구하기
            for (int stage : stages) challenger[stage]++;
    
            //스테이지 번호, 실패율
            HashMap<Integer, Double> fails = new HashMap<>();
            double total = stages.length;
    
            //실패율 계산
            for (int i=1; i<=N; i++) {
                if (challenger[i] == 0) { //도전한 사람이 없는 경우
                    fails.put(i, 0.); //실패율은 0
                } else {
                    fails.put(i, challenger[i] / total); //실패율
                    total -= challenger[i]; //현재 스테이지 인원 수 제거
                }
            }
    
            //실패율 내림차순, 동일할 경우 스테이지 오름차순
            //entrySet에는 key, value값이 있다.
            return fails.entrySet().stream()
                    .sorted(((o1, o2) -> Double.compare(o2.getValue(), o1.getValue()))) //value(실패율) 내림차순 정렬
                    .mapToInt(HashMap.Entry::getKey).toArray(); //key(스테이지) 오름차순 정렬 후, 정수 배열로 변환
        }
    
        public static void main(String[] args) {
            int[] a = {2, 1, 2, 6, 2, 4, 3, 3};
            solution(5, a);
        }
    }
    

     


    코딩테스트

    명령어에 따른 좌표 이동, 중복되지 않는 경로 개수 구하기

    https://school.programmers.co.kr/learn/courses/30/lessons/49994

     

    힌트

    음수 좌표인 경우 원점을 (0, 0) -> (0+n, 0+n) 양수 좌표로 수정해서 탐색할 수 있다.

    해당 좌표가 유효한 좌표인지 검증한다.

    HashSet을 사용하면 중복 경로를 제외하고 값을 구할 수 있다.

    방향성이 있는지 없는지 확인을 해야한다.

    A 값에 따라 방향성이 정해진다면 HashMap으로 구현할 수 있다.

    좌표를 이동하고 난 후, 좌표 업데이트를 해준다.

    * 코드

    더보기
    import java.util.HashMap;
    import java.util.HashSet;
    
    public class Solution {
        // 좌표평면을 벗어나는지 체크하는 메서드
        private static boolean isValidMove(int nx, int ny) {
            //0~10까지의 범위 (음수 좌표때문에 원점 (0,0) -> (5,5) 변경)
            return 0 <= nx && nx < 11 && 0 <= ny && ny < 11;
        }
    
        //좌표 결졍을 위한 해시맵 생성
        private static final HashMap<Character, int[]> location = new HashMap<>();
    
        private static void initLocation() {
            location.put('U', new int[]{0, 1});
            location.put('D', new int[]{0, -1});
            location.put('L', new int[]{-1, 0});
            location.put('R', new int[]{1, 0});
        }
    
        /**
         * @param dirs 명령어
         * @return 처음 걸어본 길의 길이
         *
         * 중복 포함 X -> HashSet 이용
         */
        public static int solution(String dirs) {
    
            initLocation(); //좌표 객체 생성
            int x = 5, y = 5; //원점
            HashSet<String> answer = new HashSet<>(); //중복 좌표 처리 X
    
            //주어진 명령어로 움직이면서 좌표 지정
            for (int i=0; i<dirs.length(); i++) {
                int[] offset = location.get(dirs.charAt(i)); //명령어로 인한 좌표 이동 값
                int nx = x + offset[0];
                int ny = y + offset[1];
    
                //유효한 좌표값인 경우만 이동 가능하다.
                if (!isValidMove(nx, ny)) continue;
    
                //(5, 6) == (6, 5)은 동일한 경로이므로 좌표를 추가해준다.
                answer.add(x + " " + y + " " + nx + " " + ny); //(x, y) -> (nx, ny)
                answer.add(nx + " " + ny + " " + x + " " + y); //(nx, ny) -> (x, y)
    
                //좌표 이동 값으로 좌표 업데이트
                x = nx;
                y = ny;
            }
            return answer.size() / 2;
        }
    
        public static void main(String[] args) {
            solution("ULURRDLLU");
        }
    }
    

     


    CS 기초 복습

    • Server: '기능'을 제공해주는 것. 컴퓨터 자체를 말하기도 한다.
    • 라이브러리 vs 프레임워크
      • 라이브러리: 특정 기능을 수행하기 위한 코드의 모음. 제어 흐름은 개발자가 관리한다.
        ex) 김치를 먹고싶을 때, 마트에서 김치를 사서 먹는다(라이브러리 O) / 배추 농사를 짓는다(라이브러리 X)
      • 프레임워크: 소프트웨어 개발을 위한 구조와 기본적인 코드 흐름을 제공하고, 개발자가 구조 내에서 필요한 부분을 구현한다. 제어 흐름은 프레임워크가 관리한다.
        ex) 김치찌개를 만들 때, 밀키트를 사용하고 재료를 추가한다(프레임워크 O) / 하나씩 레시피를 보면서 만든다(프레임워크 X)
    • DNS: Domain Name System. 도메인 이름과 IP 주소 간의 변환을 제공하는 인터넷 서비스이다.
    • HTTP Method
      • GET: query를 통해 데이터를 받는다.
        • @RequestParam
        • @RestController 덕분에 객체를 반환할 때, 컬럼들의 `getter`가 있다면 스프링이 HTTP Bod에 JSON로 변환해준다.
      • POST: HTTP Body를 통해 데이터를 주고 받는다. (JSON)
        • @RequestBody
        • DTO에 List 객체가 있을 경우, JSON의 배열이 담긴다.

    Annoation

    어노테이션을 사용하는 이유

    1. 코드의 가독성 및 명확성 향상

    • 코드의 의미와 의도를 명확하게 전달할 수 있다.
    • 예시로 @Override는 부모에서 정의한 메서드를 오버라이딩한다는 것을 명확하게 나타낸다.

    2. 메타데이터 제공

    • 클래스, 메서드, 변수 등에 추가적인 정보를 제공한다.
    • 예시로 @Deprecated를 사용할 경우 프로그래밍에서 사용되지 않거나 더이상 추천되지 않는 요소로 판별됩니다.
      @Deprecated를 사용하면 해당 요소를 사용할 때 컴파일러가 경고를 표시해줘서 유지보수하기 용이해진다.
      이전 버전의 API를 호환성을 유지하면서 새로운 버전으로 업데이트 할 수 있다.

    3. 코드 검증 및 유효성 검사

    • Bean Validation API에서 @NotNull, @Size 등으로 입력값의 유효성을 검사할 수 있다.

    4. 컴파일러 지시

    • @SuppressWarnings은 컴파일러에게 특정 경고를 무시하도록 지시한다. 
      unchecked(타입 안정성이 보장되지 않는 경우), deprecation(deprecated 메서드, 클래스 사용하는 경우), rawtypes(제네릭 타입을 지정하지 않은 경우) 등 옵션을 사용할 수 있다.

    5. 프레임워크 통합

    • Spring Framework에서 @Autowired를 통해 의존성 주입을 간단하게 처리할 수 있다.
    • 어노테이션을 활용하여 설정을 단순화하고 코드 구성을 돕는다.

    6. 런타임 처리

    • 런타임에 리플렉션을 통해 메타데이터를 읽고 처리할 수 있게 한다.
      리플렉션: 프로그램이 실행되는 동안에 자신의 구조를 검사하고 수정할 수 있는 능력
      -> 사용자 시점에 사용자 어노테이션 정보를 읽고 처리하기 (메서드명, 값 등을 빼낼 수 있다.)
    • 동적 프록시 생성, AOP(Aspect-Oriented Programming) 구현 등 다양한 응용 프로그램에서 유용하다.
    • 추가 공부 필요...

    사용자 어노테이션을 만드는 방법

    어노테이션은 메타데이터를 제공하는 인터페이스의 일종이기 때문에 메타 어노테이션도 추가로 작성해야 한다.

    • 어노테이션 정의: @interface
    • 메타 어노테이션
      • @Retention: 어노테이션 유지 기간 설정 (RUNTIME, CLASS, SOURCE)
      • @Target: 어노테이션 적용될 요소 지정 (TYPE, METHOD, FIELD...)

    어노테이션 정의

    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    // 애노테이션이 런타임까지 유지됨을 명시
    @Retention(RetentionPolicy.RUNTIME)
    // 애노테이션이 메서드에만 적용될 수 있음을 명시
    @Target(ElementType.METHOD)
    public @interface MyCustomAnnotation {
        String value(); // 애노테이션의 요소 정의
    }

    어노테이션 사용

    value: 어노테이션 속성으로, 해당 값을 지정하여 메타 데이터로 사용할 수 있다.

    public class MyClass {
    
        @MyCustomAnnotation(value = "Example value")
        public void myMethod() {
            System.out.println("My method is called");
        }
    }

    리플렉션을 사용하여 어노테이션 처리

    import java.lang.reflect.Method;
    
    public class AnnotationProcessor {
    
        public static void main(String[] args) {
            try {
                // MyClass의 클래스 객체를 가져옴
                Class<?> clazz = MyClass.class;
    
                // 클래스의 모든 메서드를 가져옴
                Method[] methods = clazz.getDeclaredMethods();
    
                // 각 메서드에 대해
                for (Method method : methods) {
                    // MyCustomAnnotation이 있는지 확인
                    if (method.isAnnotationPresent(MyCustomAnnotation.class)) {
                        // MyCustomAnnotation 객체를 가져옴
                        MyCustomAnnotation annotation = method.getAnnotation(MyCustomAnnotation.class);
                        // 애노테이션의 값 출력
                        System.out.println("Method: " + method.getName() + ", Value: " + annotation.value());
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    728x90
    반응형

    'Blog > TIL' 카테고리의 다른 글

    [240528] 백문이 불여일타!  (0) 2024.05.28
    [240527] 코딩테스트 다다익선  (0) 2024.05.27
    [240524] 수학 지식을 넓히자  (0) 2024.05.24
    [240523] 배워도 배워도 끝이 없네  (0) 2024.05.23
    [240522] 드디어 JPA를 접하다  (0) 2024.05.22

    댓글