Using Java 8 Streams' Collectors to increment value based of existing key/value pair

Suppose there is a List<Object> and that Object contains two methods: getUserId and getPoints.

Consider that List<Object> contains three objects, and they contain the following data:

userId A; 3 points
userId A; 5 points
userId B; 1 point

After collecting this properly, I am expecting to have a Map<String, Integer> that would look like this:

A: 8,
B: 1

I am attempting this using Java’s 8 functional interfaces, the streams, because I only need the final result and I do not have nor need any of these mappings in between. I am willing to modify this if there is no other way.
I first came up with this:

this.service.getListObject()
    .stream()
    .collect(Collectors.toMap(Object::getUserId, Object::getPoints));

However, this has shown insufficient because it will always replace the key with the newest value, thus producing:

A: 5,
B: 1

How can I tweak the last bits from the Collectors.toMap() to automatically increment its value according to the value already stored in the map, so that I produce the result above?

Solution:

Use Collectors.groupingBy together with Collectors.summingInt as a downstream collector:

this.service.getListObject()
    .stream().collect(Collectors.groupingBy(
        Object::getUserId, Collectors.summingInt(Object::getPoints)));

Java Comparator with null fields

I have a list of entities Entity with the fields id and createdDate. I want to sort them as following:

  • higher id first
  • if id null, most recent createdDate first

I’ve tried the following unsuccessfuly, as it throwns a NullPointerException when id is null

