전체 글 342

[백준] 11123번

끝까지 전부 순회하면서 양이 몇 무리 있는지를 세야하는 문제라 DFS로 풀었다. 다른 문제들과는 달리 map이 숫자로 이루어진 게 아니라, 문자로 이루어져있기 때문에 boolean 으로 2차원 배열을 만들어줬다. dfs를 돌면서 상하좌우를 살필 때, 경계 조건을 잘 설정하지 않으면 ArrayIndexOutOfBoundsException이 발생하니 주의해야 한다. 처음에는 BFS, DFS를 이해하는 게 정말 어려웠는데, 기초 문제부터 하나씩 풀다보니까 슬슬 감이 잡히는 것 같다. BFS, DFS.. 좋아지기.. 시작.. public class Main { static boolean[][] map; static boolean[][] check; static StringBuilder sb = new Strin..

[백준] 1817번

아ㅏㅏㅏㅏㅏㅏㅏ주 그냥 허를 찌르는 문제를 만났다. 제출하면 자꾸 NPE가 발생하는데, 도대체 어디서 발생하는 건지 알 수가 없었다. 하지만 문제를 똑바로 읽지 않은 나의 실수였으니... 첫 번째, N이 0보다 크거나 '같고'.. 같다는 가정을 하지 않았다. 그래서 N이 0일 경우에는 0을 반환하도록 만들었지만 여전히 NPE는 발생했다. 두 번째, 다시 문제를 자세히 살펴보니 'N이 0보다 큰 경우에' 무게가 주어진다고 했다. 설마 N이 0이면 아예 둘째 줄에 추가 정보가 들어오지 않나?? 하고 0을 반환하는 코드를 StringTokenizer를 받기 전으로 옮기니까 통과했다. 제출 코드 public class Main { public static void main(String[] args) throws..

함수형 인터페이스 - Supplier와 Consumer

프로젝트에서 작성한 코드를 리팩토링할 방법을 찾다가 Supplier와 Consumer라는 함수형 인터페이스를 찾게 되었다. 함수형 인터페이스(Functional Interface)는 단일 추상 메서드를 가지고 있는 인터페이스로, 람다식이나 메서드 참조를 활용해서 함수형 프로그래밍을 지원한다. Supplier Supplier는 매개변수가 없고 값을 반환한다. get() 메서드를 호출해서 값을 생성하거나 가져올 수 있다. 일반적으로는 데이터를 생성하거나 외부에서 값을 가져오는 용도로 사용하며, 'Supplier 변수명'으로 선언하고 그에 따른 람다식을 작성하면 된다. 예를 들어, Supplier는 정수 값을 생성하고 Supplier은 문자열 값을 가져올 수 있다. Consumer Consumer는 매개변수를..

개발 일지/Java 2023.06.24

REST API 의 GET 요청에는 Request Body를 넣을 수 있을까?

REST API의 GET 요청은 서버로부터 리소스를 조회하거나 검색하기 위해 사용되며, 보통은 요청 매개변수(query parameters)를 사용해서 필요한 데이터를 전달하거나 URL 경로의 특정 부분에 /{id}와 같이 변수를 넣어서 사용한다. 그렇다면 과연 GET 요청에 Request Body를 포함해서 요청을 보낼 수 있을까? 결론부터 얘기하면 HTTP 표준은 GET요청에 Request Body(요청 본문)를 포함할 수 있도록 허용한다. 하지만 GET 요청은 서버로부터 정보를 요청하고 응답을 받는 것에 중점을 두기 때문에, 요청 본문에 데이터를 담는 것은 권장되지 않는 방법이라고 한다. GET 요청에 Request Body를 넣는 것이 권장되지 않는 이유는 다음과 같다. 캐싱 : GET 요청은 캐..

개발 일지/CS 2023.06.22

[백준] 1764번

기존에 풀었던 방식은 HashMap에 먼저 '듣도 못한 사람'을 모두 넣어둔 다음, '보도 못한 사람'을 map에 넣어주면서 만약 map에 해당 키가 있으면 value를 증가시켜서 중복 검사를 했었다. 이렇게 중복된 애들을 ArrayList에 넣고 sort 함수로 정렬해서 return. 후에 자료구조를 공부하다 TreeSet을 사용하면 어떨까 생각이 들어 다시 풀어봤다. 그러면 sort 함수를 사용할 필요도 없고 애초에 '듣도 못한 사람'을 모두 HashSet에 넣어둔 다음, '보도 못한 사람'들을 입력하면서 조건문을 통해 TreeSet에 넣어주면 자동으로 오름차순 정렬되니까 바로 return 하면 되지 않을까? 맨처음 풀었던 HashMap + ArrayList + sort() 방식 public clas..

DIP에 나오는 저수준 모듈 / 고수준 모듈의 의미

자바를 통해 개발 공부를 진행하고 있지만, 정작 가장 중요한 객체지향의 5대 원칙에 대해서 이해하고 프로젝트에 적용하고 있는가?라는 의문이 들었다. 그래서 객체지향 5대 원칙(SOLID)을 다시 공부하던 도중, 의존관계 역전 원칙에서 고수준 모듈과 저수준 모듈이 나오는데, 정확한 의미가 무엇인지 궁금하여 찾아보았다. 의존 역전 원칙 (Dependency Inversion Principle) - 고수준 모듈은 저수준 모듈의 구현에 의존해서는 안된다. 우선 저 말을 내가 이해하는 말로 다시 쓰면, '추상화에 의존해야지 구체화에 의존하면 안된다'라는 의미이다. 저수준 모듈은 고수준 모듈이 정의한 추상 타입에 의존해야 한다는 것이다. 고수준 모듈과 저수준 모듈이 뭔데..? 고/저는 무엇을 기준으로 나뉘는 거지...

개발 일지/Java 2023.06.12

[백준] 5430번

기존에 직접 LinkedList를 만들어서 (삽입, 수정이 빈번하게 발생하므로) 로직을 수행하게 만들었다. 테스트케이스를 입력해서 실행했을 때 결과는 잘 나오지만 결과는 시간초과.. 시간 복잡도를 고려했을 때 왜 시간 초과가 발생하는 지 알 수가 없었다. 다른 분의 블로그를 참고해보니 배열을 뒤집는 과정에서 시간 초과가 발생했을 것이라고 하셨다. 이 분은 Deque를 활용하셨는데 생각해보니 배열을 뒤집을 필요 없이 R 키워드가 주어지면 왼쪽에서부터 or 오른쪽에서부터만 결정하면 되는 것이었다. 이해하기 쉽게 설명해 주셔서 자주 보는 블로그인데 이번에도 역시.. 또 하나를 배워간다. 데큐 메모 [백준] 5430번 : AC - JAVA [자바] www.acmicpc.net/problem/5430 5430번:..

토스 SLASH 23 개발자 컨퍼런스 후기

처음으로 개발자 컨퍼런스 라는 것을 경험해 봤다. 이번 컨퍼런스를 보면서 토스 개발자분들이 구현하는 것을 넘어서 최고의 사용자 경험을 위해서 고민하는 모습이 인상 깊었다. 아직 의욕만 앞서긴 하지만, 나름 프로젝트를 진행하면서 코드를 더 효율적으로 구현하고 실제 사용자가 서비스를 사용한다면 어떨까 라는 생각을 지속적으로 했던 나에게는 모니터에서 빛이 나지 않을 수가 없었다. (열심히 공부하겠읍니다..) 세션은 A, B로 나눠서 같은 시간대에 진행됐고 A 세션은 Frontend, DevOps, Core Banking에 관련된 내용들이 구성되어 있었고 B 세션은 Server와 관련된 내용들로 구성되어 있었다. 컨퍼런스는 이틀 동안 진행되고 내일도 마찬가지로 세션 A와 B로 나뉘지만 내용이 iOS, Andro..

Controller 내부 API 요청 메소드에 트랜잭션 적용

위 코드는 기존에 작성되었던 코드이다. 컨트롤러 내부에서 dto를 엔티티 객체로 변환하고 변환된 객체를 service 로직에서 사용하고 있다. 이렇게 쿼리가 실행된다면 발생하는 문제점이 데이터의 안전성이 보장되지 않는다는 것이다. 예를 들어, service 클래스의 createCv가 실행되어 새로운 Cv가 생성되고 repository에 저장되었는데 아래 injectLowDomain에서 실패하게 되면 작업은 종료되어 적절한 응답을 주지 못했지만 저장소에는 새로운 Cv가 있을 것이다. 즉, 데이터의 일관성을 보장하기 위한 작업이 필요했고 helper라는 클래스를 만들어서 트랜잭션을 적용시켜줬다. 트랜잭션은 한 번에 실행되어야 하는 일련의 연산들을 모아놓은 것이다. 예를 들어, 여러 개의 작업이 실행되는 경우..

String concatenation as argument to 'StringBuilder.append()' call

인텔리제이로 알고리즘 문제를 풀던 도중 index 라는 변수를 줄 별로 출력하기 위해 다음과 같이 코드를 작성하니까 노란 밑줄이 생겼다. 인텔리제이가 다음과 같이 친절하게 교체할 것을 권장하면서 이유를 말해줬다. 두 코드는 사실 동일한 결과를 만들어준다. 하지만 수정된 코드를 권장하는 이유는 해당 방법이 성능 면에서 더 효율적이기 때문이다. sb.append(index + "\n"); 는 index 와 "\n"을 연결한 후에 그 결과를 StringBuilder에 추가한다. 따라서 연결하는 과정에서 연결 연산자인 '+' 를 사용하여 작업을 수행한다. 하지만 sb.append(index).append("\n"); 는 index를 StringBuilder에 추가한 다음 "\n" 문자열을 주가한다. 따라서 중간..

개발 일지/Java 2023.06.04