HashMap in Unary Functional Interface with Lambda in Java 8 - java

I'm studying for Java 8 Lambda and Unary Functional Interface. I have a practice assignment about "Function" class using HashMap, which the following steps to do:
Create a variable of type Function<Set, Map> that receives a Set and creates a HashMap using lambda expressions
Put words in the map, using as key the uppercase first letter of that word
Execute lambda expression and view the result
I trying in the following way, but it doesn't work. I think that the problem is in the lambda expression, but I want to understand how I have to do (for simplicity I put the same word as key). In this way, the result is "null".
import java.util.*;
import java.util.function.Function;
public class FunctionTest {
public static void main(String[] args) {
HashSet<String> hs = new HashSet<String>();
hs.add("ciao");
hs.add("hello");
hs.add("hallo");
hs.add("bonjour");
Function<Set, Map> setToMap = s2 -> (Map) new HashMap().put(s2,s2);
System.out.println(setToMap.apply(hs));
}
}
For the above example, the expected result should be {B=bonjour, C=ciao, H=hello}.

I think this means that you have to add all the words of the Set in the Map following 2 rules
the key is the first letter in uppercase
the value is the word
Function<Set<String>, Map<Character, String>> setToMap = aSet -> {
Map<Character, String> map = new HashMap<>();
for (String s : aSet ) {
map.put(s.toUpperCase().charAt(0), s);
}
return map;
};
// or using Streams :
Function<Set<String>, Map<Character, String>> setToMap = aSet ->
aSet.stream().collect(Collectors.toMap(s -> s.toUpperCase().charAt(0),
Function.identity(),
(oldK, newK) -> oldK)); // merging function in cas of duplicate key
Tip: don't use raw types, but specify them as much as possible:
Function<Set,Map> becomes Function<Set<String>, Map<Character, String>>

I bet that you misunderstood your problem a bit.
You probably want a function that gets the key from the value of each item you have in the set. So:
Set<String> set = new HashSet<>();
set.add("ciao");
set.add("hello");
set.add("bonjour");
Function<String, Character> keyExtractor = s -> Character.toUpperCase(s.charAt(0));
Map<Character, String> map = set.stream()
.collect(Collectors.toMap(keyExtractor, Function.identity()));
This assumes you only have one word for each letter.
If you want to have more than one entry for each first letter then you can do:
Set<String> set = new HashSet<>();
set.add("ciao");
set.add("hello");
set.add("hallo");
set.add("bonjour");
Function<String, Character> keyExtractor = s -> Character.toUpperCase(s.charAt(0));
Map<Character, List<String>> map = set.stream()
.collect(Collectors.groupingBy(keyExtractor));
If you wanted to do it without streams, it will be more complicated but possible:
Function<Set<String>, Map<Character, List<String>>> setConverter = set -> {
Map<Character, List<String>> map = new HashMap<>();
for (String s : set) {
Character key = Character.toUpperCase(s.charAt(0));
map.compute(key, (k, v) -> {
if (v == null) {
List<String> newList = new ArrayList<>();
newList.add(s);
return newList;
} else {
v.add(s);
return v;
}
});
}
return map;
};

