Về nguyên tắc, bạn có thể thay thế các vòng lặp lồng nhau với một Stream
sử dụng flatMap
. Điều này yêu cầu bạn chọn loại phần tử có khả năng giữ thông tin tương đương với các biến vòng lặp, nếu bạn cần. Trong trường hợp của bạn, đó là hai giá trị cho x
và y
. Nó sẽ đơn giản hóa mã nếu lớp Node
của bạn nắm giữ những thông tin này vì bạn có thể dễ dàng lặp qua các nút thay vì giá trị int
sau đó. Vì bạn không nói rõ khả năng của lớp Node
của bạn, đây là một ví dụ trong đó sử dụng một long[]
kích thước hai để giữ điểm:
IntStream.range(0, width).boxed()
.flatMap(x->IntStream.range(0, height).mapToObj(y->new int[]{ x, y }))
.forEach(p1 -> {
Consumer<Node> register=getNode(p1[0], p1[1])::registerObserverAtNeighbor;
IntStream.rangeClosed(p1[0]-1, p1[0]+1).boxed()
.flatMap(x->IntStream.rangeClosed(p1[1]-1, p1[1]+1).mapToObj(y->new int[]{ x,y }))
.filter(p2 -> (p1[0] != p2[0] || p1[1] != p2[1]))
.map(point -> getNode(point[0], point[1]))
.filter(node -> node != null)
.forEach(register);
});
Nó vẫn đơn giản hoá mã trong cùng bằng cách di chuyển mã để bên ngoài, nơi có thể, ví dụ các cuộc gọi getNode
. Bạn cũng có thể đơn giản hóa mã bằng cách đặt các nhiệm vụ lặp đi lặp lại của việc tạo ra một Stream
điểm trên cho một khu vực thành một phương pháp:
static Stream<int[]> area(int x0, int x1, int y0, int y1) {
return IntStream.range(x0, x1).boxed()
.flatMap(x->IntStream.range(y0, y1).mapToObj(y->new int[]{ x, y }));
}
Sau đó, bạn có thể sử dụng nó như thế này:
area(0, width, 0, height).forEach(p1 -> {
Consumer<Node> register=getNode(p1[0], p1[1])::registerObserverAtNeighbor;
area(p1[0]-1, p1[0]+2, p1[1]-1, p1[1]+2)
.filter(p2 -> (p1[0] != p2[0] || p1[1] != p2[1]))
.map(point -> getNode(point[0], point[1]))
.filter(node -> node != null)
.forEach(register);
});
Nó vẫn có thể là dễ dàng hơn nếu bạn có/sử dụng một lớp điểm chuyên dụng hoặc nếu lớp nút giữ thông tin điểm (và có một phương thức so sánh cho nó, trong trường hợp tốt nhất).