javadictionarysetjava-stream

How to get an array of nested map value properties using the Java Stream API


I am trying and googling and can not get it right. How to write this with stream?

private final ConcurrentMap<UUID, Expression> alleMap = new ConcurrentHashMap<>(1000);

 private String[] getAllDatabases()
  {
     Set<String> allDatabases = new HashSet<>();
     for (Entry<UUID, Expression> entry : alleMap.entrySet())
     {
        allDatabases.add(entry.getValue().getChapter().getDatabaseName());
     }
     List<String> allDatabasesList = new ArrayList<>(allDatabases);
     String[] result = new String[allDatabases.size()];
     for (int i=0; i < result.length; i++)
     {
        result[i] = allDatabasesList.get(i);
     }  
     return result;
  }


alleMap.values().stream().???

The reason I need an Array is that I am writing a Swing application and need the String[] for a JOptionPane question.


Solution

  • Breaking this down for you:

    Set<String> allDatabases = new HashSet<>();
    for (Entry<UUID, Expression> entry : alleMap.entrySet()) {
        allDatabases.add(entry.getValue().getChapter().getDatabaseName());
    }
    

    This is getting all unique database names for all chapters for expressions that are values in your map.

     List<String> allDatabasesList = new ArrayList<>(allDatabases);
     String[] result = new String[allDatabases.size()];
     for (int i=0; i < result.length; i++) {
        result[i] = allDatabasesList.get(i);
     }  
    

    As far as I can tell this is all just to convert the set of database names to an array. If so, you could have just used allDatabases.toArray(new String[allDatabases.size()]. Streams have a similar method (though they take an IntFunction to create an array rather than the new array):

    This translates to:

    alleMap.values().stream()
        .map(Expression::getChapter)
        .map(Chapter::getDatabaseName)
        .distinct()
        .toArray(String[]::new);
    

    Note the distinct to replicate the uniqueness of sets.