2

I am trying to use an IntStream to increment an int value that is outside the stream.The point of this method is to find if there are chars on same position that are not equal. The n and word Strings are both same length.

When I try to increment the counter in the scope of forEach it shows me that it should be final or effectively final. Anyone could suggest a better way to do this or a way to increment this counter?

public boolean check(String n,String word){
    int counter=0;

    IntStream.range(0, n.length())
        .forEach(z->{

            if(n.charAt(z)!=word.charAt(z)){
            counter++;
            }
        });
    if(counter>1)
        return false;
    else
        return true;


} 
Stefan Zobel
  • 3,182
  • 7
  • 28
  • 38
LexByte
  • 382
  • 4
  • 15
  • 1
    Is there a reason you can't use `n.equals(word)`? – Radiodef Jun 10 '17 at 21:55
  • 3
    @Radiodef the words have same length but it should only return true if there is only 1 char that is different in the word on same position. Example hello and hallo. – LexByte Jun 10 '17 at 22:00

3 Answers3

9

There's a way to do what you want without needing to keep a counter variable:

public boolean check(String n, String word) {
    long count = IntStream.range(0, n.length())
        .filter(i -> n.charAt(i) != word.charAt(i))
        .limit(2) // short-circuit here!
        .count();
    return count <= 1;
}

This is like other answers. The only difference is that I'm using limit(2) to short-circuit the stream if we've already found 2 different characters.

fps
  • 33,623
  • 8
  • 55
  • 110
8

You shouldn't use the forEach to count occurrences, rather use the built in count method.

public boolean check(String n, String word){
       int counter = (int)IntStream.range(0, n.length())
                     .filter(z -> n.charAt(z) != word.charAt(z)).count();
       return counter <= 1;
}
Ousmane D.
  • 54,915
  • 8
  • 91
  • 126
0

You can declare counter as instance variable instead. For more, read my another answer about effectively final.

class Test {
    private int counter = 0;
    public boolean check(String n,String word){

        IntStream.range(0, n.length())
                .forEach(z->{
                    if(n.charAt(z) != word.charAt(z)) {
                        counter++;
                    }
                });
        return counter <= 1;
    }
}
  • This seems to work aka it doesn't give me that error anymore. Thank you. – LexByte Jun 10 '17 at 22:02
  • I didnt -1 you. Your answer was correct and it helped me understand some stuff! @snr – LexByte Jun 10 '17 at 22:06
  • 2
    I didn't -1 either but what would be the drawback of using `final AtomicInteger counter` instead of introducing a new instance variable that'll have to be maintained? – ChiefTwoPencils Jun 10 '17 at 22:13
  • I haven't downvoted, but maybe the downvoter didn't like your answer because it doesn't work with parallel streams. Besides, it has side-effects. Please take a look at the [`java.util.stream` package docs](https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html), where it is explained why side-effects shouldn't be used in behavioral parameters (i.e. your `forEach`'s `Consumer`). @ChiefTwoPencils The drawback is the side-effect. – fps Jun 10 '17 at 23:23
  • 2
    @Federico Peralta Schaffner: it doesn’t need a parallel stream to make this code break. Just call the method *again*… – Holger Jun 12 '17 at 07:50