Comparator comp = Comparator
                .nullsFirst(Comparator.comparing(e -> ((Entity) e).getId()))
                .thenComparing(e -> ((Entity e).getCreatedDate())
                .reversed();
entities.stream().sorted(comp).findFirst();

For what I see, Comparator.nullsFirst handles when the entity is null, not when the field to be compared is null. How can I handle this situation?

Solution:

I think you are looking for comparator like this :

Comparator<MyClass> comparator = Comparator.comparing(MyClass::getId, Comparator.nullsLast(Comparator.reverseOrder()))
                .thenComparing(MyClass::getCreateDate);

The code to test it :

List<MyClass> list = new ArrayList<>();

list.add(new MyClass(null, LocalDate.now()));
list.add(new MyClass(4L, LocalDate.now()));
list.add(new MyClass(2L, LocalDate.now()));
list.add(new MyClass(4L, LocalDate.now().plusDays(1)));
list.add(new MyClass(null, LocalDate.now().plusDays(1)));

Comparator<MyClass> comparator = Comparator.comparing(MyClass::getId, Comparator.nullsLast(Comparator.reverseOrder()))
                .thenComparing(MyClass::getCreateDate);

list.stream().sorted(comparator).forEach(myClass -> System.out.println(myClass.id + " " + myClass.createDate));

The output is :

4 2019-06-14
4 2019-06-15
2 2019-06-14
null 2019-06-14
null 2019-06-15

If you want nulls to be first just change nullsLast to nullsFirst.

How to get Either left/right depending of Option value

I’m trying to return Either value depending on option value. My goal is to return Either.right() if the option is present otherwise, the code should return Either.left().
I use Java 8 and vavr 0.9.2

I want to avoid conditional imbrication

public Either<String, Integer> doSomething() {
    Optional<Integer> optionalInteger = Optional.of(Integer.MIN_VALUE);
    Option<Integer> integerOption = Option.ofOptional(optionalInteger);

    return integerOption.map(value -> {
      //some other actions here
      return Either.right(value);
    }).orElse(() -> {
      //some other checks her also 
      return Either.left("Error message");
    });
}

the compiler fail with this message

Error:(58, 7) java: no suitable method found for orElse(()->Either[...]age"))
    method io.vavr.control.Option.orElse(io.vavr.control.Option<? extends io.vavr.control.Either<java.lang.Object,java.lang.Integer>>) is not applicable
      (argument mismatch; io.vavr.control.Option is not a functional interface
          multiple non-overriding abstract methods found in interface io.vavr.control.Option)
    method io.vavr.control.Option.orElse(java.util.function.Supplier<? extends io.vavr.control.Option<? extends io.vavr.control.Either<java.lang.Object,java.lang.Integer>>>) is not applicable
      (argument mismatch; bad return type in lambda expression
          no instance(s) of type variable(s) L,R exist so that io.vavr.control.Either<L,R> conforms to io.vavr.control.Option<? extends io.vavr.control.Either<java.lang.Object,java.lang.Integer>>)

Solution:

orElse returns Option<T> while doSomething return type requires Either<String, Integer>.

Instead, try to use getOrElse which returns T:

public Either<String, Integer> doSomething() {
    // ...
    return integerOption.map(
        Either::<String, Integer>right).getOrElse(
            () -> Either.left("Error message"));
}

Getting "cannot find symbol" error with reader.nextLine()

Here is my code (it is code to reverse a given string)

    import java.util.Scanner;

public class ReversingName {
    public static String reverse(String text) {
    // write your code here
    int strlenght= text.length();
    int i=1;
    String str= "";
    while (i<=strlenght){
        char test= text.charAt(strlenght-1);
        str=str+test;
    }
    return str;
}


public static void main(String[] args) {
    System.out.print("Type in your text: ");
    String text = reader.nextLine();
    System.out.println("In reverse order: " + reverse(text));
}
}

But I cannot take in input because when I try to take the string input I get a “cannot find symbol error” even though I have clearly defined the variable “text”.

This question is from MOOC.fi’s Java OOP course, and can be found here (question 52, if it helps): https://materiaalit.github.io/2013-oo-programming/part1/week-3/

Solution:

reader is never declared. From the looks of things, it seems as though it’s supposed to be a Scanner instance:

public static void main(String[] args) {
    Scanner reader = new Scanner(System.in); // Declare and initialize reader
    System.out.print("Type in your text: ");
    String text = reader.nextLine();
    System.out.println("In reverse order: " + reverse(text));
}

Is there a possibility to write a random letter generator as short as in phyton?

So I want to shorten my code and I asked myself if there is any possibilty that a Random Lettergenrator in Java is as short as in phyton. In Phyton its just one a oneliner.

The following Code is my Code yet:

int random = (int) Math.random()*25;

    String[] letters ={"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w", "x","y","z"}; 

    String letter = letters[random]; 

Solution:

If “short” just means one line, then any of these would do:

char letter = "abcdefghijklmnopqrstuvwxyz".charAt((int) (Math.random() * 26));

char letter = (char) ThreadLocalRandom.current().nextInt('a', 'z'+1);

char letter = (char) ('a' + Math.random() * 26);

Functional style java.util.regex match/group extraction

Using java.util.regex to extract substrings I find myself implementing the same code pattern working around calls to :

Pattern p = Pattern.compile(pattern); // can be static final
Matcher m = p.matcher(input);
if (m.find()) { // or m.matches()
    foo(m.group(x));
} else {
    ...
}

Is there a functional extension or popular library (guava / apache commons) that avoids the ugly unnecessary and error-prone local variable, like:

Pattern p = Pattern.compile(pattern); // can be static final
p.matchedGroup(input, x) // return Optional<String>
    .map(group -> foo(group))
    .orElse(...);

and also a stream of match results like:

Pattern p = Pattern.compile(pattern);
p.findMatches(input)
    .map((MatchResult mr) -> {
        mr.groupsIfPresent(x).map(g -> foo(g)).orElse(...)
    })
    .findFirst();

It seems the only functional addition in Java8 was .splitAsStream() but that only helps when trying to split around matches.

Solution:

The following is only available from

You’re probably looking for Matcher::results which produces a Stream<MatchResult>

You can use it in the following way for example

p.matcher(input)
 .results()
 .map(MatchResult::group)
 .findAny()
 .orElse(null);

Search for multiline String in a text file

I have a text file from which i am trying to search for a String which has multiple lines. A single string i am able to search but i need multi line string to be searched.

I have tried to search for single line which is working fine.

public static void main(String[] args) throws IOException 
{
  File f1=new File("D:\\Test\\test.txt"); 
  String[] words=null;  
  FileReader fr = new FileReader(f1);  
  BufferedReader br = new BufferedReader(fr); 
  String s;     
  String input="line one"; 

  // here i want to search for multilines as single string like 
  //   String input ="line one"+
  //                 "line two";

  int count=0;   
  while((s=br.readLine())!=null)   
  {
    words=s.split("\n");  
    for (String word : words) 
    {
      if (word.equals(input))   
      {
        count++;    
      }
    }
  }

  if(count!=0) 
  {
    System.out.println("The given String "+input+ " is present for "+count+ " times ");
  }
  else
  {
    System.out.println("The given word is not present in the file");
  }
  fr.close();
}

And below are the file contents.

line one  
line two  
line three  
line four

Solution:

Use the StringBuilder for that, read every line from file and append them to StringBuilder with lineSeparator

StringBuilder lineInFile = new StringBuilder();

while((s=br.readLine()) != null){
  lineInFile.append(s).append(System.lineSeparator());
}

Now check the searchString in lineInFile by using contains

StringBuilder searchString = new StringBuilder();

builder1.append("line one");
builder1.append(System.lineSeparator());
builder1.append("line two");

System.out.println(lineInFile.toString().contains(searchString));

Isn't it guaranteed that parallel stream derived from list will always behave like its sequential counterpart and give the same, predictable output?

The following code prints true for 100 times:

for(int i=0; i<100; i++) {
   String s2 = Arrays.asList("A", "E", "I", "O", "U").parallelStream().reduce("x", String::concat, String::concat);
   System.out.println("xAxExIxOxU".equals(s2));
}

Granted, 100 times is not a guarantee. But doesn’t it seem though that even if the identity used here does not meet the requirement “…for all u, combiner.apply(identity, u) is equal to u” per the doc, we can still say that a parallel stream derived from list or any other inherently ordered structure will behave just like a sequential stream in reduce() returning the same output?

Solution:

The Javadoc for the Stream.reduce function with an identity argument says:

The identity value must be an identity for the accumulator function.
This means that for all t, accumulator.apply(identity, t) is equal to
t.

Which is clearly not the case here – "x".concat(anything) doesn’t equal anything. The only valid identity value here is "".

If you had tested the premise of the title of your question – by seeing what a non-parallel operation returns – you’d see that the answer to your title is “no” – because a non-parallel stream returns "xAEIOU" for your reduce operation.

If you change the identity value from "x" to "", then the answer would be “yes, there is such a guarantee, as your reduce function is associative and the constraints on the identity value are also satisfied.”

Even with your modified title, the answer is clear:

You are breaking the contract of the reduce function by providing, as the identity value, a value that is not an identity value for your reduce function. As such, since you are breaking the contract of the reduce methods, all guarantees are off.

It’s easy to create a case where it doesn’t hold; just make your list larger like Holger already pointed out:

List<String> list = new ArrayList<>();
for (int i = 0; i < 500; i++) {
    list.add("A");
}
String s2 = list.parallelStream().reduce("x", String::concat, String::concat);
System.out.println(s2);
if (s2.length() != list.size() * 2) {
    System.out.println("Bad s2 size");
}

Generating Pyramid to Show Numbers in Module 10

I am trying to generate pyramid starts with the number one (1), in each row the first digit determines the number of row. In addition, the first number in the row also determines the number of numbers in that order (according to module 10). All other numbers in a row we calculate by adding the number from the left and the number above it, according to module 10.

int n = 12;
int i, j;

for (i = 1; i <= n; i++) {
    for (j = 0; j <= i; j++) {
      int module = i % 10;

      System.out.print(module + " ");

    }

    System.out.println();
  }
}

With my implementation, I get

1 1 
2 2 2 
3 3 3 3 
4 4 4 4 4 
5 5 5 5 5 5 
6 6 6 6 6 6 6 
7 7 7 7 7 7 7 7 
8 8 8 8 8 8 8 8 8 
9 9 9 9 9 9 9 9 9 9 
0 0 0 0 0 0 0 0 0 0 0 
1 1 1 1 1 1 1 1 1 1 1 1 
2 2 2 2 2 2 2 2 2 2 2 2 2 

The actual result should be

1
2 3
3 5 8
4 7 2 0
5 9 6 8 8
6 1 0 6 4 2
7 3 4 4 0 4 6
8 5 8 2 6 6 0 6
9 7 2 0 2 8 4 4 0
0 9 6 8 8 0 8 2 6 6
1 1 0 6 4 2 2 0 2 8 4
2 3 4 4 0 4 6 8 8 0 8 2

What am I missing?

Solution:

First you write a helper method to calculate the digit to display. This method takes as an argument the row index and column index or the row number and column number, whatever you are more comfortable with. Assuming we use 0-based indices for the row and column, we can define the following values for that method:

  • When the column index is 0 (so we are in the first column), the return value is the row index + 1 modulo 10.
  • When the row index is 0 (so we are at the top), the return value is 1.
  • For all the other positions, we use a recursive call of the helper method to add “the number from the left” with “the number above it”.

The helper method will look like this:

/**
 * Calculate the digits. The arguments are 0 based.
 * 
 * @param row The row index
 * @param column The column index
 * @return The digit to display
 */
public static int calculateDigit(int row, int column) {
    if (row < 0) {
        throw new IllegalArgumentException("The row index must not be negative");
    }
    if (column < 0) {
        throw new IllegalArgumentException("The column index must not be negative");
    }
    if (column == 0) {
        return (row+1) % 10; // simply return the row number
    }
    if (row == 0) {
        return 1; // in the first row, so it is the "1"
    }
    // calculate the new number based on the expression
    // "adding the number from the left and the number above it"
    int left = calculateDigit(row, column-1);
    int above = calculateDigit(row-1, column-1);
    int sum = left + above;
    int modulo = sum % 10;
    return modulo;
}

You can use this helper method in the simple two for loops you already have.

for (int r=0; r<10; r++) {
    for (int c=0; c<=r; c++) {
        int value = calculateDigit(r, c);
        System.out.print(value+" ");
    }
    System.out.println();
}

And this will get you the expected output:

1 
2 3 
3 5 8 
4 7 2 0 
5 9 6 8 8 
6 1 0 6 4 2 
7 3 4 4 0 4 6 
8 5 8 2 6 6 0 6 
9 7 2 0 2 8 4 4 0 
0 9 6 8 8 0 8 2 6 6 

is this use of objects redundant and/or inefficient?

I’m fairly inexperienced with using objects so I would really like some input.

I’m trying to remove comments from a list that have certain “unwanted words” in them, both the comments and the list of “unwanted words” are in ArrayList objects.

This is inside of a class called FormHelper, which contains the private member comments as an ArrayList, the auditList ArrayList is created locally in a member function called populateComments(), which then calls this function (below). PopulateComments() is called by the constructor, and so this function only gets called once, when an instance of FormHelper is created.

private void filterComments(ArrayList <String> auditList) {
    for(String badWord : auditList) {
        for (String thisComment : this.comments) {
            if(thisComment.contains(badWord)) {
                int index = this.comments.indexOf(thisComment);
                this.comments.remove(index);
            }
        }
    }
}

something about the way I implemented this doesn’t feel right, I’m also concerned that I’m using ArrayList functions inefficiently. Is my suspicion correct?

Solution:

It is not particularly efficient. However, finding a more efficient solution is not straightforward.

Lets step back to a simpler problem.

private void findBadWords(List <String> wordList, List <String> auditList) {
    for(String badWord : auditList) {
        for (String word : wordList) {
            if (word.equals(badWord)) {
                System.err.println("Found a bad word");
            }
        }
    }
}

Suppose that wordList contains N words and auditList contains M words. Some simple analysis will show that the inner loop is executed N x M times. The N factor is unavoidable, but the M factor is disturbing. It means that the more “bad” words you have to check for the longer it takes to check.

There is a better way to do this:

private void findBadWords(List <String> wordList, HashSet<String> auditWords) {
    for (String word : wordList) {
        if (auditWords.contains(word))) {
            System.err.println("Found a bad word");
        }
    }
}

