프로젝트에서 우리는 Java 8로 마이그레이션하고 있으며 새로운 기능을 테스트하고 있습니다.
내 프로젝트에서 Guava 술어와 함수를 사용하여 Collections2.transform
및을 사용하여 일부 컬렉션을 필터링하고 변환 하고 Collections2.filter
있습니다.
이 마이그레이션에서 예를 들어 구아바 코드를 Java 8 변경으로 변경해야합니다. 그래서 제가하고있는 변화는 다음과 같습니다.
List<Integer> naturals = Lists.newArrayList(1,2,3,4,5,6,7,8,9,10,11,12,13);
Function <Integer, Integer> duplicate = new Function<Integer, Integer>(){
@Override
public Integer apply(Integer n)
{
return n * 2;
}
};
Collection result = Collections2.transform(naturals, duplicate);
에…
List<Integer> result2 = naturals.stream()
.map(n -> n * 2)
.collect(Collectors.toList());
구아바를 사용하여 각 변환 프로세스를 디버깅 할 수 있었기 때문에 코드 디버깅이 매우 편리했지만 예를 들어 디버깅 방법이 우려 .map(n -> n*2)
됩니다.
디버거를 사용하면 다음과 같은 코드를 볼 수 있습니다.
@Hidden
@DontInline
/** Interpretively invoke this form on the given arguments. */
Object interpretWithArguments(Object... argumentValues) throws Throwable {
if (TRACE_INTERPRETER)
return interpretWithArgumentsTracing(argumentValues);
checkInvocationCounter();
assert(arityCheck(argumentValues));
Object[] values = Arrays.copyOf(argumentValues, names.length);
for (int i = argumentValues.length; i < values.length; i++) {
values[i] = interpretName(names[i], values);
}
return (result < 0) ? null : values[result];
}
그러나 코드를 디버깅하는 것은 Guava만큼 어렵지 않습니다. 실제로 n * 2
변환을 찾을 수 없습니다 .
이 변환을 볼 수있는 방법이나이 코드를 쉽게 디버그 할 수있는 방법이 있습니까?
편집 : 다른 댓글에서 답변을 추가하고 답변을 게시했습니다.
Holger
내 질문에 답한 의견 덕분에 람다 블록을 사용하는 방법을 통해 변환 프로세스를보고 람다 본문 내부에서 발생한 일을 디버깅 할 수있었습니다.
.map(
n -> {
Integer nr = n * 2;
return nr;
}
)
Stuart Marks
메서드 참조를 갖는 접근 방식 덕분에 변환 프로세스를 디버깅 할 수도 있습니다.
static int timesTwo(int n) {
Integer result = n * 2;
return result;
}
...
List<Integer> result2 = naturals.stream()
.map(Java8Test::timesTwo)
.collect(Collectors.toList());
...
Marlon Bernardes
답변 덕분에 내 Eclipse 가해 야 할 내용을 표시하지 않고 peek () 사용이 결과를 표시하는 데 도움이된다는 것을 알았습니다.
답변
Eclipse 또는 IntelliJ IDEA를 사용하는 동안 일반적으로 람다 식을 디버깅하는 데 문제가 없습니다. 중단 점을 설정하고 전체 람다 식을 검사하지 않도록하십시오 (람다 본문 만 검사).
또 다른 접근 방식은 peek
스트림의 요소를 검사하는 데 사용 하는 것입니다.
List<Integer> naturals = Arrays.asList(1,2,3,4,5,6,7,8,9,10,11,12,13);
naturals.stream()
.map(n -> n * 2)
.peek(System.out::println)
.collect(Collectors.toList());
최신 정보:
나는 때문에 혼란스러워지고 있다고 생각 map
이다 intermediate operation
– 즉 : 그것은이 후에 만 실행됩니다 게으른 작업입니다 terminal operation
수행되었다. 따라서 stream.map(n -> n * 2)
람다 본문 을 호출 할 때 현재 실행되지 않습니다. 중단 점을 설정하고 터미널 작업이 호출 된 후 검사해야합니다 ( collect
이 경우).
자세한 설명은 스트림 작업 을 확인하십시오 .
업데이트 2 :
Holger의 의견을 인용하면 :
여기서 까다로운 것은 map 호출과 람다식이 한 줄에 있으므로 완전히 관련되지 않은 두 작업에서 줄 중단 점이 중지된다는 것입니다.
바로 뒤에 줄 바꿈을 삽입
map(
하면 람다 식에 대해서만 중단 점을 설정할 수 있습니다. 그리고 디버거가return
명령문의 중간 값을 표시하지 않는 것은 드문 일이 아닙니다 . 람다를로 변경하면n -> { int result=n * 2; return result; }
결과를 검사 할 수 있습니다. 다시 말하지만, 한 줄씩 이동할 때 줄 바꿈을 적절하게 삽입하십시오.
답변
IntelliJ에는이 경우 Java Stream Debugger 플러그인 과 같은 멋진 플러그인이 있습니다. 확인해야합니다 : https://plugins.jetbrains.com/plugin/9696-java-stream-debugger?platform=hootsuite
현재 스트림 체인 추적 버튼을 추가하여 IDEA 디버거 도구 창을 확장합니다.이 버튼은 디버거가 스트림 API 호출 체인 내에서 중지 될 때 활성화됩니다.
별도의 스트림 작업으로 작업하기위한 멋진 인터페이스가 있으며 디버그해야하는 일부 값을 따를 수있는 기회를 제공합니다.
여기를 클릭하여 디버그 창에서 수동으로 시작할 수 있습니다.
답변
람다 디버깅은 NetBeans에서도 잘 작동합니다. NetBeans 8 및 JDK 8u5를 사용하고 있습니다.
람다가있는 라인에 중단 점을 설정하면 실제로 파이프 라인이 설정 될 때 한 번 히트 한 다음 각 스트림 요소에 대해 한 번 히트합니다. 예제를 사용하면 중단 점에 처음 도달 map()
하면 스트림 파이프 라인을 설정 하는 호출이됩니다.
main
예상대로 호출 스택과 지역 변수 및 매개 변수 값을 볼 수 있습니다. 스텝핑을 계속하면 “동일한”중단 점이 다시 적중됩니다. 단, 이번에는 람다 호출 내에 있습니다.
이번에는 호출 스택이 스트림 기계 내에 깊숙이 있고 로컬 변수는 둘러싸는 main
메서드가 아니라 람다 자체의 로컬 입니다. ( naturals
이를 명확히하기 위해 목록 의 값을 변경했습니다 .)
마찬가지로 말론 Bernardes이 (+1)을 지적, 당신은 사용할 수 있습니다 peek
들이 파이프 라인에 의해 가서 값을 검사 할 수 있습니다. 병렬 스트림에서 이것을 사용하는 경우 조심하십시오. 값은 여러 스레드에서 예측할 수없는 순서로 인쇄 될 수 있습니다. 에서 디버깅 데이터 구조에 값을 저장하는 경우 peek
해당 데이터 구조는 물론 스레드로부터 안전해야합니다.
마지막으로 람다 (특히 여러 줄 문 람다) 디버깅을 많이 수행하는 경우 람다를 명명 된 메서드로 추출한 다음 메서드 참조를 사용하여 참조하는 것이 좋습니다. 예를 들면
static int timesTwo(int n) {
return n * 2;
}
public static void main(String[] args) {
List<Integer> naturals = Arrays.asList(3247,92837,123);
List<Integer> result =
naturals.stream()
.map(DebugLambda::timesTwo)
.collect(toList());
}
이렇게하면 디버깅하는 동안 무슨 일이 일어나고 있는지 더 쉽게 볼 수 있습니다. 또한이 방법으로 메서드를 추출하면 단위 테스트가 더 쉬워집니다. 람다가 너무 복잡해서 한 단계 씩 진행해야한다면 어쨌든 많은 단위 테스트를 원할 것입니다.
답변
Intellij IDEA 15는 훨씬 더 쉽게 만드는 것 같습니다. 람다가있는 라인의 일부에서 멈출 수 있습니다. 첫 번째 기능을 참조하십시오. http://blog.jetbrains.com/idea/2015/06/intellij-idea-15 -eap-is-open /
답변
더 많은 업데이트 된 세부 정보를 제공하기 위해 (2019 년 10 월) IntelliJ는 매우 유용한 이러한 유형의 코드를 디버깅하는 매우 멋진 통합을 추가했습니다.
람다가 포함 된 줄에서 멈출 때 F7 IntelliJ가 디버그 할 코드 조각을 강조 표시합니다. 디버그 할 청크를 전환 할 수 있으며 Tab결정한 후 F7다시 클릭 합니다.
다음은 설명 할 몇 가지 스크린 샷입니다.
1- F7(단계 진입) 키를 누르면 하이라이트 (또는 선택 모드)가 표시됩니다.
답변
IDE를 사용한 디버깅은 항상 유용하지만 스트림의 각 요소를 통해 디버깅하는 이상적인 방법은 Java Steam이 느리게 평가되기 때문에 터미널 메서드 작업 전에 peek ()를 사용하는 것이므로 터미널 메서드가 호출되지 않는 한 각 스트림은 평가되지 않습니다.
List<Integer> numFromZeroToTen = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
numFromZeroToTen.stream()
.map(n -> n * 2)
.peek(n -> System.out.println(n))
.collect(Collectors.toList());