glenn-syj / more-effective-java

이펙티브 자바를 읽으며 자바를 더 효율적으로 공부합니다
4 stars 5 forks source link

[MEJ-012] 부정확한 메서드 참조 조건과 제네릭 메서드 #210

Open FickleBoBo opened 3 months ago

FickleBoBo commented 3 months ago

Based on : #206 by @undeadtimo


이전 이슈에 대한 추가적인 심화탐구까지 진행해주시면서 다양한 자료를 찾아주시느라 고생 많으셨습니다.

이슈를 작성하면서 테스트 예시가 잘 작성된 것일까 고민이 많았는데 부정확한 메서드 참조의 예시를 통해 문제점을 찾아나가는 방향성을 잡는데 많은 도움이 된 것 같습니다. println 메서드는 메서드 오버로딩이 근본적인 원인이었는데 이를 파악하지 못하고 다른 예시들로 문제점을 찾으려고 해서 문제가 있었던 것 같습니다.

부정확한 메서드 참조의 4가지 조건을 보며 myPrint1이 Callable로 형변환 될 수 없는 이유는 잘 이해가 된 것 같습니다.

myPrint2 ~ 4까지는 부정확한 메서드 참조의 4가지 조건에 모두 해당되지 않아서 따로 형변환을 하지 않아도 에러가 발생하지 않은 것을 기본은 Callable로 해석되는데 Runnable로 형변환하면 반환값을 무시해서 출력은 잘되고 에러가 발생하지 않은 것으로 이해했습니다.(Runnable로 형변환이 가능한 이유는 ChatGPT의 답변을 참고해서 이해했습니다.)

다만 myPrint5의 경우 제네릭 메서드라서 부정확한 메서드 참조 4번 조건에 따라 TypeArgument를 제공하는 방식으로 해결하려고

// 기존 코드
exec.submit(Main::myPrint5);    // 빨간줄O

// 제네릭 타입 표시
exec.submit(Main::<Void>myPrint5);    // 빨간줄X

// 제네릭 타입 표시 + Callable로 타입 캐스팅
exec.submit((Callable<Void>) Main::<Void>myPrint5);    //  인텔리제이가 Callble<Void>와 <Void>를 쓸 필요가 없다고 추천하는데 없애고 실행하면 ambiguous 뜸

위와 같이 제네릭을 붙여줬는데 기존에 빨간줄은 붙이면서 사라졌지만 실행시 여전히 ambiguous라는 에러 문구가 발생했습니다. 최대한 Type Argument를 붙여서 해결하는 방식으로 코드를 작성해보려했는데 안돼서 웬만하면 그냥 명시적 형변환을 하는 것이 좋겠다고 결론을 내게 됐는데 @undeadtimo 님은 제네릭 메서드의 메서드 참조에 대해 어떻게 생각하시나요?


undeadtimo commented 2 months ago
// 제네릭 타입 표시
exec.submit(Main::<Void>myPrint5);

공식문서를 통해 이해한 바로는 Argument Type을 지정함으로써 Generic에 대한 혼동이 제거되어 위 코드가 정상적으로 실행되어야 하지만, 실행되지 않는 이유를 결국 찾지 못했습니다. 이 의문에 대해서는 계속해서 조사하면서 찾아보도록 하겠습니다.

아무래도 메서드 참조식을 사용할 때의 로직에 문제점이 있어서 발생하는 것 같으니 이러한 오류를 방지하기 위해서 람다식을 사용하거나 명시적 형변환을 사용해야 할 것 같습니다.