에서 지역 변수 수정 forEach
컴파일 오류가 발생합니다.
표준
int ordinal = 0;
for (Example s : list) {
s.setOrdinal(ordinal);
ordinal++;
}
Lambda 사용
int ordinal = 0;
list.forEach(s -> {
s.setOrdinal(ordinal);
ordinal++;
});
이 문제를 해결하는 방법을 아십니까?
답변
래퍼 사용
어떤 종류의 래퍼도 좋습니다.
와 자바 8 이상 , 사용 어느 쪽 AtomicInteger
:
AtomicInteger ordinal = new AtomicInteger(0);
list.forEach(s -> {
s.setOrdinal(ordinal.getAndIncrement());
});
… 또는 배열 :
int[] ordinal = { 0 };
list.forEach(s -> {
s.setOrdinal(ordinal[0]++);
});
와 10 + 자바 :
var wrapper = new Object(){ int ordinal = 0; };
list.forEach(s -> {
s.setOrdinal(wrapper.ordinal++);
});
노트 : 병렬 스트림을 사용하는 경우 매우주의하십시오. 예상 한 결과를 얻지 못할 수도 있습니다. Stuart와 같은 다른 솔루션은 이러한 경우에 더 적합 할 수 있습니다.
이외의 유형 int
물론 이것은 int
. 래핑 유형을 AtomicReference
또는 해당 유형의 배열 로 변경하기 만하면 됩니다. 예를 들어를 사용하는 경우 String
다음을 수행하십시오.
AtomicReference<String> value = new AtomicReference<>();
list.forEach(s -> {
value.set("blah");
});
배열 사용 :
String[] value = { null };
list.forEach(s-> {
value[0] = "blah";
});
또는 Java 10 이상 :
var wrapper = new Object(){ String value; }
list.forEach(s->{
wrapper.value = "blah";
});
답변
이것은 XY 문제에 상당히 가깝습니다. . 즉, 질문은 본질적으로 람다에서 캡처 된 지역 변수를 변경하는 방법입니다. 그러나 실제 작업은 목록의 요소에 번호를 매기는 방법입니다.
내 경험상 80 % 이상의 시간에 람다 내에서 캡처 된 로컬을 변경하는 방법에 대한 질문이 있습니다. 더 나은 진행 방법이 있습니다. 일반적으로 여기에는 감소가 포함되지만이 경우 목록 인덱스에서 스트림을 실행하는 기술이 잘 적용됩니다.
IntStream.range(0, list.size())
.forEach(i -> list.get(i).setOrdinal(i));
답변
외부에서 람다로 값을 전달하고 가져 오지 않으면 람다 대신 일반 익명 클래스를 사용하여 수행 할 수 있습니다.
list.forEach(new Consumer<Example>() {
int ordinal = 0;
public void accept(Example s) {
s.setOrdinal(ordinal);
ordinal++;
}
});
답변
람다 외부에서 사용 된 변수는 (암묵적으로) 최종적이어야하므로 다음과 같은 것을 사용해야합니다. AtomicInteger
하거나 자신의 데이터 구조를 작성해야합니다.
https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html#accessing-local-variables를 참조
하십시오 .
답변
Java 10을 사용 var
하는 경우 다음을 사용할 수 있습니다 .
var ordinal = new Object() { int value; };
list.forEach(s -> {
s.setOrdinal(ordinal.value);
ordinal.value++;
});
답변
AtomicInteger
(또는 값을 저장할 수있는 다른 객체) 의 대안 은 배열을 사용하는 것입니다.
final int ordinal[] = new int[] { 0 };
list.forEach ( s -> s.setOrdinal ( ordinal[ 0 ]++ ) );
그러나 Stuart의 답변을 참조하십시오 . 귀하의 사건을 처리하는 더 좋은 방법이있을 수 있습니다.
답변
나는 그것이 오래된 질문이라는 것을 알고 있지만, 외부 변수가 최종적이어야한다는 사실을 고려하여 해결 방법에 익숙하다면 간단히 다음과 같이 할 수 있습니다.
final int[] ordinal = new int[1];
list.forEach(s -> {
s.setOrdinal(ordinal[0]);
ordinal[0]++;
});
가장 우아하거나 가장 정확하지 않을 수도 있지만 그렇게 될 것입니다.