How can I map a String to a function in Java? - java

Currently, I have a bunch of Java classes that implement a Processor interface, meaning they all have a processRequest(String key) method. The idea is that each class has a few (say, <10) member Strings, and each of those maps to a method in that class via the processRequest method, like so:
class FooProcessor implements Processor
{
String key1 = "abc";
String key2 = "def";
String key3 = "ghi";
// and so on...
String processRequest(String key)
{
String toReturn = null;
if (key1.equals(key)) toReturn = method1();
else if (key2.equals(key)) toReturn = method2();
else if (key3.equals(key)) toReturn = method3();
// and so on...
return toReturn;
}
String method1() { // do stuff }
String method2() { // do other stuff }
String method3() { // do other other stuff }
// and so on...
}
You get the idea.
This was working fine for me, but now I need a runtime-accessible mapping from key to function; not every function actually returns a String (some return void) and I need to dynamically access the return type (using reflection) of each function in each class that there's a key for. I already have a manager that knows about all the keys, but not the mapping from key to function.
My first instinct was to replace this mapping using if-else statements with a Map<String, Function>, like I could do in Javascript. But, Java doesn't support first-class functions so I'm out of luck there. I could probably dig up a third-party library that lets me work with first-class functions, but I haven't seen any yet, and I doubt that I need an entire new library.
I also thought of putting these String keys into an array and using reflection to invoke the methods by name, but I see two downsides to this method:
My keys would have to be named the same as the method - or be named in a particular, consistent way so that it's easy to map them to the method name.
This seems WAY slower than the if-else statements I have right now. Efficiency is something of a concern because these methods will tend to get called pretty frequently, and I want to minimize unnecessary overhead.
TL; DR: I'm looking for a clean, minimal-overhead way to map a String to some sort of a Function object that I can invoke and call (something like) getReturnType() on. I don't especially mind using a 3rd-party library if it really fits my needs. I also don't mind using reflection, though I would strongly prefer to avoid using reflection every single time I do a method lookup - maybe using some caching strategy that combines the Map with reflection.
Thoughts on a good way to get what I want? Cheers!

There aren't any first-class standalone functions, but you can do what you want with an interface. Create an interface that represents your function. For example, you might have the following:
public interface ComputeString
{
public String invoke();
}
Then you can create a Map<String,ComputeString> object like you want in the first place. Using a map will be much faster than reflection and will also give more type-safety, so I would advise the above.

While you can't have first class functions, there are anonymous classes which can be based on an interface:
interface ProcessingMethod {
String method();
}
Map<String, ProcessingMethod> methodMap = new HashMap<String, ProcessingMethod>();
methodMap.put("abc", new ProcessingMethod() {
String method() { return "xyz" }
});
methodMap.put("def", new ProcessingMethod() {
String method() { return "uvw" }
});
methodMap.get("abc").method();
Or you could use Scala :-)

Couldn't you do String to Method? Then you can cache the methods you need to execute.

This example uses an enum of named functions and an abstract FunctionAdapter to invoke functions with a variable number of homogeneous parameters without reflection. The lookup() function simply uses Enum.valueOf, but a Map might be worth it for a large number of functions.

As you've noticed, you can do what you want using the Reflection API, but you loose some benefits of the Java compiler, on top of the issues you've already come up with. Would wrapping your Strings in an object and using the Visitor pattern solve your issue? Each StringWrapper would only accept a Visitor that has the right method, or something along those lines.

Use a Map where the key is a string and the value is an object that implements an interface containing method(). That way you can get the object containing the method you want out of the map. Then just call that method on the object. For example:
class FooProcessor implements Processor{
Map<String, FooMethod> myMap;
String processRequest(String key){
FooMethod aMethod = myMap.getValue(key);
return aMethod.method();
}
}

What about Method class from the reflection API? You can find methods of a class based on name, parameters, or return type. Then you just call Method.invoke(this, parameters).
That's pretty much the same as a Map from JavaScript you are talking about.

public class CarDetailsService {
private final CarRepository carRepository;
private final Map<String, Function<CarDTO, String>> carColumnMapper = new HashMap<>();
public ApplicationDetailsServiceImpl(CarRepository carRepository) {
this.carRepository = carRepository;
//---- Initialise all the mappings ------- //
carColumnMapper.put("BRAND", CarDTO::getBrandName);
carColumnMapper.put("MILEAGE", CarDTO::getMileage);
}
public Map<String, List<CarDTO>> getListOfCars(String groupBy) {
return carRepository.findAll()
.stream()
.map(toCarDTO)
.collect(groupingBy(carColumnMapper.get(groupBy.toUpperCase())));
}
Function<CarDetails, CarDTO> toCarDTO = (carDetails) -> CarDTO
.builder()
.brand(carDetails.getBrand())
.engineCapacity(carDetails.getEngineCapacity())
.mileage(carDetails.getMileage())
.fuel(carDetails.getFuel())
.price(carDetails.getPrice())
.build();
}

Related

Java 8 functional interfaces verses functions

Suppose I have an application that needs to apply several custom transformation on strings. The needs will grow by time. The following two approaches do exactly the same thing, but I am wondering which one is more beneficial in the long run. Are they the same? Or, does one offer more benefits than the other as the number of transforms increase and vary?
Suppose we have these:
public static final String PL = "(";
public static final String PR = ")";
public static final String Q1 = "'";
Here is each approach's setup and usage.
Approach 1:
#FunctionalInterface
public interface StringFunction {
String applyFunction(String s);
}
public class StrUtils {
public static String transform(String s, StringFunction f) {
return f.applyFunction(s);
}
public static String putInQ1(String s) {
return Q1.concat(s).concat(Q1);
}
public static String putInParens(String s) {
return PL.concat(s).concat(PR);
}
// and so on...
}
Which I would use like this:
System.out.println(StrUtils.transform("anSqlStr", StrUtils::putInQ1));
System.out.println(StrUtils.transform("sqlParams", StrUtils::putInParens));
Approach 2:
Here, I use straightforward Function:
Function<String, String> putInQ1 = n -> Q1.concat(n).concat(Q1);
Function<String, String> putInParens = n -> PL.concat(n).concat(PR);
// and so on...
Which I would use like this:
System.out.println(putInQ1.apply("anSqlStr");
System.out.println(putInParens.apply("sqlParams");
You sketched two ways of offering a certain functionality
The first one is to explicitly offer it as a method
public static String putInQ1(String s) {
return Q1.concat(s).concat(Q1);
}
which is supposed to be used via a method reference.
The second one is to offer it as a Function object:
Function<String, String> putInQ1 = n -> Q1.concat(n).concat(Q1);
(Here, you did not say where these instances should be located. I assume that you would also create a class that contained all these Function instances as (possibly public static final fields)
JBNizet mentioned a third option: You could use the methods directly, and not via method references. Indeed, the purpose of the transform function is not entirely clear. The only justification for this would be that you want to pass in arbitrary method references there, but these method references would just be Function objects - like in the second approach...
However, in a technical sense, the difference is not so large. Just to illustrate the point: Both approaches can trivially be converted into each other! The method can be implemented based on the function object
public static String putInQ1(String s) {
return putInQ1.apply(s);
}
And a function object can be created from the method reference:
Function<String, String> putInQ1 = StringUtils::putInQ1;
So the main question may be: How do you want to offer this functionality to the user of your library?
For this, consider the use case the you have an input string, and want to put it into ( parentheses ), and the result into ' single quotes ':
String doItWithMethodReferences(String input) {
String result = input;
result = StrUtils.transform(result, StrUtils::putInParens);
result = StrUtils.transform(result, StrUtils::putInQ1);
return result;
}
String doItWithFunctionObjects(String input) {
String result = input;
result = StringFunctions.putInParens.apply(result);
result = StringFunctions.putInQ1.apply(result)
return result;
}
String doItWithMethods(String input) {
String result = input;
result = StrUtils.putInParens(result);
result = StrUtils.putInQ1(result);
return result;
}
You can see that there is hardly a difference between the approaches that would qualify one of them as "better" or "worse" than the other in terms of readability, except for the obvious fact that the last one is simpler than the first one by avoiding the unnecessary transform calls.
Of course, each of these methods could be written "more compactly", in a single line. But depending on the number and the structure of the operations, this could severely reduce the readability, and in fact, this leads to another point: I could imagine that extensibility may something to consider. Imagine you wanted to create a single operation that placed a string into '( single quotes and parentheses )' at once.
With methods:
public static String putInPandQ1(String s) {
return putInQ1(putInParens(s));
}
With functions:
Function<String, String> putInPandQ1 = putInParens.andThen(putInQ1);
I think that the andThen function would be a nice feature that helps to compose more complex string manipulations.
(But taking that arbitrarily far, one has to ask whether you are not actually attempting to implement a template engine or a new domain-specific programming language...)
A short note: All this seems fairly unrelated to performance. Whether you do return s0 + s1; or return s0.concat(s1) will often not matter, and in the few cases where it does matter, you can change the implementation later - because, given the functionality that is sketched in the question, the decision about using + or concat or some StringBuilder trickery is exactly that: An implementation detail.
And another note, as pointed out in the comments: Instead of defining your own StringFunction interface, you could use UnaryOperator<String>. Both are "structurally equal", but the first one is part of the standard API. Imagine that there are already many libraries out there, with methods that expect the standard UnaryOperator<String> as an argument. When you only have instances of your own StringFunction, then you may have to convert these instances so that your code can cooperate with other code. This is trivial, of course, but the interfaces in the functional package are carefully chosen to cover a large range of application cases, and I think that the interoperability between libraries can be greatly increased when programmers don't needlessly create new interfaces that already exist in the standard API. One could argue that the introduction of the StringFunction makes code easier, because it does not need the <String> generic parameter. But if you want this, then you should simply declare the iterface as interface StringFunction extends UnaryOperator<String> { }, which simply is a further specialization, and will keep the compatibility with other code. Additionally, you'll then conveniently inherit all the default methods from Function, like the andThen that I mentined above.
Why not simply define the method 'putInWhatever(String s, String left, String right) {
return left + s + right;
}
with overloaded variants in case left and right are equal. No complicated functional interfaces and lambda's needed

Can I enforce immutability of individual elements in a collection using plain JDK framework?

I know there are wrapper methods like Collections#unmodifiableSet and its other variations like Collections#unmodifiableMap, Collections#unmodifiableList etc which makes the collection immutable provided that the client only accesses the collection through the reference returned by these methods and not directly. But does it prevent the individual objects in the collections to be immutable? Can I achieve the same using standard JDK classes and not apis like Google Guava?
No, you have to make yourself immutable versions of your classes.
Sample :
List< StringBuilder > l1 = new LinkedList< StringBuilder >();
l1.add( new StringBuilder()); // ok
List< StringBuilder > l2 = Collections.unmodiableList( l1 );
l2.get(0).append( "Hello" ); // ok, because StringBuilder, unlike String is mutable
l2.add( new StringBuilder()); // throws exception
The only way I could think of making a class immutable that wasnt designed to be so is to wrap it in a Proxy - you could then access control any mutating methods:
ie.
MyClass {
private int anInt;
public void setInt(int a) {
anInt = a;
}
public int getInt() {
return anInt;
}
...
and then
MyProxy {
private MyClass myClass = ...;
public int getInt() {
return myClass.getInt();
}
...
and so on.
You could also achieve the same thing through reflection (in the same way Spring wraps beans and you only generally interact with their proxies)
Not though that if a client got hold of the actual underlying class (MyClass in this example) then they would be able to mutate the internals. Theres no real way to stop this directly, other than only ever exposing the "mutable" wrappers you let clients see
If i understand your goal. You can use something like this
class Wraper<T>{
List<T> list = new ArrayList<T>(); //Other Collection?
T someObj = getYourInstance();
public T get(int index) {
T obj = list.get(index);
if (obj.equals(someObj)){//should be overriden
return createInstanceOf(obj);
} else {
return obj;
}
}
}
You are asking for the equivalent of const in Java. Which is not possible. This has been requested by many users as an enhancement to Java (including myself) over the years. It was closed and rejected by Sun.
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4211070
If you want to do this, you will have to build a mutability flag into your object (probably at construction time). And then in every mutator method, check the mutability flag. Perhaps you might be able to do something more "fancy" using a proxy library such as CGLIB, but it might be overly complicated for what you are trying to achieve.

Call a function from a string array (Java or Groovy)

In Java, or Groovy, say I have a String array like
myArray = ["SA1", "SA2", "SA3", "SA4"]
I want to call a different function based off of each string.
class Myclass{
public static void SA1() {
//doMyStuff
}
public static void SA2() {
//doMyStuff
}
...etc
}
I would love to be able to loop through my array and call the functions that they pertain to without having to compare the string or make a case statement. For example is there a way to do something like the following, I know it doesn't currently work:
Myclass[myArray[0]]();
Or if you have suggestions of another way I can structure something similar.
In groovy you can do:
Myclass.(myArray[0])()
In Java you can do:
MyClass.class.getMethod(myArray[0]).invoke(null);
In Groovy, you can use a GString for dynamic method invocation:
myArray.each {
println Myclass."$it"()
}
You can, for instance, declare an interface such as:
public interface Processor
{
void process(String arg);
}
then implement this interface, for example in singletons.
Then create a Map<String, Processor> where keys are your strings, values are implementations and, when invoking:
Processor p = theMap.containsKey(theString)
? theMap.get(theString)
: defaultProcessor;
p.process(theString);
I suggest you look at Reflection APIs, to call methods at runtime
check Reflection docs
Class cl = Class.forName("/* your class */");
Object obj = cl.newInstance();
//call each method from the loop
Method method = cl.getDeclaredMethod("/* methodName */", params);
method.invoke(obj, null);

Better way to convert an List<MyDataType> to List<String>

I am wondering if there isn't a better way to convert whole Lists or Collections as the way I show in the following code example:
public static List<String> getAllNames(List<Account> allAccounts) {
List<String> names = new ArrayList<String>(allAccounts.size());
for (Account account : allAccounts) {
names.add(account.getName());
}
return names;
}
Every time I produce a method like this, I start thinking, isn't there a better way? My first thought would be to create maybe a solution with some generics and reflections, but this seems maybe a bit over sized and maybe a bit to slow when it comes to performance?
Take a look at Google's Guava library
Something like this should do it
final List<String> names = Lists.transform(myObjs, new Function<MyObject, String>() {
public String apply(final MyObject input) {
return input.getName();
}
});
With Guava, there is a more functional approach:
return FluentIterable.from(allAccounts).transform(new Function<Account,String>(){
public String apply(Account account){return account.getName();}
}).toImmutableList()
But that essentially does the same thing, of course.
BTW: the difference between this answer and RNJ's is that in my case the list will be created once, while in the other answer it's a live view. Both versions are valid, but for different scenarios.
I actually have exactly this kind of method in my personal library.
public static <TSource,TTarget> List<TTarget> castList(List<TSource> sourceList)
{
List<TTarget> targetList = new ArrayList<TTarget>(sourceList.size());
for (TSource t : sourceList) {
//This will throw a ClassCastException if the types are not compatible
//Be carefull
targetList.add((TTarget)t);
}
return targetList;
}
Usage is very simple because the compiler infers the type for TTarget.
List<Object> objects = new ArrayList<Object>();
objects.add("One");
objects.add("Two");
List<String> strings = castList(objects);
Regarding the performance:
I think using generics is no problem here. But the need to copy the whole array is another story.
There is no better way. Casting is a difficult and dangerous thing. In your example, your are not able to cast a String to a MyDataType or vice versa, aren't you?
You might create an own List-Implementation with some kind of toStringList()-Method if you need these more often.
There's a simple way but it is not type safe
List<A> a = new ArrayList<A>();
List<B> b = (List)a;
but then you have to override the implementation of toString() method of your class to return the getName() value.
But there's no type checking,
And as mentioned you can of course do instead a loop and call getName on every object
You could try using the Iterables and Function classes from the Guava libraries. You can create a new type of an Iterable using,
Iterable<String> newTypeIterable = Iterables.transform(oldTypeIterable, new Function<MyDataType, String> () {
#Override
public String apply(MyDataType from)
{
return from.getName();
}
});
Turns out you can do this with the Lists class too!

How to create an object in a utility class based on if statement in Java? (Or based on a particular string)

I would have a string that is parsed into an array, as shown here:
class Example extends ParentClass {
private String[] array;
public static Example parseString(String lineToParse) {
array = lineToParse.split("\");
}
public ObjectType1() { // arguments: String, String, String
}
public ObjectType2() { // arguments: String, String, String, double, double
}
}
What I'm wondering is could I do this?
if (array[0].equals("Test")) {
public ObjectType1()
}
Or is there a better way to do this?
I want to create various objects with different arguments each, and the first argument (array[0]) will be applicable to each object, so I was wondering if I could create objects within an if statement like this, or a switch (not sure if that would work either).
I believe a factory method would be useful for you, one that returns instances of classes according to the parameter received:
// ObjectType1, ObjectType2, ObjectType3 inherit from ObjectType
static ObjectType getInstance(String[] array) {
if (array[0].equals("Test"))
return new ObjectType1(array);
else if (array[0].equals("Test2"))
return new ObjectType2(array);
else
return new ObjectType3(array);
}
For the record, actually you can define a class inside a method, this is valid code in Java ... of course, that's hardly a good thing to do:
// ObjectType1, ObjectType2 inherit from ObjectType
public ObjectType example(String[] array) {
if (array[0].equals("Test")) {
class ObjectType1 {
ObjectType1(String[] array) {
}
}
return new ObjectType1(array);
}
else {
class ObjectType2 {
ObjectType2(String[] array) {
}
}
return new ObjectType2(array);
}
}
"Creating" an object means "instantiating it", with new:
ObjectType1 foo = new ObjectType1(...);
You can do that anywhere it's legal to instantiate a class, including in an if statement.
You cannot define classes in arbitrary locations, however.
If you just want to call a method (which should start with a lower-case letter if you want Java developers to understand what you're trying to do), you can call it from anywhere, including inside if statements.
This sounds like you may want to use a [static factory method][1].
[1]: http://en.m.wikipedia.org/wiki/Factory_method_pattern
I guess that you want to dynamically create objects based on a configuration file?
There are lots of ways to achieve this. One simple way is to use reflection to create the objects. Then you do not need any if/switch statements, and if you want to create a new type of object your code does not need to be changed.
Here are some examples for using reflection: Reflection API Code Samples

Categories