public class Main {
public static void main(String[] args) {
HashSet<String> hs = new HashSet<String>();
hs.add("ciao");
hs.add("hello");
hs.add("hallo");
hs.add("bonjour");
//System.out.println(setToList.apply(hs));
Function<Set<String>, Map<String,String>> setToMap = s2 -> {
HashMap<String, String> map = new HashMap<>();
for ( String o : s2)
{
map.put(o.toUpperCase(), o);
}
return map;
};
System.out.println(setToMap.apply(hs));
}

public class FunctionTest {
public static void main(String[] args) {
HashSet<String> hs = new HashSet<String>();
hs.add("ciao");
hs.add("hello");
hs.add("hallo");
hs.add("bonjour");
Function<Set<String>,Map> function=set ->{
Map<String,String> mapSet=new HashMap<>();
set.forEach(valueOfSet->mapSet.put(valueOfSet.substring(0,1).toUpperCase(),valueOfSet));'
return mapSet;
};
System.out.println(function.apply(hs));
}
}
Without Using Function you can do it as below:
Map<String,String> mapSet=new HashMap<>();
hs.forEach(value->mapSet.put(value.substring(0,1),value));
System.out.println(mapSet);

Related

Map of maps to a single map by aggregating keys

I have a structure like this one:
Map<KeyType1, Map<KeyType2, List<ValueType>>>
And also a class holding both KeyType1 and KeyType2, let's call it AggregatedKey. It can be instantiated using its constructor:
public AggregatedKey(KeyType1 keyType1, KeyType2 keyType2)
My goal is to map the structure above to something like:
Map<AggregatedKey, List<ValueType>>
So, basically, the keys should be mapped to a single aggregated key.
How can I achieve that using Java 9?
This will do the trick
Map<KeyType1, Map<KeyType2, List<String>>> m = new HashMap<>();
Map<AggregatedKey, List<String>> result = new HashMap<>();
m.entrySet().forEach(entry -> {
entry.getValue().entrySet().forEach(nestedEntry -> {
result.put(new AggregatedKey(entry.getKey(), nestedEntry.getKey()), nestedEntry.getValue());
});
});
Don't forget to implement hashcode/equals in your AggregatedKey, otherwise you'll have some trouble using the result map.
You can do it like so using streams.
first stream the entry set of the outer map
then invoke flatMap to stream the inner map's entrySet
create the AggregatedKey instance using outerEntry.getKey() and innerEntry.getKey() Note this requires that class to have a constructor accepting the keys.
then put that instance and the value from the inner map (List<ValueType>) in an AbstractMap.SimpleEntry instance to pass to the collector.
create the new map with the key and value of the SimpleEntry
Given the following source map.
Map<KeyType1, Map<KeyType2, List<ValueType>>> map =
new HashMap<>(); // contains the info to be remapped.
Here is the result
Map<AggregatedKey, List<ValueType>> result = map.entrySet()
.stream()
.flatMap(outerEntry-> outerEntry
.getValue().entrySet().stream()
.map(innerEntry -> new AbstractMap.SimpleEntry<>(
new AggregatedKey(outerEntry.getKey(),innerEntry.getKey()),
innerEntry.getValue())))
.collect(Collectors.toMap(
AbstractMap.SimpleEntry::getKey,
AbstractMap.SimpleEntry::getValue));
}
This is one of the ways:
public static void main(String[] args) {
Map<String, Map<String, String>> map = new HashMap<>();
Map<String, String> innerMap1 = new HashMap<>();
Map<String, String> innerMap2 = new HashMap<>();
innerMap1.put("k11", "v11");
innerMap1.put("k12", "v12");
innerMap1.put("k13", "v13");
innerMap2.put("k21", "v22");
innerMap2.put("k22", "v22");
map.put("k1", innerMap1);
map.put("k2", innerMap2);
Map<String, String> result = map
.entrySet()
.stream()
.flatMap(stringMapEntry ->
stringMapEntry
.getValue()
.entrySet()
.stream()
.map(stringStringEntry ->
new AbstractMap.SimpleEntry<String, String>(
buildAggregatedKey(
stringMapEntry.getKey(),
stringStringEntry.getKey()
),
stringStringEntry.getValue()
)
)
).collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue));
System.out.println(result);
}
private static String buildAggregatedKey(String key1, String key2){
return key1 + "_" + key2;
}
Where you change this buildAggregatedKey to meet your aggregation logic.
this is a sample test using streams where in the first step it transforms the inner element of the map and in the second it collects to a Map:
package prove.aggregatemap;
import org.junit.Assert;
import org.junit.Test;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class TestAggregator {
#Test
public void aggregate() {
Map<String, List<String>> letter_map= Map.of("first", List.of("one","two","three"),
"second", List.of("four","five","six"),
"third", List.of("seven","eight","nine"));
Map<String, List<String>> num_map= Map.of("first_num", List.of("1","2","3"), "second_num", List.of("4","5","6"), "third_num", List.of("7","8","9"));
Map<String,Map<String,List<String>>> mapOfMaps=Map.of("letter",letter_map,"num",num_map);
Map<AggregateKey, List<String>> result=mapOfMaps.entrySet().stream().flatMap(entry ->
entry.getValue().entrySet().stream().collect(Collectors.toMap(
inner_entry -> new AggregateKey(entry.getKey(), inner_entry.getKey()),
inner_entry -> inner_entry.getValue())).entrySet().stream()
).collect(Collectors.toMap(entry->entry.getKey(),entry->entry.getValue()));
Assert.assertEquals(List.of("one","two","three"),result.get(new AggregateKey("letter","first")));
Assert.assertEquals(List.of("four","five","six"),result.get(new AggregateKey("letter","second")));
Assert.assertEquals(List.of("seven","eight","nine"),result.get(new AggregateKey("letter","third")));
}
}
public static final class AggregatedKey<K1, K2> {
private final K1 one;
private final K2 two;
public AggregatedKey(K1 one, K2 two) {
this.one = one;
this.two = two;
}
}
public static <K1, K2, V> Map<AggregatedKey<K1, K2>, List<V>> convert1(Map<K1, Map<K2, List<V>>> map) {
Map<AggregatedKey<K1, K2>, List<V>> res = new HashMap<>();
for (Map.Entry<K1, Map<K2, List<V>>> one : map.entrySet())
for (Map.Entry<K2, List<V>> two : one.getValue().entrySet())
res.put(new AggregatedKey<>(one.getKey(), two.getKey()), two.getValue());
return res;
}
public static <K1, K2, V> Map<AggregatedKey<K1, K2>, List<V>> convert2(Map<K1, Map<K2, List<V>>> map) {
return map.entrySet().stream()
.flatMap(e1 -> e1.getValue().entrySet().stream()
.map(e2 -> new AggregatedKey<>(new AggregatedKey<>(e1.getKey(), e2.getKey()), e2.getValue())))
.collect(Collectors.toMap(tuple -> tuple.one, tuple -> tuple.two));
}

