0

Given:

@Entity
public class Pixel {
    @Id
    Point position;
    String color;

I store pixels like this:

for (int row = 0; row < 20; row++) {
    for (int col = 0; col < 20; col++) {
        repository.save(new Pixel(new Point(row, col), "w3-flat-turquoise"));
    }
}

This represents a square of 20x20

Now I need to display that list using layouts.

I can display easily a square like this (working):

Now I would like to retrieve the pixels from the database and display them... but I can't find a proper way.

So far, I have this (not working because final 'i' can't be change):

VerticalLayout lines = new VerticalLayout();
HorizontalLayout line;
int width = 20;
List<Pixel> pixels = pixelRepository.findAll();

for(final int i=0;i<width;++i) {
    line = new HorizontalLayout();
    Stream<Pixel> pixelLine = pixels.stream().filter(pixel -> pixel.getPosition().x == i);
    for(int j=0;j<width;++j) {
        addNewColorButton(line, pixelLine.filter(pixel -> pixel.getPosition().y == j).findFirst().get().color);
    }
    lines.add(line);
}
add(lines);

What would be a proper algorithm to do it ?

Working solution with final variables:

VerticalLayout lines = new VerticalLayout();
HorizontalLayout line;
int width = 20;
List<Pixel> pixels = pixelRepository.findAll();

for(int i=0;i<width;++i) {
    int finalI = i;
    line = new HorizontalLayout();
    Supplier<Stream<Pixel>> pixelLine = () -> pixels.stream().filter(pixel -> pixel.getPosition().x == finalI);
    for(int j=0;j<width;++j) {
        int finalJ = j;
        addNewColorButton(line, pixelLine.get().filter(pixel -> pixel.getPosition().y == finalJ).findFirst().get().color);
    }
    lines.add(line);
}
add(lines);
Tyvain
  • 2,640
  • 6
  • 36
  • 70
  • Warning: `findFirst().get()` might result in an exception if `findFirst` returns `Optional.empty` – Thiyagu Dec 12 '18 at 04:42

2 Answers2

1

You can just create a final object from the i that changes i's value. finalI value is final and never changes.

int finalI = i;
int finalJ = j;

and here is your code after adding the final objects

VerticalLayout lines = new VerticalLayout();
HorizontalLayout line;
int width = 20;
List<Pixel> pixels = pixelRepository.findAll();

for (int i = 0; i < width; ++i) {
    int finalI = i;
    line = new HorizontalLayout();
    Stream<Pixel> pixelLine = pixels.stream().filter(pixel -> pixel.getPosition().x == finalI);
    for (int j = 0; j < width; ++j) {
        int finalJ = j;
        addNewColorButton(line, pixelLine.filter(pixel -> pixel.getPosition().y == finalJ).findFirst().get().color);
    }
    lines.add(line);
}
add(lines);
SamHoque
  • 2,978
  • 2
  • 13
  • 43
  • It gives the error "stream has already been operated upon or closed" on the 'addNewColorButton' line. that odd, because filter is not supposed to consume the stream... – Tyvain Dec 12 '18 at 04:51
  • @Tyvain Did you close the Stream? – SamHoque Dec 12 '18 at 04:52
  • https://stackoverflow.com/questions/23860533/copy-a-stream-to-avoid-stream-has-already-been-operated-upon-or-closed – SamHoque Dec 12 '18 at 04:53
0

for(final int i=0;i<width;++i) is pretty bogus for obvious reasons.

If you need to get your i into the lambda you can transform it to an array, which will be treated as effectively final by the compiler like this:

int[] wrapped_i = new int[]{i}

and access it from within the lambda with wrapped_i[0]. This approach is somewhat error-prone and no cure-all, especially when you're using parallel streams (which sorta-kinda is the whole selling point).

nitowa
  • 1,079
  • 2
  • 9
  • 21