Function to add Numbers and Strings using Generics - java

In an interview, I was asked to write a function using Generics that adds the numbers and Strings passed to it. The number could be Integer, Double, etc.
If 2 strings are passed to the function, it should append the strings. Finally, the added result should be returned.
I used Lambda as mentioned below.
public class WorkAround {
public static void main(String[] args) {
MyAdd myAdd = new MyAdd();
System.out.println("Adding Integers: " + myAdd.add(1, 2, (a,b) -> a+ b));
System.out.println("Adding Double: " + myAdd.add(1.2, 1.2, (a,b) -> a+ b));
System.out.println("Adding String: " + myAdd.add("James ", "Bond", (a,b) -> a + b));
}
}
class MyAdd {
public <T> T add(T a, T b, BinaryOperator<T> operation) {
return operation.apply(a, b);
}
}
Output:
Adding Integers: 3
Adding Double: 2.4
Adding String: James Bond
But then, I was asked to achieve the same result with Generics alone. Something like the below code snippet.
public class Trial {
public static void main(String[] args) {
MyAdd myAdd = new MyAdd();
System.out.println("Adding Integers: " + myAdd.add(1, 2));
System.out.println("Adding Double: " + myAdd.add(1.2, 1.2));
System.out.println("Adding String: " + myAdd.add("James ", "Bond"));
}
}
class MyAdd {
public <T> T add(T a, T b) {
return a + b;
}
}
Obviously, this did not work because of the following.
The operator + is undefined for the argument type(s) T, T
I found this thread the closet to my question. But that question did not handle Strings. Is there any other way that I might be missing?

We have 2 cases, String or Number. This differentiation should be made.
The following solves the problem.
import java.math.BigDecimal;
public class Trial {
public static void main(String[] args) {
MyAdd myAdd = new MyAdd();
System.out.println("Adding Integers: " + myAdd.add(1, 2));
System.out.println("Adding Double: " + myAdd.add(1.2, 1.2));
System.out.println("Adding String: " + myAdd.add("James ", "Bond"));
}
}
class MyAdd {
public String add(String a, String b) {
return a + b;
}
public <T extends Number> T add(T a, T b){
return (T) new BigDecimal(a.toString()).add(new BigDecimal(b.toString()));
}
}

Related

Error Storing static function from another class in BiFunction

