I came across an interesting problem and was wondering if and how could this be done in Java:
Create a method which can memoize any function/method . The method has the following arguments : the method/function and the argument(s) for it.
For example let's say i have this method :
int addOne(int a) { return a + 1;}
and i call my memoization method two times with the same arguments : addOne and 5 for example, the first call should actually call the addOne method and return the result and also store that result for that given argument. The second time when i call it should know this has been called before and just look up the previous answer.
My idea would be to have something like a HashMap<Callable,HashMap<List<Objects>,Object>> where you would store the previous answers and look them up later on.I think this can be somehow done with lambda expressions but i'm not that familiar with them.I'm not quite sure how to write this method and would appreciate some help.
Can this be done with this approach?
In Java 8 you can use ConcurrentHashMap.computeIfAbsent:
Map<Integer, Integer> cache = new ConcurrentHashMap<>();
Integer addOne(Integer x) {
return cache.computeIfAbsent(x -> x + 1);
}
DZone has a good tutorial which provides a solution that will work for any method:
The Memoizer class is quite simple:
public class Memoizer<T, U> {
private final Map<T, U> cache = new ConcurrentHashMap<>();
private Memoizer() {}
private Function<T, U> doMemoize(final Function<T, U> function) {
return input -> cache.computeIfAbsent(input, function::apply);
}
public static <T, U> Function<T, U> memoize(final Function<T, U> function) {
return new Memoizer<T, U>().doMemoize(function);
}
}
Using this class is also extremely simple:
Integer longCalculation(Integer x) {
try {
Thread.sleep(1_000);
} catch (InterruptedException ignored) {
}
return x * 2;
}
Function<Integer, Integer> f = this::longCalculation;
Function<Integer, Integer> g = Memoizer.memoize(f);
public void automaticMemoizationExample() {
long startTime = System.currentTimeMillis();
Integer result1 = g.apply(1);
long time1 = System.currentTimeMillis() - startTime;
startTime = System.currentTimeMillis();
Integer result2 = g.apply(1);
long time2 = System.currentTimeMillis() - startTime;
System.out.println(result1);
System.out.println(result2);
System.out.println(time1);
System.out.println(time2);
}
Running the automaticMemoizationExample method will produce the following result:
2
2
1000
0
You can memoize any function with Java 8's MethodHandles and lambdas if you're willing to give up type safety on the parameters:
public interface MemoizedFunction<V> {
V call(Object... args);
}
private static class ArgList {
public Object[] args;
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof ArgList)) {
return false;
}
ArgList argList = (ArgList) o;
// Probably incorrect - comparing Object[] arrays with Arrays.equals
return Arrays.equals(args, argList.args);
}
#Override
public int hashCode() {
return args != null ? Arrays.hashCode(args) : 0;
}
}
public static <V> MemoizedFunction<V> memoizeFunction(Class<? super V> returnType, Method method) throws
IllegalAccessException {
final Map<ArgList, V> memoizedCalls = new HashMap<>();
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle methodHandle = lookup.unreflect(method)
.asSpreader(Object[].class, method.getParameterCount());
return args -> {
ArgList argList = new ArgList();
argList.args = args;
return memoizedCalls.computeIfAbsent(argList, argList2 -> {
try {
//noinspection unchecked
return (V) methodHandle.invoke(args);
} catch (Throwable throwable) {
throw new RuntimeException(throwable);
}
});
};
}
Working Example
This creates a variable-arity lambda that encloses the function and is almost as fast as calling the function directly (i.e., no reflection happens inside of call(Object...args)) after the lambda is constructed since we're using MethodHandle.invoke() instead of Method.invoke().
You can still do this without lambdas (replace with anonymous classes) and MethodHandles (replace with Method.invoke), but there will be performance penalties that make this less attractive for performance-conscious code.
Related
Problem: We need to get a (String) key for different classes of objects.
For expendability we want to configure the Method to use to get the key String – instead of implementing many if-else with intanceOf…
Naive solution (with example data) is:
public static String getKey(Object object, Map<Class<?>, Method> keySources) {
Method source = keySources.get(object.getClass());
if (source == null) {
return null;
}
try {
return (String) source.invoke(object);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
throw new RuntimeException("Error at 'invoke': " + e.getMessage(), e);
}
}
public static void main(String[] args) {
Map<Class<?>, Method> keySources = new HashMap<>();
try {
keySources.put(String.class, String.class.getMethod("toString"));
keySources.put(Thread.class, Thread.class.getMethod("getName"));
} catch (NoSuchMethodException | SecurityException e) {
throw new RuntimeException("Error at 'getMethod': " + e.getMessage(), e);
}
System.out.println(getKey("test", keySources));
System.out.println(getKey(new Thread("name"), keySources));
}
Desired solution would be like:
public static String getKey(Object object, Map<Class<?>, Function<Object, String>> keySources) {
Function<Object, String> source = keySources.get(object.getClass());
if (source == null) {
return null;
}
return source.apply(object);
}
public static void main(String[] args) {
Map<Class<?>, Function<Object, String>> keySources = new HashMap<>();
keySources.put(String.class, String::toString);
keySources.put(Thread.class, Thread::getName);
System.out.println(getKey("test", keySources));
System.out.println(getKey(new Thread("name"), keySources));
}
But String::toString is giving compilation error: The type String does not define toString(Object) that is applicable here
Constraints: We cannot modify the classes since they were generated.
I managed to get your code to pass compilation and run. I'm not sure why it works with lambda expressions but not with method references.
Perhaps there are better ways to do this.
public static <T> String getKey(T object, Map<Class<?>, Function<? extends Object, String>> keySources)
{
Function<T, String> source = (Function<T, String>) keySources.get(object.getClass());
if (source == null) {
return null;
}
return source.apply(object);
}
public static void main (java.lang.String[] args) throws Exception
{
Map<Class<?>, Function<? extends Object, String>> keySources = new HashMap<>();
keySources.put(String.class, s -> s.toString());
keySources.put(Thread.class, (Thread t) -> t.getName());
System.out.println(getKey("test", keySources));
System.out.println(getKey(new Thread("name"), keySources));
}
A Function<Object, String> is a function that accepts Object, in other words arbitrary objects as argument, so a function like String::toString, that requires its arguments to be String instances can’t fulfill the contract. That’s easy to fix, as you can use Object::toString instead, however, for Thread::getName, which requires the arguments to be Thread instances, there is no such replacement.
Since you are ensuring that the arguments are of the right type due to the map keys, you can solve this by converting each specific function to a Function<Object,String> that does a type cast:
public static <T,R> void put(Class<T> cl,
Function<T,R> f, Map<Class<?>,Function<Object,R>> map) {
map.put(cl, obj -> f.apply(cl.cast(obj)));
}
public static String getKey(Object object,
Map<Class<?>, Function<Object, String>> keySources) {
return keySources.getOrDefault(object.getClass(), x -> null).apply(object);
}
public static void main(String[] args) {
Map<Class<?>, Function<Object, String>> keySources = new HashMap<>();
put(String.class, String::toString, keySources);
// or put(String.class, Function.identity(), keySources);
put(Thread.class, Thread::getName, keySources);
System.out.println(getKey("test", keySources));
System.out.println(getKey(new Thread("name"), keySources));
}
Function take one parameter, which does not match the signature.
Try using Callable which take no parameter and return a value
So here's a slightly tricky question (for me).
I have a generic object. Call it MyObject. This object has a method which returns something of the type T:
public class MyObject<T>
{
private T _t;
public MyObject(T t)
{
_t = t;
}
//...
public T get()
{
return _t;
}
}
(Obviously my "MyObject" does a bit more but that's the gist).
Now, I want to have a map of this type:
Map<String, MyObject<?>> m = new HashMap<>();
I want to be able to fetch maps using some predefined string name, and these maps can be of any MyObject. For example, I could call:
m.put("map_1", new MyObject<String>("String"));
m.put("map_2", new MyObject<Integer>(new Integer(3));
m.put("map_3", new MyObject<Long>(new Long(5));
etc.
But - and here's the tricky part - I want the map to "remember" the parameterized type of MyObject when I fetch some value from the map. Using
m.get("map_1");
would return a
MyObject<Object>
type, since the map was defined as containing
MyObject<?>
values. Thus:
m.get("map_1").get() // <-- This is an Object, not a String!
What modification (if any) is possible, in order to be able to get the correct - full - information regarding the MyObject fetched object, such that invoking the last line (m.get("map_1")) would return a
MyObject<String>
Thanks :)
Amir.
Typesafe Heterogeneous Containers from Joshua Bloch's Effective Java might work here. Basically you add a Class object to represent the type.
public class MyObject<T>
{
private T _t;
private Class<T> type;
public MyObject( Class<T> type, T t)
{
_t = t;
this.type = type;
}
//...
public T get()
{
return _t;
}
public Class<T> getType() { return type; }
}
Then you could do something like this:
public <T> T get( Map<String, MyObject<?>> map, String key, Class<T> type ) {
return type.cast( m.get( key ).get() );
}
Which is safe and will compile, but will throw a runtime error if you get the type wrong.
(Note I didn't actually compile that, so I might have syntax errors floating around. But most folks don't know how to use Class to cast objects.)
You can get the class.
Class c = m.get("map_1").get().getClass();
if (String.class.equals(c)) {
System.out.println("its a String");
}
Here is a full test.
public class GenericsTest {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
Map<String, MyObject<?>> map = new HashMap<>();
MyObject<String> obj = new MyObject<>("hello");
map.put("greeting", obj);
Class c = map.get("greeting").get().getClass();
if (String.class.equals(c)) {
System.out.println("its a String");
}
}
static class MyObject<T> {
T t;
public MyObject(T t) {
this.t = t;
}
T get() {
return t;
}
}
}
The type system only knows about types, not objects, and therefore can not distinguish "key1" from "key2", because both are of type String.
If keys have different types, the easiest way is to encapsulate a weakly typed map, and use reflective casts to prove to the compiler the types are correct:
class Favorites {
private Map<Class<?>,?> map = new HashMap<>();
<V> V get(Class<V> clazz) {
return clazz.cast(map.get(clazz));
}
<V> void put(Class<V> clazz, V value) {
map.put(clazz, value);
}
}
Favorites favs = new Favorites();
favs.put(String.class, "hello");
favs.put(Integer.class, 42);
favs.get(String.class).charAt(1);
Is there any way to pass a method of a generic type as a parameter?
What I try to achieve is something like this:
ListUtils.mapObjectToField( entries, Contact.getZipCode );
I pass a List<T> and a method from the generic class T.
So far I am fine with the generic List but I am not able to achieve the method call.
public static <T, U> List<U> mapObjectToField( List<T>elements, /*generic method*/ )
{
List<U> result = new ArrayList<>();
for ( T current : elements )
{
result.add(current./*generic method*/);
}
return result;
}
No Java 8 as I am coding for Android min SDK 14.
Probably the best way would be to implement it like Stream.map in Java 8 and provide your own interface, perhaps called Mapper, but to provide an implementation at the call site, you'll have to use an anonymous inner class. Lambdas are much nicer.
It might look like this:
public interface Mapper<T, U> {
U map(T t);
}
ListUtils would like this:
public class ListUtils {
public static List<U> mapObjectToField(List<T> elements, Mapper<T, U> mapper) {
List<U> result = new ArrayList<>();
for (T current : elements) {
result.add(mapper.map(current));
}
return result;
}
}
And you could call it like this:
List<String> zipCodes = ListUtils.mapObjectToField(contacts,
new Mapper<Contact, String>() {
public String map(Contact contact) {
return contact.getZipCode();
}
});
You can define the mapper elsewhere, which will clean up the appearance somewhat, but it won't be as nice as having lambdas.
If you want to use reflection just do like this (But it is not recommended solution),
public static <T, U> List<U> mapObjectToField( List<T>elements, String methodName )
{
List<U> result = new ArrayList<>();
Method method = null;
for ( T current : elements )
{
if(method == null){
try {
method = current.getClass().getDeclaredMethod(methodName);
} catch (Exception e) {
e.printStackTrace();
}
}
U object = (U) invokeMethod(current, method);
result.add(object);
}
return result;
}
public static Object invokeMethod(Object obj , Method method)
{
if (method != null) {
try {
Object value = method.invoke(obj);
return value;
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
You can use Retrolambda to have lambdas and method references also in android SDK 14.
https://github.com/evant/gradle-retrolambda
The code suggested in https://stackoverflow.com/a/42996933/802034 will become:
public void main(){
List<Integer> lengths = mapObjectToField(nCopies(5, "hello"), String::length);
}
public static <T, U> List<U> mapObjectToField(List<T> elements, Mapper<T, U> mapper) {
List<U> result = new ArrayList<>();
for (T current : elements) {
result.add(mapper.map(current));
}
return result;
}
public interface Mapper<T, U> {
U map(T t);
}
}
If you want go further and use Streams, you can on android with this library: https://github.com/aNNiMON/Lightweight-Stream-API
List<Integer> lengths =
Stream.of(nCopies(5, "hello"))
.map(String::length)
.collect(Collectors.toList());
When develop java code, always need extract some property from a list of some object, e.g.
List<Foo> fooList = ...
List<Integer> idList = new ArrayList<>();
for(Foo f : fooList){
idList.add(f.getId());
}
because in production environment we used java7, so I cannot use java8 stream to implement this. So I write an util code to implement this
public static <T, O> List<T> extract(Collection<O> collection, String propertyName) {
List<T> result = new ArrayList<>(collection.size());
for (O o : collection) {
Object val = getFieldValue(propertyName, o);
result.add((T) val);
}
return result;
}
then I implement this just like below
List<Integer> idList = extract(fooList,"id");
but it's not friendly to refactor, if I changed the property name,e.g. id --> fooId, it cannot perceive to this change.
So I want to know how to implement this function refactor friendly and also use it easily?
Even if you don't use Java 8, you can apply the same logic by using a function as next:
public interface Function<T, R> {
/**
* Applies this function to the given argument.
*
* #param t the function argument
* #return the function result
*/
R apply(T t);
}
public static <T, O> List<T> extract(Collection<O> collection, Function<O, T> mapper) {
List<T> result = new ArrayList<>(collection.size());
for (O o : collection) {
result.add(mapper.apply(o));
}
return result;
}
Indeed using a function instead of a String literal is much easier to refactor and much more Object Oriented.
Your method call will then be something like that:
List<Integer> idList = extract(fooList, new Function<Foo, Integer>() {
#Override
public Integer apply(final Foo f) {
return f.getId();
}
});
I think you can have a look to Guava. Guava has a Function interface and
Collections2.transform(Collection<E>, Function<E,E2>) method provides the feature you require. Following is an example:
final Collection<Foo> fooList = ...;
final Collection<Integer> idList =
Collections2.transform(fooList, new Function<Foo, Integer>(){
#Override
public Integer apply(final Foo foo){
return foo.getId();
}
});
Consider the following code:
ICondition searchCondition, scopeCondition...
List<ICondition> filtered = CollectionUtil.filter(
Arrays.asList(searchCondition, scopeCondition),
CollectionUtil.isNonNull);
It fails to compile:
"The method filter(Collection<T>, CollectionUtil.Predicate<T>) in the type CollectionUtil is not applicable for the arguments (List<ICondition>, CollectionUtil.Predicate<Object>)"
Everything is fine if I define an ICondition-specific isNonNull() predicate, but that's dumb and I don't understand what's wrong or how to fix it.
Here are my utility functions:
public interface Predicate<T>
{
boolean apply(T type);
}
public static <T> List<T> filter(Collection<T> target, Predicate<T> predicate)
{
target = Collections.unmodifiableCollection(target);
List<T> result = new ArrayList<T>();
for (T element: target) {
if (predicate.apply(element)) {
result.add(element);
}
}
return result;
}
// This predicate works as expected.
public static CollectionUtil.Predicate<String> isStringNonBlank = new CollectionUtil.Predicate<String>() {
public boolean apply (String item) {
return !StringUtils.isBlank(item);
}
};
// This predicate looks fine, but fails in usage.
public static CollectionUtil.Predicate<Object> isNonNull = new CollectionUtil.Predicate<Object>() {
public boolean apply (Object item) {
return null != item;
}
};
Why can't I use the second predicate with filter()?
It looks like your filter function's predicate parameter is not properly contravariant. Try rewriting it as follows:
public static <T> List<T> filter(Collection<? extends T> source,
Predicate<? super T> predicate)
{
final List<T> result = new ArrayList<T>(source.size());
for (T element: source)
if (predicate.apply(element))
result.add(element);
return result;
}
That says that so long as the predicate function is willing to accept a type no narrower than type T, calling it with an instance of type T (or some type further derived from T) will work fine.
Try generifying isNonNull:
private static class IsNonNullPredicate<T> implements Predicate<T> {
public boolean apply(T item) {
return null != item;
}
}
Now you can return it through a generic method in your util class instead of a constant.
public <T> Predicate<T> isNonNull() {
return new IsNonNullPredicate<T>();
}
Alternatively, just do an unchecked cast on a stored instance instead of creating a new one each time:
private final Predicate isNotNullPredicate = new IsNonNullPredicate();
public <T> Predicate<T> isNonNull() {
return (Predicate<T>) isNotNullPredicate;
}
This is what the Collections class in the Java Collections library does to provide support for generics in its utility methods. Before 1.5 there was Collections.EMPTY_LIST which after generics were added would return a List<Object>. However, that wouldn't give back a suitably generified list so Collections.emptyList() was added to return a List of any type that would fit the calling context.