Although this Piece of code is working, it still grinds my gears:
public static <K, V> Map<K, V> entityListToIdMap(List<? extends BaseEntity<K>> list, Class<K> keyClass) {
Map<K, V> map = new TreeMap<K, V>();
if(list != null){
for (BaseEntity<K> item : list) {
map.put(item.getId(), (V) item);
}
}
return map;
}
What i'm missing is, to tell the method signature, that V extends BaseEntity<K>. This may also lead to the unchecked warning which makes it necessary to cast the item in the value to V.
How can I tell V that it must extend BaseEntity<K>?
based on accepted answer from #Ori Lentz, the complete solution:
public static <K, V extends BaseEntity<K>> Map<K, V> entityListToIdMap(List<V> list, Class<K> keyClass) {
Map<K, V> map = new TreeMap<K, V>();
if (list != null) {
for (V item : list) {
map.put(item.getId(), item);
}
}
return map;
}
Simply define it when you define the generic type:
public static <K, V extends BaseEntity<K>> Map<K, V> entityListToIdMap(..) {
Related
I have a problem here that is probably very simple to solve, but unfortunately I'm still a bit stumped.
public final class ImmutableMap<K, V> extends AbstractReadableMap<K, V>
{
public ImmutableMap(Entry<K, V>[] entry)
{
super();
}
}
I have this class ImmutableMap<K, V> and its constructor.
public interface ReadableMap<K, V>
{
public abstract ImmutableMap<K, V> asImmutableMap();
}
I have this interface ReadableMap<K, V> and its abstract method asImmutableMap.
public abstract class AbstractReadableMap<K, V> implements ReadableMap<K, V>
{
protected Entry<K, V>[] entries;
public ImmutableMap<K, V> asImmutableMap()
{
return ImmutableMap(entries);
}
}
And finally I have this class AbstractReadableMap<K, V> where I'd like to implement the method asImmutableMap(). Unfortunately I get the error The method ImmutableMap(Entry<K,V>[]) is undefined for the type AbstractReadableMap<K,V>.
public class Launcher
{
public static void main(String[] args)
{
MutableMap<String, Integer> map = new MutableMap<String, Integer>();
putEntries(map);
printEntries(map);
ImmutableMap<String, Integer> immutableMap = asImmutableMap(map);
printEntries(immutableMap);
}
}
Same here: The method asImmutableMap(MutableMap<String,Integer>) is undefined for the type Launcher
Why is that and how can I fix it?
Thanks a lot in advance!
I have a method looks like this.
public static <E extends Enum<E> & FieldEnum<E, V>, V>
void fieldValues(class<E> enumType,
Collection<? super V> fieldValues) {
for ( enumConstant : enumType.getEnumConstants()) {
fieldValues.add(enumConstant.fieldValue());
}
}
It might work.
List<Some> list = new ArrayList<>();
fieldValues(Some.class, list);
Now I want to change the method to return the given collection parameter(fieldValues). I did this.
public static <E extends Enum<E> & FieldEnum<E, V>, V, T super V>
Collection<T> fieldValues(Class<E> enumType,
Collection<T> fieldValues) {
for (E enumConstant : enumType.getEnumConstants()) {
fieldValues.add(enumConstant.fieldValue());
}
return fieldValues;
}
And the compiler complains.
com/github/.../lang/FieldEnums.java:[78,61] > expected
com/github/.../lang/FieldEnums.java:[78,62] illegal start of type
com/github/.../lang/FieldEnums.java:[78,69] '(' expected
How can I solve this? What is a proper way to return given collection so that I can do
List<Some> = fieldValues(Some.class, new ArrayList<Some>());
?
I found I just can
public static <E extends Enum<E> & FieldEnum<E, V>, V>
Collection<? super V> fieldValues(
Class<E> enumType, Collection<? super V> fieldValues) {
for (E enumConstant : enumType.getEnumConstants()) {
fieldValues.add(enumConstant.fieldValue());
}
return fieldValues;
}
Is there any other way better than this?
I'm answering for my own question so that anyone who has a similar problem can help themselves.
public static <E extends Enum<E> & FieldEnum<E, V>, V,
T extends Collection<? super V>>
T fieldValues(Class<E> enumType, T fieldValues) {
for (E enumConstant : enumType.getEnumConstants()) {
fieldValues.add(enumConstant.fieldValue());
}
return fieldValues;
}
Now I can do this.
List<Some> list = fieldValues(Some.class, new ArrayList<>());
I have a List<Foo> and want a Multimap<String, Foo> where we've grouped the Foo's by their getId() function.
I am using Java 8 and its almost awesome in that you can do:
List<Foo> foos = ...
Map<String, List<Foo>> foosById = foos.stream().collect(groupingBy(Foo::getId));
However, I have a good amount of code that wants a MultiMap<String, Foo> so this doesnt save me anything and I'm back to using a for-loop to create my Multimap. Is there a nice "functional" way that I am missing?
You can just use the Guava Multimaps factory:
ImmutableMultimap<String, Foo> foosById = Multimaps.index(foos, Foo::getId);
or wrap a call to Multimaps.index with a Collector<T, A, R> interface (shown below, in an unoptimized naive implementation).
Multimap<String, Foo> collect = foos.stream()
.collect(MultimapCollector.toMultimap(Foo::getId));
and the Collector:
public class MultimapCollector<T, K, V> implements Collector<T, Multimap<K, V>, Multimap<K, V>> {
private final Function<T, K> keyGetter;
private final Function<T, V> valueGetter;
public MultimapCollector(Function<T, K> keyGetter, Function<T, V> valueGetter) {
this.keyGetter = keyGetter;
this.valueGetter = valueGetter;
}
public static <T, K, V> MultimapCollector<T, K, V> toMultimap(Function<T, K> keyGetter, Function<T, V> valueGetter) {
return new MultimapCollector<>(keyGetter, valueGetter);
}
public static <T, K, V> MultimapCollector<T, K, T> toMultimap(Function<T, K> keyGetter) {
return new MultimapCollector<>(keyGetter, v -> v);
}
#Override
public Supplier<Multimap<K, V>> supplier() {
return ArrayListMultimap::create;
}
#Override
public BiConsumer<Multimap<K, V>, T> accumulator() {
return (map, element) -> map.put(keyGetter.apply(element), valueGetter.apply(element));
}
#Override
public BinaryOperator<Multimap<K, V>> combiner() {
return (map1, map2) -> {
map1.putAll(map2);
return map1;
};
}
#Override
public Function<Multimap<K, V>, Multimap<K, V>> finisher() {
return map -> map;
}
#Override
public Set<Characteristics> characteristics() {
return ImmutableSet.of(Characteristics.IDENTITY_FINISH);
}
}
Guava 21.0 introduced several methods that return Collector instances which will convert a Stream into a Multimap grouped by the result of applying a function to its elements. These methods are:
ImmutableListMultimap.toImmutableListMultimap — creates an ImmutableListMultimap
ImmutableSetMultimap.toImmutableSetMultimap — creates an ImmutableSetMultimap
Multimaps.toMultimap — Creates a Multimap using the given Supplier
ImmutableListMultimap<String, Foo> foosById = foos.stream().collect(
ImmutableListMultimap.toImmutableListMultimap(
Foo::getId, Function.identity()));
ImmutableSetMultimap<String, Foo> foosById = foos.stream().collect(
ImmutableSetMultimap.toImmutableSetMultimap(
Foo::getId, Function.identity()));
HashMultimap<String, Foo> foosById = foos.stream().collect(
Multimaps.toMultimap(
Foo::getId, Function.identity(), HashMultimap::create)
);
I know, that I can use Raw types to write XMLAdapter, but can I use generic types. I tried reading the API ( link ), but did not even notice a clue about this.
For example map:
I want to use, something like:
#XmlJavaTypeAdapter(GenericMapAdapter<String, Double>.class)//
private final HashMap<String, Double> depWageSum = //
new HashMap<String, Double>();
to get
<depWageSum>
<entry key="RI">289.001</entry>
<entry key="VT">499.817</entry>
<entry key="HI">41.824</entry>
...
<depWageSum>
And class itself would probably look something in the lines of:
#SuppressWarnings("serial") public class GenericMapAdapter<K, V> extends XmlAdapter<GenericMapAdapter.MapType<K, V>, Map<K, V>> {
public static class MapType<K, V> {
#XmlValue protected final List<MapTypeEntry<K, V>> entry = new ArrayList<MapTypeEntry<K, V>>();
public static class MapTypeEntry<K, V> {
#XmlAttribute protected K key;
#XmlValue protected V value;
private MapTypeEntry() {};
public static <K, V> MapTypeEntry<K, V> of(final K k, final V v) {
return new MapTypeEntry<K, V>() {{this.key = k; this.value = v;}};
} } }
#Override public Map<K, V> unmarshal(final GenericMapAdapter.MapType<K, V> v) throws Exception {
return new HashMap<K, V>() {{ for (GenericMapAdapter.MapType.MapTypeEntry<K, V> myEntryType : v.entry)
this.put(myEntryType.key, myEntryType.value);}};
}
#Override public MapType<K, V> marshal(final Map<K, V> v) throws Exception {
return new GenericMapAdapter.MapType<K, V>() {{for (K key : v.keySet())
this.entry.add(MapTypeEntry.of(key, v.get(key)));}};
} }
You will not be able to do this as described. The type parameters will not be retained by the class. However you could introduce some simple subclasses that could leverage the logic from your GenericMapAdapter:
public class StringDoubleMapAdapter extends GenericMapAdapter<String, Double> {
}
Then use the adapter sub class on the property:
#XmlJavaTypeAdapter(StringDoubleMapAdapter.class)//
private final HashMap<String, Double> depWageSum = //
new HashMap<String, Double>();
For more information on XmlAdapter see:
http://bdoughan.blogspot.com/2010/07/xmladapter-jaxbs-secret-weapon.html
One of my favourites from apache commons-collections was the LazyMap which would use a Transformer to instantiate values on the fly when doing map.get(newKey); // Will not return null!.
Why doesn't google collections have the same?
Hey look! It does!
It's called new MapMaker().makeComputingMap(Function<? super K, ? extends V> computer)
Awesome.
Note that map maker is a factory - you can make one, set all the object reference types, expansion properties (and even object expiration time!), and then go about creating lots of computing maps (or other types) with one line calls.
e.g. like pretty much everything else about the google-collections library, it's really good - once you've figured out where 'it' is
since 10.0, guava have a new class CacheBuilder instead, and it's gwt-compatible.
These are the differences.
I suggest to write your own
public class LazyMap<K, V> extends ForwardingMap<K, V> {
final Function<? super K, ? extends V> factory;
final Map<K, V> delegate;
public static <K, V> LazyMap<K, V> lazyMap(final Map<K, V> map, final Supplier<? extends V> supplier) {
return new LazyMap<>(map, supplier);
}
public static <K, V> LazyMap<K, V> lazyMap(final Map<K, V> map, final Function<? super K, ? extends V> factory) {
return new LazyMap<>(map, factory);
}
private LazyMap(final Map<K, V> map, final Function<? super K, ? extends V> factory) {
this.factory = factory;
this.delegate = map;
}
private LazyMap(final Map<K, V> map, final Supplier<? extends V> supplier) {
this.factory = Functions.forSupplier(supplier);
this.delegate = map;
}
#Override
protected Map<K, V> delegate() {
return delegate;
}
#Override
public V get(final Object key) {
if (delegate().containsKey(key) == false) {
#SuppressWarnings("unchecked")
final K castKey = (K) key;
final V value = factory.apply(castKey);
delegate().put(castKey, value);
return value;
}
return delegate().get(key);
}
}