Why is that better? It is better (faster) because HashSet::contains doesn’t need to check all of the audit words one at a time. In fact, in the optimal case it will check none of them (!) and the average case just one or two of them. (I won’t go into why, but if you want to understand read the Wikipedia page on hash tables.)


But your problem is more complicated. You are using String::contains to test if each comment contains each bad word. That is not a simple string equality test (as per my simplified version).

What to do?

Well one potential solution is to split the the comments into an array of words (e.g. using String::split and then user the HashSet lookup approach. However:

  • That changes the behavior of your code. (In a good way actually: read up on the Scunthorpe problem!) You will now only match the audit words is they are actual words in the comment text.

  • Splitting a string into words is not cheap. If you use String::split it entails creating and using a Pattern object to find the word boundaries, creating substrings for each word and putting them into an array. You can probably do better, but it is always going to be a non-trivial calculation.

So the real question will be whether the optimization is going to pay off. That is ultimately going to depend on the value of M; i.e. the number of bad words you are looking for. The larger M is, the more likely it will be to split the comments into words and use a HashSet to test the words.

Another possible solution doesn’t involve splitting the comments. You could take the list of audit words and assemble them into a single regex like this: \b(word-1|word-2|...|word-n)\b. Then use this regex with Matcher::find to search each comment string for bad words. The performance will depend on the optimizing capability of the regex engine in your Java platform. It has the potential to be faster than splitting.


My advice would be to benchmark and profile your entire application before you start. Only optimize:

  1. when the benchmarking says that the overall performance of the requests where this comment checking occurs is concerning. (If it is OK, don’t waste your time optimizing.)

  2. when the profiling says that this method is a performance hotspot. (There is a good chance that the real hotspots are somewhere else. If so, you should optimize them rather than this method.)

Note there is an assumption that you have (sufficiently) completed your application and created a realistic benchmark for it before you think about optimizing. (Premature optimization is a bad idea … unless you really know what you are doing.)