creating Map from List is not giving expected result

I have the two list objects as shown below, from which i'm creating the map object.
List<Class1> list1;
List<Class2> list2;
HashMap<String,String> map = new HashMap<>();
for(Class1 one : list1){
if(one.isStatus()){
map.put(one.getID(),one.getName());
}
}
//iterating second list
for(Class2 two : list2){
if(two.isPerformed()){
map.put(two.getID(),two.getName());
}
}
The above code works fine , want the above to be written using streams.
Below is the sample code using streams().
map = list1.stream().filter(one.isStatus()).collect(toMap(lst1 -> lst1.getID(), lst1.getName());
map = list2.stream().filter(...);
But the "map" is not giving the expected result when written using stream() API.
Stream concatenation Stream.concat may be applied here to avoid map.putAll
Map<String, String> map = Stream.concat(
list1.stream()
.filter(Class1::isStatus)
.map(obj -> Arrays.asList(obj.getID(), obj.getName())),
list2.stream()
.filter(Class2::isPerformed)
.map(obj -> Arrays.asList(obj.getID(), obj.getName()))
) // Stream<List<String>>
.collect(Collectors.toMap(
arr -> arr.get(0), // key - ID
arr -> arr.get(1),
(v1, v2) -> v1 // keep the first value in case of possible conflicts
));
The code above uses a merge function (v1, v2) -> v1 to handle possible conflicts when the same ID occurs several times in list1 and/or list2 to keep the first occurrence.
However, the following merge function allows joining all the occurrences into one string value (v1, v2) -> String.join(", ", v1, v2).
I'm not sure what expected result you're not seeing but I created a minimal working example that you should be able to adapt for your own use case.
public class Main {
public static void main(String[] args) {
List<Person> personList = new ArrayList<>();
Map<Integer, String> personMap = personList.stream()
.filter(Person::isStatus)
.collect(Collectors.toMap(person -> person.id, person -> person.name));
}
private static class Person {
public String name;
public int id;
public boolean isStatus() {
return true;
}
}
}
Try this,
List<Class1> list1;
List<Class2> list2;
Map<String, String> map1 = list1.stream().filter(Class1::isStatus).collect(Collectors.toMap(Class1::getId, Class1::getName));
Map<String, String> map2 = list2.stream().filter(Class2::isPerformed).collect(Collectors.toMap(Class2::getId, Class2::getName));
map1.putAll(map2);

how to merge more than one hashmaps also sum the values of same key in java

ı am trying to merge more than one hashmaps also sum the values of same key,
ı want to explain my problem with toy example as follows
HashMap<String, Integer> m = new HashMap<>();
HashMap<String, Integer> m2 = new HashMap<>();
m.put("apple", 2);
m.put("pear", 3);
m2.put("apple", 9);
m2.put("banana", 6);
ı tried putall
m.putAll(m2);
output is as follows
{banana=6, apple=9, pear=3}
but its result is not true for this problem.
ı want to output as
{banana=6, apple=11, pear=3}
how can ı get this result in java?
If you are using Java 8, you can use the new merge method of Map.
m2.forEach((k, v) -> m.merge(k, v, (v1, v2) -> v1 + v2));
This is a very nice use case for Java 8 streams. You can concatentate the streams of entries and then collect them in a new map:
Map<String, Integer> combinedMap = Stream.concat(m1.entrySet().stream(), m2.entrySet().stream())
.collect(Collectors.groupingBy(Map.Entry::getKey,
Collectors.summingInt(Map.Entry::getValue)));
There are lots of nice things about this solution, including being able to make it parallel, expanding to as many maps as you want and being able to trivial filter the maps if required. It also does not require the orginal maps to be mutable.
This method should do it (in Java 5+)
public static <K> Map<K, Integer> mergeAndAdd(Map<K, Integer>... maps) {
Map<K, Integer> result = new HashMap<>();
for (Map<K, Integer> map : maps) {
for (Map.Entry<K, Integer> entry : map.entrySet()) {
K key = entry.getKey();
Integer current = result.get(key);
result.put(key, current == null ? entry.getValue() : entry.getValue() + current);
}
}
return result;
}
Here's my quick and dirty implementation:
import java.util.HashMap;
import java.util.Map;
public class MapMerger {
public static void main(String[] args) {
HashMap<String, Integer> m = new HashMap<>();
HashMap<String, Integer> m2 = new HashMap<>();
m.put("apple", 2);
m.put("pear", 3);
m2.put("apple", 9);
m2.put("banana", 6);
final Map<String, Integer> result = (new MapMerger()).mergeSumOfMaps(m, m2);
System.out.println(result);
}
public Map<String, Integer> mergeSumOfMaps(Map<String, Integer>... maps) {
final Map<String, Integer> resultMap = new HashMap<>();
for (final Map<String, Integer> map : maps) {
for (final String key : map.keySet()) {
final int value;
if (resultMap.containsKey(key)) {
final int existingValue = resultMap.get(key);
value = map.get(key) + existingValue;
}
else {
value = map.get(key);
}
resultMap.put(key, value);
}
}
return resultMap;
}
}
Output:
{banana=6, apple=11, pear=3}
There are some things you should do (like null checking), and I'm not sure if it's the fastest. Also, this is specific to integers. I attempted to make one using generics of the Number class, but you'd need this method for each type (byte, int, short, longer, etc)
ı improve Lucas Ross's code. in stead of enter map by one by in function ı give all maps one times to function with arraylist of hashmap like that
public HashMap<String, Integer> mergeAndAdd(ArrayList<HashMap<String, Integer>> maplist) {
HashMap<String, Integer> result = new HashMap<>();
for (HashMap<String, Integer> map : maplist) {
for (Map.Entry<String, Integer> entry : map.entrySet()) {
String key = entry.getKey();
Integer current = result.get(key);
result.put(key, current == null ? entry.getValue() : entry.getValue() + current);
}
}
return result;
}
}
it works too. thanks to everbody
Assume that you have many HashMaps: Map<String,Integer> map1, map2, map3;
Then you can use Java 8 streams:
Map<String,Integer> combinedMap = Stream.of(map1, map2, map3)
.flatMap(map -> map.entrySet().stream())
.collect(Collectors.groupingBy(Map.Entry::getKey,
Collectors.summingInt(Map.Entry::getValue)));
If the key exists, add to it's value. If not insert.
Here is a simple example which merges one map into another:
Foo oldVal = map.get(key);
if oldVal == null
{
map2.put(key, newVal);
}
else
{
map2.put(key, newVal + oldVal);
}
Obviously you have to loop over the first map so you can process all of it's entries but that's trivial.
Something like this should work:
for (Map.Entry<String, Integer> entry : map.entrySet()) {
String map1_key = entry.getKey();
int map1_value = entry.getValue();
//check:
if(map2.get(map1_key)!=null){
int map2_value = map2.get(map1_key);
//merge:
map3.put(map1_key,map1_value+map2_value);
}else{
map3.put(map1_key,map1_value);
}
}
for (Map.Entry<String, Integer> entry2 : map2.entrySet()) {
String map2_key = entry2.getKey();
int map2_value = entry2.getValue();
//check:
if(map1.get(map2_key)!=null){
int map1_value = map1.get(map2_key);
//merge:
map3.put(map2_key,map1_value+map2_value);
}else{
map3.put(map2_key,map2_value);
}
}

collecting HashMap<String, List<String>> java 8

I want to be able to convert a List to a HashMap where the key is the elementName and the values is a list of something random (in this case its the Element Name). So in short I want (A->List(A), B->List(B), C-> List(C)). I tried using toMap() and passing it the keyMapper and ValueMapper but I get a compilation error. I would really appreciate if someone can help me out.
Thanks!
public static void main(String[] args) {
// TODO Auto-generated method stub
List<String> list = Arrays.asList("A","B","C","D");
Map<String, List<String>> map = list.stream().map((element)->{
Map<String, List<String>> map = new HashMap<>();
map.put(element, Arrays.asList(element));
return map;
}).collect(??);
}
Function<Map<String, String>, String> key = (map) -> {
return map.keySet().stream().findFirst().get();
};
Function<Map<String, String>, String> value = (map) -> {
return map.values().stream().findFirst().get();
};
=== This worked for me
Thanks for all the help guys! #izstas "they should operate on the elements" helped a lot :). Actually this is what I was looking for to be exact
public static void test2 (){
Function<Entry<String, List<String>>, String> key = (entry) -> {
return entry.getKey();
};
Function<Entry<String, List<String>>, List<String>> value = (entry) -> {
return new ArrayList<String>(entry.getValue());
};
BinaryOperator<List<String>> merge = (old, latest)->{
old.addAll(latest);
return old;
};
Map<String, List<String>> map1 = new HashMap<>();
map1.put("A", Arrays.asList("A1", "A2"));
map1.put("B", Arrays.asList("B1"));
map1.put("D", Arrays.asList("D1"));
Map<String, List<String>> map2 = new HashMap<>();
map2.put("C", Arrays.asList("C1","C2"));
map2.put("D", Arrays.asList("D2"));
Stream<Map<String, List<String>>> stream =Stream.of(map1, map2);
System.out.println(stream.flatMap((map)->{
return map.entrySet().stream();
}).collect(Collectors.toMap(key, value, merge)));
}
You can use the groupingBy method to manage aggregation, for example:
public static void main(String[] args) {
List<String> list = Arrays.asList("A", "B", "C", "D", "A");
Map<String, List<String>> map = list.stream().collect(Collectors.groupingBy(Function.identity()));
}
If you want more flexibility (for example to map the value and return a Set instead of a List) you can always use the groupingBy method with more parameters as specified in javadoc:
Map<City, Set<String>> namesByCity = people.stream().collect(Collectors.groupingBy(Person::getCity, mapping(Person::getLastName, toSet())));
Functions key and value you have defined in your code are not correct because they should operate on the elements of your list, and your elements are not Maps.
The following code works for me:
List<String> list = Arrays.asList("A", "B", "C", "D");
Map<String, List<String>> map = list.stream()
.collect(Collectors.toMap(Function.identity(), Arrays::asList));
First argument to Collectors.toMap defines how to make a key from the list element (leaving it as is), second argument defines how to make a value (making an ArrayList with a single element).
Thanks for all the help guys! #izstas "they should operate on the elements" helped a lot :). Actually this is what I was looking for to be exact
public static void test2 (){
Function<Entry<String, List<String>>, String> key = (entry) -> {
return entry.getKey();
};
Function<Entry<String, List<String>>, List<String>> value = (entry) -> {
return new ArrayList<String>(entry.getValue());
};
BinaryOperator<List<String>> merge = (old, latest)->{
old.addAll(latest);
return old;
};
Map<String, List<String>> map1 = new HashMap<>();
map1.put("A", Arrays.asList("A1", "A2"));
map1.put("B", Arrays.asList("B1"));
map1.put("D", Arrays.asList("D1"));
Map<String, List<String>> map2 = new HashMap<>();
map2.put("C", Arrays.asList("C1","C2"));
map2.put("D", Arrays.asList("D2"));
Stream<Map<String, List<String>>> stream =Stream.of(map1, map2);
System.out.println(stream.flatMap((map)->{
return map.entrySet().stream();
}).collect(Collectors.toMap(key, value, merge)));
}

