람다 메소드에서 외부 변수 사용
발생했던 문제
람다 함수를 이용해서 반복문 처리를 진행하고 있던 중에 컴파일 시 오류가 발생했었다
int[][] containerHealth = new int[2][N + 1];
int[] step = 1;
int upDown = 0;
Arrays.stream(reader.readLine().split(" "))
.forEach(i -> {
int nowStep = step;
containerHealth[current][nowStep] = Integer.parseInt(i);
step += 1;
});에러 사항
java: local variables referenced from a lambda expression must be final or effectively final
이유는 람다 함수에서 외부의 지역변수를 사용할 경우 스택 영역에 직접 접근 하는 것이 아니라 지역 변수를 자신의 스택에 복사하여 사용한다. 이유는 실행 시점에서 변수의 상태를 예측하기 어려워지고 만약 람다식이 다른 스레드에서 동작을 할 경우 멀티 쓰레드 환경에서의 동시성 문제가 발생할 수 있기 때문이다
결론
- 람다 표현식은 여러 쓰레드에서 사용할 수 있다.
- 힙 영역에 저장되는 인스턴스 변수와 달리 스택 영역에 저장되는 지역 변수는 외부 쓰레드에서 접근 불가능하다.
- 외부 쓰레드에서도 지역 변수 값을 사용할 수 있도록 복사본 기능을 제공하는데 이를
Capturing lambda이라고 한다. - 복사본은 원본의 값이 바뀌어도 알 수 없기 때문에 쓰레드 동기화를 위해 지역 변수는
final또는effectively final상태여야 한다.
두 List를 합치는 방법
Stream concat 사용
List<User> newUserList = new ArrayList<>();
List<User> existUserList = new ArrayList<>();
List<User> allUsersStream.concat(existUserList.stream(), newUserList.stream())
.collect(Collectors.toList()
새 리스트에 addAll() 하기
List<User> newUserList = new ArrayList<>();
List<User> existUserList = new ArrayList<>();
List<User> allUsers = new ArrayList<>(existUserList);
allUsers.addAll(newUserList);리스트 관련 실수한 부분
List.of 및 Arrays.asList 사용
간단 설명
List.Of를 사용해서 List를 생성하게 될 경우 불변이다.
List<String> list = List.of("a", "b", "c");
list.add("d"); // UnsupportedOperationException 발생!Arrays.asList로 만든 리스트는 크기 변경 불가 (add/remove 불가, set은 가능).
List<String> list = Arrays.asList("a", "b", "c");
list.add("d"); // UnsupportedOperationException 발생!변경 가는 객체로 사용하고 싶을 때
new ArrayList<>()로 감싸주면 된다.
List<String> immutable = List.of("a", "b", "c");
List<String> modifiable = new ArrayList<>(immutable);
modifiable.add("d"); // OK