Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Populate a map conditionally using streams - Java 8

I'm trying to translate this (simplified) code to use Java-8 streams:

Map<String, String> files = new ConcurrentHashMap<String, String>();

while(((line = reader.readLine()) != null) {
      if(content != null)
        files.put("not null"+line, "not null"+line);
      else
        files.put("its null"+line, "its null"+line);
    }
reader.close();

Here is what I've tried:

files = reader.lines().parallel().collect((content != null)?
                (Collectors.toConcurrentMap(line->"notnull"+line, line->line+"notnull")) :                                              
                (Collectors.toConcurrentMap(line->line+"null", line->line+"null")));

But the above gives a "cyclic inference" message for all the line->line+"..." on intelliJ. What is cyclic inference? Is there an error in this logic?

I noted some similar issues on SO. But they suggest to use interface(Map) instead of its implementations. But files here is declared as a Map.

Update: Adding more context, content is a String that holds the name of a directory. files is a map that holds multiple file paths. What file paths need to go into the files map depends on content directory-name is populated or not.

like image 317
A.R.K.S Avatar asked Dec 10 '22 17:12

A.R.K.S


1 Answers

Another way to fix this is to introduce the intermediate variable for collector:

Collector<String, ?, ConcurrentMap<String, String>> collector = (content != null) ?
        (Collectors.toConcurrentMap(line->"notnull"+line, line->line+"notnull")) :
        (Collectors.toConcurrentMap(line->line+"null", line->line+"null"));
Map<String, String> files = reader.lines().parallel().collect(collector);       

This solution (unlike one presented by @JanXMarek) does not allocate intermediate arrays and does not check the content for every input line.

The cyclic inference is the situation in the type inference procedure when to determine the type of inner subexpression, the type of outer subexpression must be determined, but it cannot be determined without knowing the type of inner subexpression. Type inference in Java-8 can infer that in case of Stream<String>.collect(Collectors.toConcurrentMap(line->line+"null", line->line+"null")) the type of Collector is Collector<String, ?, ConcurrentMap<String, String>>. Normally when subexpression type (here we're speaking about toConcurrentMap(...) subexpression) cannot be explicitly determined, it can be reduced using the outer context if the outer context is method invocation, cast or assignment. Here however the outer context is ?: operator which has its own complex type inference rules, so this becomes too much and you should help the type inference system specifying the explicit type somewhere.

like image 83
Tagir Valeev Avatar answered Dec 26 '22 15:12

Tagir Valeev