简体   繁体   中英

How to replace null values in map with length of key using java 8 stream

I have a Map<String, Integer> , which has some keys and values. I want to associate all keys with the values as the key's length. I have been able to solve this in pure java and java-8, but somehow I don't think that appending a terminal operation at the end like .collect(Collectors.toList()); which is not required for me in my code.

My code: ( Java ) works fine

 Map<String, Integer> nameLength = new HashMap<>();
   nameLength.put("John", null);
    nameLength.put("Antony", 6);
    nameLength.put("Yassir", 6);
    nameLength.put("Karein", 6);
    nameLength.put("Smith", null);
    nameLength.put("JackeyLent",null);
    for(Entry<String, Integer> length: nameLength.entrySet()){
      if(length.getValue() == null){
        nameLength.put(length.getKey(),length.getKey().length());
      }
    }

Java-8 also works fine but the terminal operation is useless, how I avoid it without using .foreach() .

nameLength.entrySet().stream().map(s->{
  if(s.getValue() == null){
    nameLength.put(s.getKey(),s.getKey().length());
  }
  return nameLength;
}).collect(Collectors.toList());
System.out.println(nameLength);

Any other way in which I can do the above logic in Java-8 and above??

If you're going to use streams then you should avoid side effects . Functional programming is all about pure operations where the output depends only on the input and functions have no side effects. In other words, create a new map instead of modifying the existing one.

If you do that you might as well just throw away the partially-filled-out map and recompute everything from scratch. Calling String.length() is cheap and it's not really worth the effort to figure out which values are null and which aren't. Recompute all the lengths.

Map<String, Integer> newMap = nameLength.keySet().stream()
    .collect(Collectors.toMap(
        name -> name,
        name -> name.length()
    ));

On the other hand if you just want to patch up your current map streams don't really buy you anything. I'd just modify it in place without involving streams.

for (Map.Entry<String, Integer> entry: nameLength.entrySet()) {
  if (entry.getValue() == null) {
    entry.setValue(entry.getKey().length());
  }
}

Or, as discussed above, you could simplify matters by replacing all of the lengths:

nameLength.replaceAll((name, __) -> name.length());

( __ signifies a variable that isn't used and so doesn't get a meaningful name .)

You almost there, just use the filter to identify the entries with null values and then use Collectors.toMap to collect them into Map with key length as value

Map<String, Integer> nameLengths = nameLength.entrySet()
                 .stream()
                 .filter(entry->entry.getValue()==null)
                 .collect(Collectors.toMap(Map.Entry::getKey, entry->entry.getKey().length()));

Or more simpler way you have that check in Collectors.toMap

  Map<String, Integer> nameLengths = nameLength.entrySet()
                 .stream()
                 .collect(Collectors.toMap(Map.Entry::getKey, entry->entry.getValue() == null ? entry.getKey().length() : entry.getValue()));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM