Hot questions for Converting the Data in Guava

Top 10 Java Open Source / Guava / Converting the Data

How to convert Map<String, String> to Map<Long, String> ? (option : using guava)

Question: I have a Map<String, String> the String key is nothing but numeric value like "123" etc. I'm getting numeric value because this values are coming from the UI in my JSF component. I don't want to change the contract of UI component.

Now I would like to create a Map<Long, String> based on the above Map, I saw some transform methods in the Maps class but all are focusing on the converting value and not key.

Is there any better way to convert Map<String, String> to Map<Long, String> ?

Answer: I would think that you'd have to iterate over the map:

Map<Long, String> newMap = new HashMap<Long, String>();
for(Map.Entry<String, String> entry : map.entrySet()) {
   newMap.put(Long.parseLong(entry.getKey()), entry.getValue());
}

This code assumes that you've sanitized all the values in map (so no invalid long values).

Or you can use streams in Java 8 to do this:

Map<Long, String> newMap = oldMap.entrySet().stream()
  .collect(Collectors.toMap(e -> Long.parseLong(e.getKey()), Map.Entry::getValue));

This assumes that all keys are valid string-representations of Longs. Also, you can have collisions when transforming; for example, "0" and "00" both map to 0L.


Converting a List<String> to a List<Integer> (or any class that extends Number)

Question: I want to create a very generic utility method to take any Collection and convert it into a Collection of a user selectable class that extends from Number (Long, Double, Float, Integer, etc.)

I came up with this code that uses Google Collections (Guava) to transform the Collection and to return an Immutable List.

    public static <T extends Number> List<T> toNumberList(List<String> stringValues, final Class<T> clazz) {
        List<T> ids = Lists.transform(stringValues, new Function<String, T>() {
            @SuppressWarnings("unchecked")
            @Override
            public T apply(String from) {
                T retVal = null;
                if (clazz.equals(Integer.class)) {
                    retVal = (T) Integer.valueOf(from);
                } else if (clazz.equals(Long.class)) {
                    retVal = (T) Long.valueOf(from);
                } else if (clazz.equals(Float.class)) {
                    retVal = (T) Float.valueOf(from);
                } else if (clazz.equals(Double.class)) {
                    retVal = (T) Double.valueOf(from);
                } else {
                    throw new RuntimeException(String.format("Type %s is not supported (yet)", clazz.getName()));
                }
                return retVal;
            }
        });
        return ImmutableList.copyOf(ids);
    }

It can be used like this:

// Convert List<String> to List<Long>
List<Long> ids = MiscUtils.toNumberList(productIds, Long.class);

Is my code overkill or how would you simplify it and at the same time keep it generic enough?

Answer: I think the most important aspect of this code is the Function as opposed to the method itself. I also don't think it makes sense to switch over the subclasses you allow in the Function body, as you already know what type of Number you want to return at the time the Function is created. It's also slightly problematic that your method fails if given, say, BigInteger.class.

Given this, what I would do is create a utility class (let's call it Numbers) and provide methods on it that each return a Function (which can be an enum singleton) for parsing a String as a specific type of Number. That is:

public class Numbers {
  public static Function<String, Integer> parseIntegerFunction() { ... }
  public static Function<String, Long> parseLongFunction() { ... }
  ...
}

They could each be implemented something like this:

public static Function<String, Integer> parseIntegerFunction() {
  return ParseIntegerFunction.INSTANCE;
}

private enum ParseIntegerFunction implements Function<String, Integer> {
  INSTANCE;

  public Integer apply(String input) {
    return Integer.valueOf(input);
  }

  @Override public String toString() {
    return "ParseIntegerFunction";
  }
}

This can then be used however users want:

List<String> strings = ...
List<Integer> integers = Lists.transform(strings, Numbers.parseIntegerFunction());

As a side note, I'd recommend making the return type of any method that returns an ImmutableList be ImmutableList rather than List... it provides information that is useful to clients of the method.


convert MultiLabelDataset<String, String> to Guava Multimap for printing / examining

Question: I'm working with the following program:

public static void main(String[] args) throws Exception
{
    String input = args[0];

    InputStream is = new BufferedInputStream( new FileInputStream( input ) );

    toMultiLabelDataset(is);
    is.close();
}

public static MultiLabelDataset<String, String> toMultiLabelDataset(InputStream is) throws IOException
{
    List<RelationAndMentions> relations = toRelations(is, true);
    MultiLabelDataset<String, String> dataset = toDataset(relations);

    return dataset;
}

As you can see it utilizes a data structure of the form MultiLabelDataset<String, String>, I want to print the contents of that beast in a human intelligabe form. According to my previous searching I can likely use apache string utils or google guava library, is that right? How would I go about going that?

My guess would be that theres an equivalent data struc in those libraries, one that takes <String, String>, I just need to determine what that is, copy the contents of MultiLabelDataset<String, String> and then print? Is that reasonable?

Answer: Assuming it's this MultiLabelDataset, then it's similar to Guava's Multimap and you can convert it easily. However, this conversion will be neither simpler nor smarter than a direct conversion to a String. The only advantage would be that thereafter you can work with a sane Java class having many useful method and working well together with other Java classes.

he whole conversion goes like always, but you need something to iterate the keys. Assuming the only implementation is LabeledLDADataset, it's easy:

Multimap<String, String> toMultimap(MultiLabelDataset<String, String> dataset) {
    Multimap<String, String> result = HashMultimap.create();
    for (Item key : ((LabeledLDADataset) dataset).items()) {
        result.putAll(key.toString(), dataset.getLabels(key));
    }
    return result;
}

Convert java Map to custom key=value string

Question: I have reeMap<String,String> which I need to convert to URI-like string and then back to Map. I need to set custom delimiters.

Is there any tool (Guava, Apache commons?) that can do it for me? I know, I can write simple loops, but I'm looking for one-liner :)

For example

key    value
key1   val1
key2   val2

key1_val1|key2_val2

Answer: could do it in guava via

String string = Joiner.on("|").withKeyValueSeparator("_").join(map);

The opposite is also available via

Map<String, String> map = Splitter.on("|").withKeyValueSeparator("_").split(string);

How can I convert MultiMap<Integer, Foo> to Map<Integer, Set<Foo>> using Guava?

Question: I'm using MultiMap from Google Guava like this:

Multimap<Integer, OccupancyType> pkgPOP = HashMultimap.create();

after inserting values into this multimap, I need to return:

Map<Integer, Set<OccupancyType>>

However, when I do:

return pkgPOP.asMap();

It returns me

Map<Integer, Collection<OccupancyType>>

How can I return Map<Integer, Set<OccupancyType>> instead ?

Answer: Since Guava 15.0 you can use helper method to do this in more elegant way:

Map<Integer, Set<OccupancyType>> mapOfSets = Multimaps.asMap(pkgPOP);

how to convert java Future<V> to guava ListenableFuture<V>

Question: I need to find a way to convert from Future to ListenableFuture. Currently i'm using a service which returns Future but i need to hook up a listener to it. I can't change the service interface as it doesn't belong to me.

Is there a simple way to do that?

Answer: Guava provides the JdkFutureAdapters types for this conversion. The API states Utilities necessary for working with libraries that supply plain Future instances.

For example

Future<?> future = ...;
ListenableFuture<?> listenable = JdkFutureAdapters.listenInPoolThread(future);

But you should use it with care: it's hard to emulate listenable future when you already have submitted task, because there is no way to put a hook on completion there, so Guava takes a new thread and blocks there until original Future is completed.