I am working with anonymous functions and functional interfaces, I have one functional interface that takes two objects of same type and returns true or false.
package elementutils;
#FunctionalInterface
public interface TwoElementPredicate <T> {
public boolean compare(T a, T b);
}
I use the functional interface in another class to get the "better element" using anonymous functions, the method betterElement takes two objects and the instance of the functional interface. Then i should be able to create lambdas to compare two objects of the same type in the main.
package elementutils;
public class ElementUtils <T> {
public T betterElement(T a, T b, TwoElementPredicate elements){
if (elements.compare(a, b) == true) {
return a;
}else {
return b;
}
}
public static void main(String[] args) {
//String x= ElementUtils.betterElement("java", "python", (a, b) -> a.length() < b.length());
//int y= ElementUtils.betterElement(2, 3, (a, b) -> a > b);
//double z= ElementUtils.betterElement(2.5, 3.7, (a, b) -> a > b);
// all this give errors
}
}
The functions should take any object as long as they are from the same type. I thought I could achieve that using generic classes but when I instantiate the lambdas it seems that the elements are always of type object so I cannot use length() and cannot assigne them to a String for example.
I hope I explained myself correctly, any help will be highly appreciated.
You are missing the type parameter T on TwoElementPredicate and hence you are using a raw type
You need to declare the parameter elements as of type TwoElementPredicate<T>
Your definition of betterElement uses a raw TwoElementPredicate, so its arguments will always be Objects. Instead, you should use a generic parameter, with the same T as the elements:
public T betterElement(T a, T b, TwoElementPredicate<T> elements) {
// Here ----------------------------------------^
Related
I am trying to create a generic class in Java that will perform operations on numbers. In the following example, addition, as follows:
public class Example <T extends Number> {
public T add(T a, T b){
return a + b;
}
}
Forgive my naivety as I am relatively new to Java Generics. This code fails to compile with the error:
The operator + is undefined for the argument type(s) T, T
I thought that with the addition of "extends Number" the code would compile. Is it possible to do this Java or will I have to create overridden methods for each Number type?
Number does not have a + operator associated with it, nor can it since there is no operator overloading.
It would be nice though.
Basically, you are asking java to autobox a descedant of Number which happens to include Integer, Float and Double, that could be autoboxed and have a plus operator applied, however, there could be any number of other unknown descendants of Number that cannot be autoboxed, and this cannot be known until runtime. (Damn erasure)
Your problem is not really related to generics, rather to operators, primitives vs objects, and autoboxing.
Think about this:
public static void main(String[] args) {
Number a = new Integer(2);
Number b = new Integer(3);
Number c = a + b;
}
The above does not compile
public static void main(String[] args) {
Integer a = new Integer(2);
Integer b = new Integer(3);
Number c = a + b;
}
The above does compile, but only because of autoboxing - which is kind of a hacky syntax glue introduced in Java 5, and only works (in compile time) with some concrete types : int-Integer for example.
Behind the scenes, the Java compiler is rewriting the last statement ("I must unbox a and b to apply the sum operator with primitive datatypes, and box the result to assign it to object c") thus:
Number c = Integer.valueOf( a.intValue() + b.intValue() );
Java can't unbox a Number because it does not know at compile time the concrete type and hence it cannot guess its primitive counterpart.
You can do something like this
class Example <T extends Number> {
public Number add(T a, T b){
return new Double(a.doubleValue() + b.doubleValue());
}
}
Yes, Nathan is correct. If you want something like this, you have to write it yourself
public class Example <T extends Number> {
private final Calculator<T> calc;
public Example(Calculator<T> calc) {
this.calc = calc;
}
public T add(T a, T b){
return calc.add(a,b);
}
}
public interface Calculator<T extends Number> {
public T add(T a, T b);
}
public class IntCalc implements Calculator<Integer> {
public final static IntCalc INSTANCE = new IntCalc();
private IntCalc(){}
public Integer add(Integer a, Integer b) { return a + b; }
}
...
Example<Integer> ex = new Example<Integer>(IntCalc.INSTANCE);
System.out.println(ex.add(12,13));
Too bad Java has no type classes (Haskell) or implicit objects (Scala), this task would be a perfect use case...
There are similar questions to this one, and the answer is you can't do it like that.
You could check if a and b are an instance of Long/Double/Integer/etc. and delegate the add to methods like:
public Integer add(Integer a, Integer b) {
return a+b; // this actually uses auto boxing and unboxing to int
}
And you would need to create one for every type that extends Number, so that's not really feasible. In other words, don't use generics for numeric operations. Number as a superclass is pretty limited.
Consider Example<Number>, how would + work on that? There is no add or similar in Number or even the likes of Integer.
Worse consider final class FunkyNumber extends Number { ... weird stuff, no add op ... }.
Even the java runtime library has this problem, most of the methods dealing with primitives have to duplicate the same functionality.
The fastest option would be to write your code for one type and then copy it and replace the type to generate the methods for the other types. A short script should be enough to do this.
i was trying to understand polymorphism in Java better with the following example:
public class A {
1 int method(A a) { return 1; }
2 static int method(B b) { return 2 + b.method((A)b); }
}
public class B extends A {
3 final int method(A a) { return 4 + super.method(a); }
4 int method(C c) { return 8 + this.method((B)c); }
}
public class C extends B {
5 int method(C c) { return 16 + method((A)c); }
}
And, the following declaration, initialization, methodcall:
B b = new B();
b.method(b);
I can not wrap my head around, why the "int method(A a) { return 1; }", is the last one to be called.
My train of thought so far:
We figure out the static and dynamic Type and of b (B and B)
We look in class B, if we find a method called method, which accepts parameter with static type B.
We find two candidates: 3, 2.
We call 2, because it requires no implicit casting to the static Type B in the parameter and the static and dynamic types of B are the same.
Now figure out the stat/dyn.types for b.method((A) b):
b is (B/B), and b in the parameter is (A/B) after the cast. Now, we look in class B for a Method called method, which accepts an A-type parameter, we find one,1, but now, because we have a different dynamic type (B), we also need so search B for a possible candidate, we find 3, we use it, since it overrides 1.
After that, we discern the types again, because of "super" the static type is the one from the parentclass (A), and the dynamic one: B (the dynamic type of the object which caused the super-call), and A and A for its parameter.
So, now we seek in A for a method which accepts an A, we find 1, but the dynamic class is different, so we need to also check for candidates, in class B, which might overwrite the method found in A (1), and use it, if that is the case, which would lead us to calling method 3, again.
But obviously that is not what Java returns, and i do not know where the error to this approach is. In other polymorphism exercises, i came to the correct solution.
I have a requirement where in the function takes different parameters and returns unique objects. All these functions perform the same operation.
ie.
public returnObject1 myfunction( paramObject1 a, int a) {
returnObject1 = new returnObject1();
returnObject1.a = paramObject1.a;
return returnObject1;
}
public returnOject2 myfunction( paramObject2 a, int a){
returnObject2 = new returnObject2();
returnObject2.a = paramObject2.a;
return returnObject2;
}
As you can see above, both the function do the same task but they take different parameters as input and return different objects.
I would like to minimize writing different functions that does the same task.
Is it possible to write a generic method for this that can substitute the parameters based on the call to the function?
paramObject and returnObject are basically two classes that have different variables. They are not related to each other.
My objective is that I do not want to do function overloading since the functions do almost the same work. I would like to have a single function that can handle different input and different return output.
my aim is to do something like this (if possible):
public static < E > myfunction( T a, int a ) {
// do work
}
The return type E and the input T can keep varying.
you can using the 3rd apply method to remove the code duplications, you separate creation & initialization from the apply method in this approach. and don't care about which type of T is used. for example:
returnObject1 myfunction(paramObject1 a, int b) {
return apply(returnObject1::new, b, value -> {
//uses paramObject1
//populates returnObject1
//for example:
value.foo = a.bar;
});
}
returnOject2 myfunction(paramObject2 a, int b) {
return apply(returnOject2::new, b, value -> {
//uses paramObject2
//populates returnObject2
//for example:
value.key = a.value;
});
}
<T> T apply(Supplier<T> factory, int b, Consumer<T> initializer) {
T value = factory.get();
initializer.accept(value);
//does work ...
return value;
}
Note the 2 myfunction is optional, you can remove them from you source code, and call the apply method directly, for example:
paramObject2 a = ...;
returnObject2 result = apply(returnOject2::new, 2, value -> {
//for example:
value.key = a.value;
});
Make interface Foo and implement this interface in both paramObject1 and paramObject2 class. Now your method should be look like:
public Foo myFunction(Foo foo, int a){
//Rest of the code.
return foo;
}
I'm learning how to use lambda expressions now, and I've seen some tutorials with a simple example:
(int x) -> x + 5;
But my compiler is showing this error:
Syntax error, insert "AssignmentOperator Expression" to complete Expression
Am I forgetting something?
Lambda expressions always have to be assigned to a reference type of Functional Interafces (also called single abstract method interfaces). Infact, they provide shortcut to the verbose anonymous class (with single method) implementations.
So, in simple words, Lambda expression = abstract method implementation (of the functional interface).
For example, your expression can be assigned to the below Functional Interface:
public interface MyInterface {//define Functional Interafce (SAM)
public int someMethod(int a);
}
public class Test {
public static void main(String[] args) {
MyInterface myInterface = (int a) -> a +5;//assign the expression to SAM
int output = myInterface.someMethod(20)); //returns 25
}
}
Lambdas are expressions that cannot be used as statements. From JLS8 §15.27:
It is a compile-time error if a lambda expression occurs in a program in someplace other than an assignment context (§5.2), an invocation context (§5.3), or a casting context (§5.5).
Consider this example:
// functional interface
interface Operator
{
int apply(int a, int b);
}
// method that expects instance of the interface
int calculate(int a, int b, Operator op)
{
return op.apply(a, b);
}
// lambda expression
Operator plus = (a, b) -> a + b;
// method call
calculate(40, 2, plus);
The issue is, as pointed out above, you are not doing anything with the lambda. This means that:
the compiler does not know which functional interface (e.g. java.util.function.Function) to infer as the type for your lambda.
Your line of code is "not a statement" (another error message often emitted by the compiler). This is similar to something like this:
"Hello";
Which is not valid Java.
A lambda expression cannot stand alone in Java, it need to be associated to a functional interface.
public interface myinterface
{
int mymethod(int a,int b);
}
public static void main(String[] args)
{
myinterface my = ( a,b ) -> {
int mul = a*4;
int add = a+b;
return add; };
}
Note: This is the first and last time you will see implemention of interface without keyword "Implements".
Play Around: try adding a new dummy method to your interface myinterface and you will see that your code will fail to compile, thus indicating that reference has to be only made from Functional interface not from general interfaces.
public interface myinterface
{
int mymethod(int a,int b);
int newmethod(String j);
}
public static void main(String[] args) {
myinterface my = ( a,b ) -> {
int mul = a*4;
int add = a+b;
return add;
};
Compilation Error: The target type of this expression must be a
functional interface
I've made a very simple generic class that store 2 variable of the same type, like this:
public MyClass<T>
{
private T v1;
private T v2;
public MyClass(T v1, T v2)
{
this.v1 = v1;
this.v2 = v2;
{
}
Now I need to implement, trough another non-generic class, a method that take an Object list of different types as input and give as output a list of MyClass<T> with couples of the same type.
My problem is that I cannot see a way to make something like this without knowing what types I'm working with, how do I instantiate the right type of MyClass every time?
I've come this far without getting errors from eclipse
public List<MyClass<?>> match()
{
List<MyClass<?>> list = new ArrayList<MyClass<?>>();
for(Object obj : this.list)//not the same list it's a parameter of the
{ //non-generic class
for(Object obj2 : this.list)
{
if(!(obj == obj2)&&obj.getClass().equals(obj2.getClass()))
{
MyClass<Object> couple = new MyClass<Object>(obj, obj2);
insertCouple(couple, list);
}
}
}
insertCouple is a private method that check if the couple are already in the output list, I've tried to implements Comparable on MyClass but made the coding even more complex.
As you can see I'm forced to stay generic but I can see there are problems with it.
If there isn't a method to find and fill the specific type at run time, how do I have to wrote that to make it possible trough generics?
You cannot decide which type of MyClass object to create at runtime (depending on the class of the matched objects), since all generic types are erased at compile time. You can read more on type erasure at:
http://docs.oracle.com/javase/tutorial/java/generics/erasure.html
From what I could gather in the comments, the solution is to build a list of pairs of elements from input list, based on a predicate.
class Match<T>
{
T a, b;
Match(T a, T b)
{
this.a = a;
this.b = b;
}
}
<T> List<Match<T>> match(List<T> list)
{
List<Match<T>> matchList = new ArrayList<Match<T>>();
for(T a : list)
{
for(T b : list)
{
if(a != b && a.getClass().equals(b.getClass()))
{
matchList.add(new Match<T>(a, b));
}
}
}
return matchList;
}
I believe I met your requirements:
Now I need to implement, trough another non-generic class, a method that take an Object list of different types as input and give as output a list of MyClass with couples of the same type.
The class containing the code above does not need be generic, and so the match method can be invoked with implicit specification of T, as in, you don't need to know T or specify it, in fact you can simply call match on a List<Object> or List (legacy code) if you will. The only restriction is that, the list you will get in return is typed as List<Match<K>> when you call match on a List<K>, but that's a good thing - generics are well applicable here.
You can even customize match, by having it operate on a predicate parameter:
class Predicate
{
<T> boolean eval(T a, T b)
{
return a != b && a.getClass().equals(b.getClass());
}
}
<T> List<Match<T>> match(List<T> list, Predicate predicate)
{
List<Match<T>> matchList = new ArrayList<Match<T>>();
for(T a : list)
{
for(T b : list)
{
if(predicate.eval(a, b))
{
matchList.add(new Match<T>(a, b));
}
}
}
return matchList;
}
As a final advice, avoid omitting type parameters for generic classes - that's a practice reserved for legacy code, and otherwise may indicate a logic problem with your code. It's the easiest thing to do - put Object or ? everywhere, but it is better to try to find true matching types for these generic specifications, in most cases.