Search code examples
javafunctional-programmingjava-8

Java Functional Programming: creating a map of functions


I have a context map, which stores a list sorted in default order.

Map<String,Object> context = new HashMap<String,Object>();
context.put("list_all_content_default",getAllContentSortedDefault());

where getAllContentSortedDefault() returns a List by sorted in default order.

Now, I want to store the same list, in two different orders, lets say by creation date as well.

It is not possible for my clients to retrieve the list and then sort it.

So I have an option to populate the same context map twice with different key

context.put("list_all_content_createdate",getAllContentSortedCreateDate());

But this would mean, storing the same elements in context twice with different keys.

Is it possible in Java 8 to store references of methods in a Map, which can be invoked on call. e.g. something like

    context.put("list_all_content_createdate",{
List<Contents> all_contents =  (List<Contents>)context.get("list_all_content_default");

return Collections.sort(all_contents, new ContentComparatorByCreateDate(); 
});

This would help me save memory , and would create desired sort behaviour.


Solution

  • Yes that's certainly possible. It sounds as though you just need a Comparator passed to your function which you can then sort by. I would suggest returning a Stream rather than a List if possible - then you can sort it yourself.

    I'm assuming that your map needs to store multiple lists and the caller passes a key to specify the one they want. If you only have one list then you obviously don't need the map.

    Map<String,List<Content>> contents = new HashMap<>();
    contents.put("first", getMyContents());
    
    public Stream<Content> getMySortedContent(Comparator comparator) {
        return contents.get("first").sorted(comparator);
    }
    

    If you really just have one list and you want to store the comparators in your map:

    Map<String,Comparator<Content>> comparatorMap = new HashMap<>();
    comparatorMap.put("byCreateDate", Comparator.comparingBy(Content::getData));
    comparatorMap.put("byName", Comparator.comparingBy(Content::getName));
    
    public Stream<Content> getSortedContent(String comparatorKey) {
        return getContentList().stream()
            .sorted(comparatorMap.get(comparatorKey));
    }
    

    Finally, if you really want to have a map to methods that retrieve a sorted list then you can certainly do that as well:

    Map<String,Supplier<List<Content>>> supplierMap = new HashMap<>();
    supplierMap.put("unsorted", this::unsortedList);
    supplierMap.put("sorted_by_date" this::sortedByDate);
    
    public List<Content> getContents(String supplierKey) {
        return supplierMap.get(supplierKey).get();
    }
    
    private List<Content> unsortedList() {
        return contentsList;
    }
    
    private List<Content> sortedByDate() {
        Collections.sort(contentsList, Comparator.comparingBy(Content::getDate));
        return contentsList;
    }
    

    I don't like the final approach much.

    Let me know if any of that is confusing you and I'll add further explanation.