Java Map, filter with values properties

I have a
TreeMap resMap new TreeMap<String, Map<String, String>>();
I would like to filter and keep only entries that values contains a known pair, let's say ('mike' => 'jordan'), and avoid a loop like below
Is there in my included libraries apache.commons and google.common a filter method (that probably would do a loop too, but at least it's less verbose
for (Entry<String, TreeMap<String, String>> el : resMap.entrySet()){
if (el.getValue().get("mike").equals("jordan")){
//
}
}
You can use filters from Guava and the Predicate interface.
Predicate<T> yourFilter = new Predicate<T>() {
public boolean apply(T o) {
// your filter
}
};
So, simple example would be:
Predicate<Integer> evenFilter = new Predicate<Integer>() {
public boolean apply(Integer i) {
return (i % 2 == 0);
}
};
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
Map<Integer, Integer> evenMap = Maps.filterValues(map, evenFilter);
Rather than force your client code to use a filter/loop, build what you need into the API of your class:
public class MyClass {
private TreeMap resMap new TreeMap<String, Map<String, String>>();
public void filter(String key, String value) {
// Some impl here. Either your loop or the guava approach
}
}
BTW, if you use your loop, consider changing to this:
for (Iterator<Map.Entry<String, TreeMap<String, String>>> i = resMap.entrySet().iterator(); i.hasNext();) {
Map.Entry<String, TreeMap<String, String>> entry = i.next();
if (value.equals(entry.getValue().get(key))) {
i.remove();
}
}
The changes to the loop are:
Changed order of equals to avoid NPE
Using iterator to allow removal of entries directly
Even if you don't have a class, you could easily wrap it up in a static method on a utility class, where it could also easily be parameterized to work with any nested map:
public static <K1, K2, V> void filter(Map<K1, Map<K2, V>> map, K2 key, V value) {
// Some impl here
}
Here's a non-guava impl for the static method:
for (Iterator<Map.Entry<K1, Map<K2, V>>> i = map.entrySet().iterator(); i.hasNext();) {
Map.Entry<K1, Map<K2, V>> entry = i.next();
if (value.equals(entry.getValue().get(key))) {
i.remove();
}
}
From #Ferrybig answer in this post.
You can use the Java 8 method Collection.removeIf for this purpose:
map.values().removeIf(Object o -> o.get("mike").equals("jordan"));
This removed all values that match the predicate.
Online demo
This works by the fact that calling .values() for a HashMap returns a collection that delegated modifications back to the HashMap itself, meaning that our call for removeIf() actually changes the HashMap (this doesn't work on all java Map's)
Take a look at Guava's Predicates and Functions.
Here are two examples. The both print the key based on match in the value's properties.
private static void printMatchingEntriesUsingALoop(Map<String, Map<String, String>> resMap, String key, String value) {
for (Map.Entry<String, Map<String, String>> entry : resMap.entrySet())
if (value.equals(entry.getValue().get(key)))
System.out.println(entry.getKey());
}
private static void printMatchingEntriesUsingGuava(Map<String, Map<String, String>> resMap, final String key, final String value) {
Predicate<Map<String, String>> keyValueMatch =
new Predicate<Map<String, String>>() {
#Override
public boolean apply(#Nullable Map<String, String> stringStringMap) {
return value.equals(stringStringMap.get(key));
}
};
Maps.EntryTransformer<String, Map<String, String>, Void> printKeys =
new Maps.EntryTransformer<String, Map<String, String>, Void>() {
#Override
public Void transformEntry(#Nullable String s,
#Nullable Map<String, String> stringStringMap) {
System.out.println(s);
return null;
}
};
Maps.transformEntries(Maps.filterValues(resMap, keyValueMatch), printKeys);
}
public static void main(String... args) {
Map<String, Map<String, String>> resMap = new TreeMap<String, Map<String, String>>();
printMatchingEntriesUsingALoop(resMap, "first", "mike");
printMatchingEntriesUsingGuava(resMap, "first", "mike");
}
One uses a loop and one use Guava.
While the first one performs better, you should really decide which will be the easiest to understand and maintain.
Some suggestions from #missingfaktor. You have to use your own judgement, but he highlighted some of the issues well.
a lot of code duplication.
special case handling.
More cyclomatic complexity.
More chances of error, as a result of first three bullets.
Hard to follow code.
Imagine you are a new developer who has to support this software. Which would you rather be facing?
You can filter the map using java 8 and streams. The first step in this process is converting to a stream using entrySet().stream(). This gives you a Stream<Map.Entry<String, TreeMap<String, String>>. You can then use filter(...) to filter the list. When you filter, you should return true when the incoming value should be included in the filter result. After you filtered the results, you can use foreach to loop over the final result.
The final result will look like the following:
resMap.entrySet().stream()
.filter(e -> el.getValue().get("mike").equals("jordan"))
.foreach(e -> {
// Do something with your entry here
});

Categories

Resources