toString() 메서드가 나올 경우

assertThat(obejct.toString()).isEqualTo("\"value\""); 위의 코드는 아래의 방식으로 바꿀 수 있다. assertThat(obejct).hasToString(expectedString)

2024-09-15 · 1 min · 9 words

ThreadLocal

배경 ThreadLocal 의 용도와 동작 방식을 알아본다. ThreadLocal이란? 하나의 스레드에서 고유하고 독립적인 변수를 갖게 해주는 클래스다. 스레드가 사라진 뒤에 해당 변수는 GC 대상이 된다. get(), set(), remove() 메서드만 존재하는 단순한 구조다. 예를 들어 스레드 마다 고유한 id를 생성하기 위해서 아래와 같이 사용할 수 있다. public class ThreadId { // Atomic integer containing the next thread ID to be assigned private static final AtomicInteger nextId = new AtomicInteger(0); // Thread local variable containing each thread's ID private static final ThreadLocal<Integer> threadId = new ThreadLocal<Integer>() { @Override protected Integer initialValue() { return nextId....

2024-09-15 · 1 min · 116 words

Thread pool 생성

배경 Executors.newFixedThreadPool(10)의 의미를 알아본다. Executors.newFixedThreadPool() 고정된 개수의 스레드를 가지는 스레드풀을 생성한다. 반환 값은 ExecutorService이다. ExecutorService executor = Executors.newFixedThreadPool(10); ExecutorService ExecutorService는 인터페이스이며, execute() 메서드를 통해 파라미터로 Callable이나 Runnable을 넘겨주면 스레드풀에서 해당 작업을 할당해 실행해준다. executorService.execute(runnableTask); ExecutorService는 수동으로 소멸시켜줘야된다. shutdown() 메소드는 즉시 소멸되지 않고, 현재 실행 중인 스레드가 모드 완료되고 소멸된다. shutdownNow(): 현재 실행중인 스레드들을 즉시 멈추고 소멸시킨다. 또한, 실행 중이던 작업들을 반환한다. executorService.shutdown(); List<Runnable> notExecutedTasks = executorService.shutDownNow(); 참고 자료 https://www.baeldung.com/java-executor-service-tutorial

2024-09-15 · 1 min · 69 words

System out print() 테스트하기

System.setOut() 메소드를 통해서 시스템의 기본 출력을 설정할 수 있다. private ByteArrayOutputStream byteArrayOutputStream; @BeforeEach void setUp() { byteArrayOutputStream = new ByteArrayOutputStream(); System.setOut(new PrintStream(byteArrayOutputStream)); } @Test public void out() { System.out.print("hello"); assertEquals("hello", byteArrayOutputStream.toString()); } 참고 자료 https://stackoverflow.com/questions/1119385/junit-test-for-system-out-println

2024-09-15 · 1 min · 35 words

String의 hashCode()

Java의 String의 hashCode() 메소드는 같은 문자열이면 같은 값이 나온다. 하지만 반환값이 int기 때문에 오버플로우가 발생해서 음수가 나올 수 있다는 것도 충분히 고려해야된다. 만약 String의 hashCode를 이용해서 추가적인 작업을하는데 0부터 시작하길 원한다면 아래처럼 구현하면 된다. long avatarIndex = ((long) nickname.hashCode() - Integer.MIN_VALUE) % NUMBER_OF_AVATAR;

2024-09-15 · 1 min · 43 words

String을 뒤집는 방법

StringBuilder에 reverse 기능이 존재한다. String reversed = new StringBuilder(original).reverse().toString() 참고 자료 https://stackoverflow.com/questions/7569335/reverse-a-string-in-java

2024-09-15 · 1 min · 12 words

String을 LocalDate로 변환하기

DateTimeFormatter 로 문자열의 날짜 형식을 지정하고 파싱하면된다. DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d/MM/yyyy"); String date = "16/08/2016"; //convert String to LocalDate LocalDate localDate = LocalDate.parse(date, formatter); 참고 자료 https://mkyong.com/java8/java-8-how-to-convert-string-to-localdate/

2024-09-15 · 1 min · 27 words

String으로 원하는 Enum 찾기

Enum에 valueOf() 메서드를 이용하면 된다. 참고 자료 https://stackoverflow.com/questions/604424/how-to-get-an-enum-value-from-a-string-value-in-java

2024-09-15 · 1 min · 8 words

String안에 특정 문자의 마지막 인덱스 찾기

abc.txt.jpg 같은 파일이름을 파싱할 때, 확장자를 jpg로 구하기 위해서 ‘.‘문자의 마지막 인덱스 위치를 알아야 됐다. fileName.lastIndexOf(FILE_EXTENSION_DELIMITER); Java에 String의 메소드로 lastIndexOf라는 메소드가 있어서 쉽게 구현할 수 있었다.

2024-09-15 · 1 min · 26 words

Stream을 collection으로 만든 후 추가 적인 작업이 필요한 경우

passengers.stream() .map(name -> new Person(name)) .collect(Collectors.collectingAndThen(Collectors.toList(), Bus::new)); collectingAndThen()메소드를 활용하면 된다. 참고 자료 https://stackoverflow.com/questions/52382157/continue-mapping-after-stream-collect

2024-09-15 · 1 min · 13 words

stream에서 findFirst(), findAny() 사용시 NPE

배경 null 값을 가지고 있는 stream에서 findFirst() 메서드를 호출하니 NullPointerException이 발생했다. 원인 공식 문서를 읽어보니 선택된 요소가 null이면 NullPointerException이 발생한다. 비어있는 Optional이 반환되는 경우는 stream이 비어있는 경우만 해당된다. 참고 자료 https://docs.oracle.com/javase/10/docs/api/java/util/stream/Stream.html#findFirst()

2024-09-15 · 1 min · 31 words

Stream groupingBy

어떤 객체의 List가 있을 때, 객체의 특정 필드값을 기준으로 묶는 과정이 필요했다. 그 때, stream의 groupingBy 을 사용하면된다. 예를들어, 블로그 포스트를 타입별로 묶고싶은 경우 아래 예시를 보면된다. class BlogPost { String title; String author; BlogPostType type; int likes; } enum BlogPostType { NEWS, REVIEW, GUIDE } Map<BlogPostType, List<BlogPost>> postsPerType = posts.stream() .collect(groupingBy(BlogPost::getType)); 참고 자료 https://www.baeldung.com/java-groupingby-collector

2024-09-15 · 1 min · 55 words

Progressive JPEG 파일 저장

https://www.notion.so/85433ee030e7453b86ef84f399faa415 여기에서 이어지는 내용이다. JPEG파일을 Progressive JPEG로 저장되도록 구현하려고 했다. ImageWriter imageWriter = ImageIO.getImageWritersByFormatName("jpg").next(); JPEGImageWriteParam imageWriteParam = new JPEGImageWriteParam(null); imageWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); imageWriteParam.setCompressionQuality(0.4f); imageWriteParam.setProgressiveMode(ImageWriteParam.MODE_DEFAULT); imageWriter.setOutput(imageOutputStream); image = ImageIO.read(file); IIOImage iioImage = new IIOImage(image, null, null); imageWriter.write(null, iioImage, imageWriteParam); 위 코드와 같이 setProgressiveMode() 메서드를 사용하면 쉽게 설정이 가능하다. 참고 자료 https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=kkforgg&logNo=221499435383 https://stackoverflow.com/questions/34178759/how-to-use-cfimage-to-save-image-as-progressive-jpg

2024-09-15 · 1 min · 49 words

PriorityQueue에 이미 추가된 객체의 값을 수정하기

결론부터 생각해보면 당연하지만 코딩테스트 문제를 풀다가 실수한 내용이라 기록해본다. 이미 PriorityQueue에 추가된 값을 수정해도, 자동으로 heapify가 진행되지 않는다. 어떻게 해결했는가 PriorityQueue에 있는 값을 계속해서 수정해야 되는 경우가 있어서 soft delete 방법을 응용해서 해결했다. 값을 수정해야 되는 객체를 soft delete 시킨다. 해당 객체에서 값을 수정한 결과를 새로 인스턴스로 만들어 PriorityQueue에 추가한다. PriorityQueue에서 pop했을 때, deleted된 객체는 무시해버린다. 참고 자료 https://stackoverflow.com/questions/1871253/updating-java-priorityqueue-when-its-elements-change-priority

2024-09-15 · 1 min · 59 words

Optional orElse() vs Optional orElseGet()

Optional<T> 기준으로 Optional.orElse()는 인자로 T 객체를 받고 orElseGet은 Supplier<? extends T> 를 받는다. orElse에 메소드를 넣어두면 null이든 아니든 항상 실행되고 orElseGet은 null일 경우에만 실행된다. 함수를 호출해야 되는 경우에는 가능하면 orElseGet을 사용하는게 좋아보인다. // Always get heavy resource getResource(resourceId).orElse(getHeavyResource()); // Get heavy resource when required. getResource(resourceId).orElseGet(() -> getHeavyResource()) 참고 자료 https://stackoverflow.com/questions/33170109/difference-between-optional-orelse-and-optional-orelseget https://velog.io/@joungeun/orElse-vs-orElseGet

2024-09-15 · 1 min · 51 words

Null 체크 메소드

Objects.isNull(shortestPath) 로 객체가 null인지 true, false로 반환해준다.

2024-09-15 · 1 min · 7 words

NPE 발생시 StackTrace가 로깅되지 않는 이슈

배경 NPE가 발생하고 있는 이슈가 발생해서 로그를 확인하니, 아래와 같이 로그가 남아있고 stack trace가 로깅되어 있지 않았다. java.lang.NullPointerException 원인 JVM에서 최초로 발생하는 예외를 출력하고, 이를 기억해뒀다가 자주 발생하는 것이 확인되면 더 이상 stack trace는 출력하지 하지않도록 최적화가 이루어지고 있다. 이를 기능을 사용하지 않고, 항상 stack trace를 출력하려면 아래와 같이 JVM 옵션을 추가해야된다. -XX:-OmitStackTraceInFastThrow 참고 자료 https://stackoverflow.com/questions/2411487/nullpointerexception-in-java-with-no-stacktrace

2024-09-15 · 1 min · 56 words

Map에서 get 호출시 NPE

배경 map.get(null)을 호출하면 NPE가 발생할 것으로 예측했는데 발생하지 않았다. NPE가 발생하지 않는 이유를 이해한다. Map 인터페이스 get() 메서드 호출시 파라미터가 null이면 NPE가 발생한다고 명시되어 있다. HashMap 하지만 HashMap은 Map 인터페이스의 구현체임에도 key가 null인 경우를 허용하고 있어, get() 메서드 호출 시 null을 넘길 수 있다. TreeMap Map의 또 다른 구현체인 TreeMap의 경우는 null을 넘기면 NPE가 발생한다. 참고 자료 https://www.baeldung.com/java-treemap-vs-hashmap

2024-09-15 · 1 min · 58 words

Lombok

롬복을 통해 쉽게 생성자, getter, setter, 빌드 패턴이 구현된다. @Builder @Getter @AllArgsConstructor @NoArgsConstructor @Entity public class Game { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @NonNull private String name; } access 속성으로 접근 제어자 지정할 수 있다. @AllArgsConstructor @NoArgsConstructor(access = AccessLevel.PROTECTED)

2024-09-15 · 1 min · 41 words

log4j vs logback vs log4j2

Java 진영의 대표적인 로깅 프레임워크 log4j, logback, log4j2를 비교해보고자 한다. log4j 가장 오래된 로깅 프레임워크이다. 하지만 그만큼 몇 년 동안 가장 인기있는 프레임워기도하다. 최근에 나온 로깅 프레임워크도 log4j의 계층적 로그 레벨과 로거 같은 개념을 사용하고 있다. 하지만, log4j는 2015년에 개발이 종료되었다. 새로운 프로젝트에서는 해당 프레임워크를 사용하는 것을 권장하지 않는다. logback log4j의 후계자로 log4j와 같은 개발자가 만들었다. log4j와 전체적으로 동일한 개념을 사용하지만 성능이 개선되고 고급 필터링 및 설정 등을 제공하고 있다....

2024-09-15 · 1 min · 108 words