Java 8: 람다의 반복 횟수를 세는 데 선호되는 방법?
나는 자주 같은 문제에 직면한다.람다 밖에서 사용하기 위해 람다의 런을 세어야 합니다.
예:
myStream.stream().filter(...).forEach(item -> { ... ; runCount++});
System.out.println("The lambda ran " + runCount + "times");
이 문제는 runCount가 다음과 같이 되어 있어야 한다는 것입니다.final
「 」, 「 」, 「 」는 수.int
은...일 수 .Integer
그건 불변의 일이니까클래스 레벨 변수(필드)로 만들 수 있지만 이 코드 블록에서만 필요합니다.
여러 가지 방법이 있다는 것을 알고 있는데, 이 문제에 대해 어떤 해결책을 선호하는지 궁금할 뿐입니다.
를하 an an an an an an an를 합니까?AtomicInteger
또는 어레이 레퍼런스나 다른 방법으로요?
설명을 위해 예를 조금 다시 포맷하겠습니다.
long runCount = 0L;
myStream.stream()
.filter(...)
.forEach(item -> {
foo();
bar();
runCount++; // doesn't work
});
System.out.println("The lambda ran " + runCount + " times");
람다 내에서 카운터를 증가시켜야 하는 경우 일반적인 방법은 카운터를AtomicInteger
★★★★★★★★★★★★★★★★★」AtomicLong
그 후, 인크리먼트 메서드 중 하나를 호출합니다.
엘리먼트를 할 수 .int
★★★★★★★★★★★★★★★★★」long
어레이는 스트림이 병렬로 실행되면 레이스 조건이 됩니다.
, 은 「」으로 끝나는 해 주세요.forEach
아, 아, 아, 아, 아, 아, 아, 맞다. 바꿀 수 있어요.forEach
a까지peek
이치노
long runCount = myStream.stream()
.filter(...)
.peek(item -> {
foo();
bar();
})
.count();
System.out.println("The lambda ran " + runCount + " times");
이이좀 、 ,,,,, 、 래래해해해해 。 는 ★★★★★★★★★★★★★★★★★★★.forEach
★★★★★★★★★★★★★★★★★」peek
을 사용하다자바8의 새로운 기능 스타일은 부작용을 피하기 위한 것이다.하여 조금 .count
컬렉션에 이 추가되는 가 있습니다.다른 전형적인 부작용은 컬렉션에 아이템을 추가하는 것이다.일반적으로 수집기를 사용하여 교체할 수 있습니다.하지만 실제로 어떤 일을 하려는지 모르면 더 이상 구체적으로 제안할 수 없습니다.
동기 ATOMIC Integer 대신 정수 배열을 사용할 수 있습니다.어레이에 대한 참조가 다른 어레이를 할당받지 않는 한(그것이 포인트) 필드의 값을 임의로 변경할 수 있지만 최종 변수로 사용할 수 있습니다.
int[] iarr = {0}; // final not neccessary here if no other array is assigned
stringList.forEach(item -> {
iarr[0]++;
// iarr = {1}; Error if iarr gets other array assigned
});
AtomicInteger runCount = 0L;
long runCount = myStream.stream()
.filter(...)
.peek(item -> {
foo();
bar();
runCount.incrementAndGet();
});
System.out.println("The lambda ran " + runCount.incrementAndGet() + "times");
Atomic Integer를 사용하면 안 됩니다.사용해야 할 이유가 없는 한 물건을 사용하면 안 됩니다.또한 AtomicInteger를 사용하는 이유는 동시접속 등을 허용하기 위해서일 수 있습니다.
고객의 문제에 관한 한
홀더는 람다 내에서 홀더를 고정하고 증가시키는 데 사용할 수 있습니다.runCount.value를 호출하여 얻을 수 있는 경우
Holder<Integer> runCount = new Holder<>(0);
myStream.stream()
.filter(...)
.forEach(item -> {
foo();
bar();
runCount.value++; // now it's work fine!
});
System.out.println("The lambda ran " + runCount + " times");
저는 이 방법이 효과가 있었습니다.누군가 유용하게 써주셨으면 합니다.
AtomicInteger runCount = new AtomicInteger(0);
myStream.stream().filter(...).forEach(item -> runCount.getAndIncrement());
System.out.println("The lambda ran " + runCount.get() + "times");
getAndIncrement()
Java 문서 상태:
VarHandle.getAndAdd에서 지정한 메모리 효과와 함께 현재 값을 아토믹하게 증가시킵니다.getAndAdd(1)와 동일합니다.
또 다른 대안은 Apache Commons Mutable을 사용하는 것입니다.내부.
MutableInt cnt = new MutableInt(0);
myStream.stream()
.filter(...)
.forEach(item -> {
foo();
bar();
cnt.increment();
});
System.out.println("The lambda ran " + cnt.getValue() + " times");
로컬에만 필요하므로 필드를 만들지 않으려면 익명 클래스에 저장할 수 있습니다.
int runCount = new Object() {
int runCount = 0;
{
myStream.stream()
.filter(...)
.peek(x -> runCount++)
.forEach(...);
}
}.runCount;
이상해, 알아.단, 일시변수는 로컬 범위에서도 제외됩니다.
다른 방법(작업이 성공한 경우 등 일부 상황에서만 카운트를 증가시키고 싶은 경우 유용함)은 다음과 같습니다.mapToInt()
그리고.sum()
:
int count = myStream.stream()
.filter(...)
.mapToInt(item -> {
foo();
if (bar()){
return 1;
} else {
return 0;
})
.sum();
System.out.println("The lambda ran " + count + "times");
Stuart Marks가 언급했듯이, 이것은 여전히 약간 이상하다. 왜냐하면 이것은 부작용을 완전히 피하지 않기 때문이다(무엇에 따라 달라짐).foo()
그리고.bar()
하고 있습니다).
람다에서 외부에서 액세스할 수 있는 변수를 증가시키는 또 다른 방법은 클래스 변수를 사용하는 것입니다.
public class MyClass {
private int myCount;
// Constructor, other methods here
void myMethod(){
// does something to get myStream
myCount = 0;
myStream.stream()
.filter(...)
.forEach(item->{
foo();
myCount++;
});
}
}
이 예에서는 하나의 메서드에서 카운터에 클래스 변수를 사용하는 것은 의미가 없을 수 있으므로 특별한 이유가 없는 한 주의합니다.클래스 변수 유지final
가능하면 스레드 안전성 등에 도움이 될 수 있습니다(사용방법에 대한 자세한 내용은 http://www.javapractices.com/topic/TopicAction.do?Id=23 참조).final
).
람다가 왜 이렇게 작동하는지 더 잘 알기 위해 https://www.infoq.com/articles/Java-8-Lambdas-A-Peek-Under-the-Hood에서 자세히 살펴봅니다.
reduce도 효과가 있습니다.이렇게 사용할 수 있습니다.
myStream.stream().filter(...).reduce((item, sum) -> sum += item);
저는 이게 제일 우아한 방법이에요.
long count = list.stream()
.peek(/* do your stuff here */)
.long();
JDK 9,10 에는, 상기의 솔루션이 동작하지 않는 버그가 있습니다만, 다음과 같이 대처해 주세요.https://bugs.openjdk.java.net/browse/JDK-8198356
long count = list.stream()
.peek(/* do your stuff here */)
.collect(Collectors.counting());
AtomicInteger runCount = new AtomicInteger(0);
elements.stream()
//...
.peek(runCount.incrementAndGet())
.collect(Collectors.toList());
// runCount.get() should have the num of times lambda code was executed
안enum
사용할 수 있습니다.특히 반복에 여러 카운터가 있는 경우:
import java.util.Arrays;
class LambdaCounter {
enum CountOf {
NO,
OK,
ERROR;
private int count;
// can be named inc(), instead of the Greek capital Delta,
// which stands for the math increment operator '∆' <https://en.wikipedia.org/wiki/%E2%88%86>
synchronized int Δ( final int... times ) {
if ( times.length <= 0 )
return ++count; // increase by 1
return count += Arrays.stream( times ).sum(); // increase by arguments
}
// can be named val[ue](), instead of the Greek capital Xi,
// which stands for the math identity operator '≡' <https://en.wikipedia.org/wiki/Triple_bar>
int Ξ() {
return count;
}
}
public static void main( final String[] args ) {
Arrays.stream( new int[] { 1, 2, 3, 4, 5, 6, 7 } )
.forEach( i -> {
CountOf.NO.Δ();
@SuppressWarnings( "unused" )
final int LHS_DUMMY =
i % 2 == 0
? CountOf.OK.Δ()
: CountOf.ERROR.Δ();
} );
System.out.printf( "No: %d, OK: %d, Error: %d, Error.inc(38): %d, Error.inc(4, 4): %d%n",
CountOf.NO.Ξ(), CountOf.OK.Ξ(), CountOf.ERROR.Ξ(), CountOf.ERROR.Δ( 38 ), CountOf.ERROR.Δ( 4, 4 ) );
// Output:
// No: 7, OK: 3, Error: 4, Error.inc(38): 42, Error.inc(4, 4): 50
}
}
언급URL : https://stackoverflow.com/questions/28790784/java-8-preferred-way-to-count-iterations-of-a-lambda
'programing' 카테고리의 다른 글
Eclipse - "호환성이 없는 JVM.JVM 버전 1.8.0_261은 이 제품에 적합하지 않습니다.버전: 11 이상 필요" (0) | 2022.09.22 |
---|---|
Java 날짜 및 시간 클래스를 사용할까요, 아니면 Joda Time과 같은 서드파티 라이브러리를 사용할까요? (0) | 2022.09.22 |
중첩된 사전을 예쁘게 인쇄하는 방법 (0) | 2022.09.21 |
MySQL: GROUP_CONCAT(왼쪽 결합 포함) (0) | 2022.09.21 |
두 날짜 사이의 데이터 프레임 행 선택 (0) | 2022.09.21 |