I have two classes and, in one of them, I want to create a variable that will hold a function from the other class. I want to do this so I can change behaviour dinamically conditionally.
I tried the following prototype which results in a compilation error:
class A {
public String myFn(int a, int b) {
return "<" + a + " " + b + ">";
}
public String myFn2(int a, int b) {
return "(" + a + " " + b + ")";
}
}
class B {
static int mode = 1;
public void fn() {
BiFunction<Integer, Integer, String> fn = null;
if(mode == 1) {
fn = ClassA.myFn(); // This results in an error "Cannot resolve method fn()".
}
else {
//fn = ClassA.myFn2();
}
// next I will use fn ...
}
}
This results in an error "Cannot resolve method fn()".
How can I store the function?
Thanks.
Calling ClassA.myFn() would require the method to be static and this is a method call, you wan't to store the method, not calling it.
Lambda
BiFunction<Integer, Integer, String> fn = null;
if(mode == 1) {
fn = (a, b) -> ClassA.myFn(a, b);
}
Method reference
BiFunction<Integer, Integer, String> fn = null;
if(mode == 1) {
fn = ClassA::myFn;
}
⚠️ Also
both myFn and myFn2 should be static
public static String myFn(int a, int b) {
return "<" + a + " " + b + ">";
}
chosse ClassA or A but they should be matching
class ClassA {
Your method myFn is not static, so you can't access it in a static context like you are trying to do. Your class is also called A, but you reference it as ClassA. Also, when assigning the BiFunction, you assign it to the return value, when you want a lambda expression. Here's an edited copy of your example:
class A {
public static String myFn(int a, int b) { //notice the static keyword
return "<" + a + " " + b + ">";
}
public static String myFn2(int a, int b) { //notice the static keyword
return "(" + a + " " + b + ")";
}
}
class B {
static int mode = 1;
public void fn() {
BiFunction<Integer, Integer, String> fn = null;
if(mode == 1) {
fn = A::myFn; // use a lambda expression, and class is named A
}
else {
//fn = A::myFn2;
}
// next I will use fn ...
}
}

How to pass methods as parameters? [duplicate]

This question already has answers here:
Java Pass Method as Parameter
(17 answers)
How to pass a function as a parameter in Java? [duplicate]
(8 answers)
Closed 3 years ago.
I have a class with bunch of methods. In another class, I need to write a method, that handles the input values. To that method, I want to pass the method of the class that I want to call. How can we do that with Java after 1.8?
There are similar questions already, but those usually assume that we can use an interface with a single method, therefore can use lambda expressions, etc.
class MyClass {
public Object myToString(String a) {
return new String(a);
}
public Object myToString(String a, String b) {
return new String(a + ", " + b);
}
public Object mySum(int a) {
return new Integer(a);
}
public Object mySum(int a, int b) {
return new Integer(a + b);
}
}
class Test {
public Object handleInputs(MyClass myClass, MethodAsParameter theMethod, List<Object> inputs) {
if (type of inputs are Strings) {
myClass.myToString(inputs.get(0));
} else if (.....) {
myClass.mySum(inputs.get(0));
}
}
}
Since Java 8 you can use method reference. Method references can be assigned to Function<A, B> functional interface variables and their subclasses.
For example, method with such signature:
class Test {
public static int DoSomething(String s) {...}
}
can be assigned to a Function<String, Integer> variable like:
Function<String, Integer> method = Test::DoSomething;
and then called:
int result = method.apply("Hello!");
So with small improvements in your code, this is the way you can use your methods as method references and passed to other function as parameters.
class MyClass {
public static String myToString(String a, String b) {
return a + ", " + b;
}
//notice the boxing in here
public static int mySum(int a, int b) {
return a + b;
}
//not kind of an revolutionary function, just for demonstration
public static<T> T Invoke(BinaryOperator<T> bo, T o1, T o2) {
return bo.apply(o1, o2);
}
public static void main(String[] args) {
int sum = Invoke(MyClass::mySum, 10, 20);
String str = Invoke(MyClass::myToString, "a", "b");
System.out.println(sum);
System.out.println(str);
}
}
I think something like this is as far as you would get:
import java.util.List;
import java.util.Arrays;
import java.util.function.Function;
import java.util.function.BiFunction;
class MyClass {
public Object myToString(String a) {
return new String(a);
}
public Object myToString(String a, String b) {
return new String(a + ", " + b);
}
public Object mySum(int a) {
return Integer.valueOf(a);
}
public Object mySum(int a, int b) {
return Integer.valueOf(a + b);
}
}
public class MethodParams {
public static Object handleInputs(Function<Object,Object> method, List<Object> inputs) {
return method.apply(inputs.get(0));
}
public static Object handleInputs(BiFunction<Object,Object,Object> method, List<Object> inputs) {
return method.apply(inputs.get(0), inputs.get(1));
}
public static void main(String args[]) {
MyClass mc = new MyClass();
String str = (String)handleInputs((a) -> mc.myToString((String)a), Arrays.asList("string"));
System.out.println(str); // string
Integer sum = (Integer)handleInputs((a) -> mc.mySum((int)a), Arrays.asList(1));
System.out.println(sum); // 1
Integer sum2 = (Integer)handleInputs((a,b) -> mc.mySum((int)a, (int)b), Arrays.asList(1, 2));
System.out.println(sum2); // 3
}
}
Not very nice, but at least you have some leeway as to which method you want to use. Code as demonstrated here has lots of casts due to using Objects - using generic types as demonstrated by t2dohx is better way of doing this, but even further from your question.
Here is a simple example:
public class TestMain {
public static void main(String [] args) {
Long a = 15L, b = 20L;
Long sum = combineTwoNumbers(a, b, (p1, p2) -> p1 + p2);
Long product = combineTwoNumbers(a, b, (p1, p2) -> p1 * p2);
System.out.println("Sum is " + sum);
System.out.println("Product is " + product);
}
public static Long combineTwoNumbers(Long a, Long b, BiFunction <Long, Long, Long> combiner) {
return combiner.apply(a, b);
}
}
Here, the functional parameter is BiFunction, which takes two parameters in input and returns an output. Specifically, it takes two long numbers and produces a third one as a result. The name of the method is kept generic so that it can cover more instances of different functions that may take place. In our example we are passing a sum and a product function as you can see.

print N-Dimensional array in java

I want a generic method to print all the elements of a multidimensional array.
In the below code i am able to print all the elements of any multidimensional array which belongs to the parent Object class but not of any primitive types.
Is it possible to print all elements of a multidimensional array of primitive type.
One more doubt if int value can be hold in a Object type then why not int[] can be cast to Object[] but, String[] can be cast to Object[].
public class MultiDimension {
public static void main(String[] args) {
//final String ar[][][] = {{{"1","2"},{"3","4","5"}},{{"6","7","8"}},{{"9","10"},{"11"},{"12","13","14","15"}}};//new String[1][3][2][2];
Integer intAr[][][][][][] = {{{{{{1},{2},{3}},{{4},{5},{6}}},{{{7}},{{8}}}}}};
recPrintArray(intAr);
}
public static void recPrintArray(Object ar) {
recPrintArray((Object[])ar,getDimensions(ar));
}
public static void recPrintArray(Object[] ar,int noODDimension) {
for (Object obj:(Object[]) ar) {
if (noODDimension > 0)
recPrintArray((Object[])obj, noODDimension - 1);
else {
System.out.print("> " + obj + " ");
}
}
}
/*return the number of dimension of an array
* takes any type as argument
* using the Object class getClass() and Class class getName() methods
*/
public static int getDimensions(Object intAr) {
return intAr.getClass().getName().lastIndexOf("[");
}
}
To answer your question, we need to introduce the concept of autoboxing first. Primitive types have their class matches. int has Integer, double has Double and so on. When a primitive type needs to be handled as an Object, the compiler will automatically convert the primitive into an instance of its wrapper class. Since you have an array of Objects, your primitive values are needed as Objects, so autoboxing will happen. If you want this to happen in a generic way, then you need to just check whether you have an array and if not, print the Object by calling its toString method.
As for your second question, you cannot convert a primitive array to an array of Objects, because your array was allocated for primitive types, not for Objects, but you can upcast a String array to an Object array, because all Strings are Objects.
since in java multidimensional arrays are array of array and array is an object. so if i recursively iterate on any array references in the last i will get only one dimensional array which i can type cast explicitly in the type supplied by using getClass().getName()
package learning;
public class MultiDimension {
public static void main(String[] args) {
final String ar[][][] = {{{"1","2"},{"3","4","5"}},{{"6","7","8"}},{{"9","10"},{"11"},{"12","13","14","15"}}};//new String[1][3][2][2];
//Integer integerAr[][] = {{1},{2}};
//byte byteAr[][] = {{1},{2}};
//int[] intAr = (int[])byteAr;
recPrintArray(ar);
}
public static void recPrintArray(Object ar) {
recPrintArray(ar,getDimensions(ar));
}
public static void recPrintArray(Object ar,int noOfDimension) {
for (Object obj:(Object[]) ar) {
if (noOfDimension > 1)
recPrintArray(obj, noOfDimension - 1);
else {
String dataType = obj.getClass().getName();
switch (dataType) {
case "[B":
printAll((byte[]) obj);
break;
case "[S":
printAll((short[]) obj);
break;
case "[I":
printAll((int[]) obj);
break;
case "[J":
printAll((long[]) obj);
break;
case "[F":
printAll((float[]) obj);
break;
case "[D":
printAll((double[]) obj);
break;
case "[Z":
printAll((boolean[]) obj);
break;
case "[C":
printAll((char[]) obj);
default:
printAll((Object[]) obj);
}
//System.out.print("> " + obj + " ");
}
}
}
public static void printAll(byte[] ar) {
for (byte val: ar)
System.out.print(">" + val + " ");
}
public static void printAll(short[] ar) {
for (short val: ar)
System.out.print(">" + val + " ");
}
public static void printAll(int[] ar) {
for (int val: ar)
System.out.print(">" + val + " ");
}
public static void printAll(long[] ar) {
for (long val: ar)
System.out.print(">" + val + " ");
}
public static void printAll(float[] ar) {
for (float val: ar)
System.out.print(">" + val + " ");
}
public static void printAll(double[] ar) {
for (double val: ar)
System.out.print(">" + val + " ");
}
public static void printAll(char[] ar) {
for (char val: ar)
System.out.print(">" + val + " ");
}
public static void printAll(boolean[] ar) {
for (boolean val: ar)
System.out.print(">" + val + " ");
}
public static void printAll(Object[] ar) {
for (Object val: ar)
System.out.print(">" + val + " ");
}
/*return the number of dimension of an array
* takes any reference type as argument
* using the Object class getClass() and Class getName() methods
*/
public static int getDimensions(Object intAr) {
return intAr.getClass().getName().lastIndexOf("[");
}
}

Overloading method :Automatic data type conversion

The following code is correct with respect to method overloading.
public class class7A {
public static void main(String[] args) {
testing obj_1 = new testing();
int a=12,b=14,c=20;
obj_1.func1(a,b,c); //invokes the 3rd method in the testing class
}
}
class testing{
void func1(int a,int b){
System.out.println("The values of length and breadth entered for the box is "+a+" "+b);
}
void func1(int a){
System.out.println("We can only talk about length here folks which is "+a);
}
void func1(double a,double b,double c){ //This method is invoked
System.out.println("The value of length ,breadth and height is "+a+","+b+","+c+" respectively");
}
}
Now the explanation given for the fact that the 3rd method is invoked even when the parameters defined for the 3rd method are "double" is that java automatically converts double into int here.I also know java does any operation on the primitive type by first converting the types into int at the back end which holds true for bytes as well.
However when i change the parameters of the 3rd method to be of byte type instead of double,the code gives an error .Foe example the code below gives an error :
Why it is happening so ?
public class class7A {
public static void main(String[] args) {
testing obj_1 = new testing();
int a=12,b=14,c=20;
obj_1.func1(a,b,c);
}
}
class testing{
void func1(int a,int b){
System.out.println("The values of length and breadth entered for the box is "+a+" "+b);
}
void func1(int a){
System.out.println("We can only talk about length here folks which is "+a);
}
void func1(byte a,byte b,byte c){ //This gives error
System.out.println("The value of length ,breadth and height is "+a+","+b+","+c+" respectively");
You must cast the type of data int to byte when you pass as argument of the method.
example:
public class class7A {
public static void main(String[] args) {
testing obj_1 = new testing();
int a = 12, b = 14, c = 20;
obj_1.func1((byte) a, (byte) b, (byte) c);
}
}
class testing {
void func1(int a, int b) {
System.out.println("The values of length and breadth entered for the box is " + a + " " + b);
}
void func1(int a) {
System.out.println("We can only talk about length here folks which is " + a);
}
void func1(byte a, byte b, byte c) { // This gives error
System.out.println("The value of length ,breadth and height is " + a + "," + b + "," + c + " respectively");
}
}
and if you want to make another type of conversion you can check this post where it is explained more detailed how to convert from int to byte
https://stackoverflow.com/a/842900/7179674

What's the most idiomatic way in Java to dynamically call a function by name?

I have a certain set of operations that I would like to be able to access dynamically by name.
If I were using JavaScript, I would represent them in a dictionary with the names of the operations as keys and the operation functions as values.
Then, for example, I could ask the user for the name of an operation, display the result of the operation if it exists, and display an error message if it doesn't exist, like so:
var operations = {
addition: function(a, b) { return a + b; },
subtraction: function(a, b) { return a - b; },
multiplication: function(a, b) { return a * b; }
// etc.
};
var a = 4, b = 7;
var opName = prompt("Enter operation name:");
if (opName in operations) {
alert("Result: " + operations[opName](a, b));
} else {
alert("The operation '" + opName + "' does not exist.");
}
How would I do the same thing in Java? I could have a Set<String> of operation names and a function that uses a switch with a case for each operation, but that requires me to repeat each operation name twice, which makes the code more brittle and more tedious to write and maintain.
Is there a reasonably concise DRY pattern for this sort of thing in Java?
This is a lot neater in Java 8 using lambdas:
Map<String, BinaryOperator<Integer>> operators = new TreeMap<>();
operators.put("add", (n1, n2) -> n1 + n2);
operators.put("minus", (n1, n2) -> n1 - n2);
if (operators.containsKey(opName)) {
return operators.get(opName).apply(n1, n2);
}
But I gather from your comments that that is not an option. An alternative is to use an enum to contain your operations so that you can add new operations in one place:
enum Operation {
PLUS {
public int operate(int arg1, int arg2) {
return arg1 + arg2;
}
},
MINUS {
public int operate(int arg1, int arg2) {
return arg1 - arg2;
}
},
...
abstract public int operate(int arg1, int arg2);
}
for (operation: Operations.values()) {
if (operation.name().equals(opName))
System.out.println("result = " + operation.operate(arg1, arg2));
return;
}
}
System.out.println("The Operation " + opName + " does not exist");
public interface Function {
double run(double a, double b);
}
public class addFunction implements Function {
double run(double a, double b) {
return a+b;
}
}
//...
Map<String, Function> operations = new HashMap<string, Function>();
operations.put("add", new addFunction());
//...
String op;
double a, b;
operations.get(op).run(a, b);
You can do the same thing in Java without using Java8:
public interface Operation<T,R> {
R perform(T... args);
}
public void test() {
Map<String, Operation> operations = new HashMap<String, Operation>() {
{
this.put("addition", new Operation<Integer, Integer>() {
public Integer perform(Integer... args) {
return args[0] + args[1];
}});
}
};
String operation = "";
Integer a = 1;
Integer b = 1;
if (operations.containsKey(operation)) {
System.out.println("Result: " + operations.get(operation).perform(a, b));
} else {
System.out.println("The operation '" + operation + "' does not exist.");
}
}
You can move that anonymous class into a separate file if you prefer that, too.
If you need arguments of different types you will have to either juggle with generics or change the argument type to Object and then do casts. Not pretty but that's the price of static typing.
Also the compiler will throw you a warning (using raw Operation) but not much to do here if you want to store operations of different types in the same map. A way out would be to make several maps for different types.

Categories

Resources