Method accepts list of different objects in Java - java

Is it possible to do this in Java:
pass a parameter to a method which will accept list of different types
as well as use that Class type inside the method ?
public class Test {
public boolean testing(List<ClassType> testObjs) {
int vals = 0;
if (CollectionUtils.isNotEmpty(testObjs)) {
vals += testObjs.stream()
.map(ClassType::getTestType)
.filter(isTestobj::isTest)
.count();
}
do_processing_with_vals
return boolean_value;
}
}
There are 3 different classes which have method getTestType but unfortunately they are in different libraries and do not share a common parent class/Interface. I have to call a method (eg testing) which could take a list of either of these 3 class objects and do some processing with it. I do not want 3 different methods with only the difference being the class of the object that is passed (eg. ClassType).
When I use Object in place of ClassType, it throws error saying cannot resolve method getTestType.

Since the methods don't share a common interface (which is the best solution), the cleanest option may be to pass an appropriate Function or Predicate:
public boolean <T> testing(List<T> testObjs, Predicate<? super T> isTest) {
vals += testObjs.stream().filter(isTest).count();
}
...
testing(someObjs, ObjType::isTest);

Related

What are the use cases of generic non-static methods?

What is a valid use case for having a non-static method generic without having the class itself generic already?
Example:
public class A {
<T> T someMethod(T param) {
//use case?
}
}
As shown above, the class is not parameterized, but the method is. When such structure can be used?
Please note that the above code is just an example. I am okay with all return types or parameters. I am just interested in a valid use case for a generic non-static method.
One use case is to infer compile-time type, but that would require your method to have actual return type, not just void.
Here is an example from GSON
public <T> T fromJson(JsonElement json, Type typeOfT) throws JsonSyntaxException {
if (json == null) {
return null;
}
return (T) fromJson(new JsonTreeReader(json), typeOfT);
}
What are the use cases of generic non-static methods (if class itself
is not generic)?
One important use of this method signature is illustrated by the type safe heterogenous container pattern. This pattern is useful in situations for which the container can represent many types (not just one single type, as is the case for List<E>). In this pattern, the value's key is made generic instead of the container.
Here is the API for a type safe heterogenous container, taken from Essential Java, 2nd Ed. J. Bloch:
// Typesafe heterogeneous container pattern - API
public class Favorites {
public <T> void putFavorite(Class<T> type, T instance);
public <T> T getFavorite(Class<T> type);
}
This container maps keys, which are generic, to values whose type is represented by its corresponding key. This pattern exploits the fact that the Java Class class was made generic in Java 5. The generic Class<T> objects are used as run time type tokens which provide both compile-time and run-time type information for the corresponding values.
To store "favorite" String and Integer objects in the map, a client would write:
myFavs = new Favorites();
myFavs.putFavorite(String.class, "My Favorite String");
myFavs.putFavorite(Integer.class, Integer.valueOf(12345));
Note how the class literals are used as run-time type tokens which can then be used to restore the correct type to each value when it is retrieved from the map:
String myFavString = myFavs.getFavorite(String.class);
int myFavInt = myFavs.getFavorite(Integer.class);
The type safe heterogenous container pattern, which is extendible to other kinds of data structures (eg. a row from a database, each column of which may have a different type), allows designers to implement data structures with an arbitrary number of unrelated types in a type safe way.
This is made possible by the fact that instance methods can be made generic.
public class A {
<T> T someMethod(T param) {
//use case?
}
}
Here if class it self is not generic, so you will be creating object of A as A a = new A();, but if there a requirement such that the someMethod in A should have generic parameter, in that case you will be using generics.
Example of such class can be, it I have Calc class which as add method.
class Calc {
<T> T add(<T extends Number> param1, <T extends Number> param2) {
return param1 + param2;
}
}
Here the above method can accept parameter which extends Number class only and it will return type that you have provided as parameter. Hence code will be more type safe.
Calc c = new Calc();
int a = 1;
int b = 2;
calc.add(1, 2) // returns int 3

Limitations of forEach with instance method references in Java 8

Assume I have the following functional interface:
public interface TemperatureObserver {
void react(BigDecimal t);
}
and then in another class an already filled-in ArrayList of objects of type TemperatureObserver.
Assuming that temp is a BigDecimal, I can invoke react in a loop using:
observers.forEach(item -> item.react(temp));
My question: can I use a method reference for the code above?
The following does not work:
observers.forEach(TemperatureObserver::react);
The error message is telling me that
forEach in the Arraylist observers is not applicable to the type TemperatureObserver::react
TemperatureObserver does not define a method react(TemperatureObserver)
Fair enough, as forEach expects as an argument a Consumer<? super TemperatureObserver>, and my interface, although functional, does not comply to Consumer because of the different argument of react (a BigDecimal in my case).
So can this be solved, or it is a case in which a lambda does not have a corresponding method reference?
There are three kinds of method references that can be used when a single value is available from the stream:
A parameter-less method of the streamed object.
class Observer {
public void act() {
// code here
}
}
observers.forEach(Observer::act);
observers.forEach(obs -> obs.act()); // equivalent lambda
The streamed object becomes the this object of the method.
A static method with the streamed object as parameter.
class Other {
public static void act(Observer o) {
// code here
}
}
observers.forEach(Other::act);
observers.forEach(obs -> Other.act(obs)); // equivalent lambda
A non-static method with the streamed object as parameter.
class Other {
void act(Observer o);
}
Other other = new Other();
observers.forEach(other::act);
observers.forEach(obs -> other.act(obs)); // equivalent lambda
There is also a constructor reference, but that is not really relevant to this question.
Since you have an external value temp, and you want to use a method reference, you can do the third option:
class Temp {
private final BigDecimal temp;
public Temp(BigDecimal temp) {
this.temp = temp;
}
public void apply(TemperatureObserver observer) {
observer.react(this.temp);
}
}
Temp tempObj = new Temp(temp);
observers.forEach(tempObj::apply);
Take a look at the Method References section in the Java Tutorial. There it says:
There are four kinds of method references:
Reference to a static method: ContainingClass::staticMethodName
Reference to an instance method of a particular object: containingObject::instanceMethodName
Reference to an instance method of an arbitrary object of a particular type: ContainingType::methodName
Reference to a constructor: ClassName::new
There it explains that i.e. TemperatureObserver::react would be a method reference of the 3rd type: a reference to an instance method of an arbitrary object of a particular type. In the context of your call to the Stream.forEach method, that method reference would be equivalent to the following lambda expression:
(TemperatureObserver item) -> item.react()
Or just:
item -> item.react()
Which doesn't match your void TemperatureObserver.react(BigDecimal t) method signature.
As you already suspect, there are cases for which you can't find an equivalent method reference for a lambda. Lambdas are way more flexible, though IMHO sometimes they are less readable than method references (but this is a matter of taste, many people think the other way round).
A way to still use a method reference would be with a helper method:
public static <T, U> Consumer<? super T> consumingParam(
BiConsumer<? super T, ? super U> biConsumer,
U param) {
return t -> biConsumer.accept(t, param);
}
Which you could use as follows:
observers.forEach(consumingParam(TemperatureObserver::react, temp));
But, honestly, I prefer to use a lambda.
It does not works, because you iterate over handlers, not over parameters.
For example, this code works:
ArrayList<BigDecimal> temps = new ArrayList<>();
TemperatureObserver observer = new TemperatureObserverImpl();
temps.forEach(observer::react);

Array Containing Methods/Functions for Argument Passing

I have a method that selects between the arguments of an array and returns a specific one. For instance, here is that method:
private <T> T selectOnType(T[] selection, T defaultOp){
switch(this.type){
case Resources.TEXT:
return selection[Resources.TEXT];
case Resources.LISTEN:
return selection[Resources.LISTEN];
default:
return defaultOp;
}
}
How can I construct an array full of method references (i.e. function pointers) in order to be able to pass that array into this method above?
I tried doing such things as:
java.util.function.Function<Void, Void>[] array = {ClassA::method1, ClassA::method2};
(where method1 and method1 take no arguments and return void)
But that throws a compiler error saying:
incompatible types: invalid method reference but expected no arguments. found: java.lang.Void reason: actual and formal argument lists differ in length
I have been playing around with lambdas such as:
() -> ClassA.method1()
But I haven't been able to get it to work. Does anyone know what I am doing wrong and know a solution to this problem?
EDIT:
I have seen this on Stack Overflow, but this is for C# and I haven't figured out how to mimic it in Java.
Example:
Let's say I have a Word class:
public class Word{
private final String text;
private int listenCorrect = 0, textCorrect = 0;
public Word(final String test){
this.text = text;
}
public void incListenCorrect(){
listenCorrect++;
}
public void incTextCorrect(){
textCorrect--;
}
}
And finally I have a Main class. Inside the action method (in the Main class) I want to have an array with these two methods in it in order to select between them if the type (shown below) is either listen or text:
public class Main{
int type = 0;
public void action(){
Word word = new Word("Hello");
// 'Functions' is used to represent something I tried above (just for demonstration)
Function[] array = {word::incListenCorrect, word::incTextCorrect};
Function picked = selectOnType(array, word::incTextCorrect);
picked.call();
}
/*
* Resources is another class that contains the following values:
* public static final int TEXT = 0;
* public static final int LISTEN = 1;
*/
private <T> T selectOnType(T[] selection, T defaultOp){
switch(this.type){
case Resources.TEXT:
return selection[Resources.TEXT];
case Resources.LISTEN:
return selection[Resources.LISTEN];
default:
return defaultOp;
}
}
}
A Function is a method that takes one argument and returns a result. You're using methods that take no arguments and do not return results. You can't use Function for this (using Void isn't a way to get around this), but the java.util.function package contains a number of classes for different common combinations (methods that take no arguments but return a result, methods that take one or two arguments and don't return a result, methods that take primitive arguments or return primitive results that won't work in a Function because the types aren't class types, etc.).
There isn't a class in java.util.function for a functional interface with no arguments and no result, but Runnable can be used for that.
You need to make sure you use the correct interface.
Note: I was assuming method1 and method2 are static methods, so that they don't take any arguments, even a hidden "instance" argument that instance methods take. If they're instance methods, then things have to be done differently.
Now that you've clarified that they're instance methods, things are different--but it depends on how you get the method. If you say
Word::incListenCorrect
since you're using the class name, you need to provide the instance as an argument. Therefore, Word::incListenCorrect returns a functional interface for a method that takes one argument, such as Consumer<Word>, and you have to pass the Word as the argument when you call the method with .accept(). But:
word::incListenCorrect
is very different. Now, the word instance becomes "baked into" the method reference, so it doesn't need to be passed as an argument. In this case, therefore, you'll still need the interface that takes no arguments and does not return a value, which is Runnable. When you say
Runnable r = word::incListenCorrect;
r.run();
where r is a Runnable, it will automatically use word as the instance for the instance method, since word became part of r when you assigned the method reference to it.

How to specify function types for void (not Void) methods in Java8?

I'm playing around with Java 8 to find out how functions as first class citizens. I have the following snippet:
package test;
import java.util.*;
import java.util.function.*;
public class Test {
public static void myForEach(List<Integer> list, Function<Integer, Void> myFunction) {
list.forEach(functionToBlock(myFunction));
}
public static void displayInt(Integer i) {
System.out.println(i);
}
public static void main(String[] args) {
List<Integer> theList = new ArrayList<>();
theList.add(1);
theList.add(2);
theList.add(3);
theList.add(4);
theList.add(5);
theList.add(6);
myForEach(theList, Test::displayInt);
}
}
What I'm trying to do is pass method displayInt to method myForEach using a method reference. To compiler produces the following error:
src/test/Test.java:9: error: cannot find symbol
list.forEach(functionToBlock(myFunction));
^
symbol: method functionToBlock(Function<Integer,Void>)
location: class Test
src/test/Test.java:25: error: method myForEach in class Test cannot be applied to given ty
pes;
myForEach(theList, Test::displayInt);
^
required: List<Integer>,Function<Integer,Void>
found: List<Integer>,Test::displayInt
reason: argument mismatch; bad return type in method reference
void cannot be converted to Void
The compiler complains that void cannot be converted to Void. I don't know how to specify the type of the function interface in the signature of myForEach such that the code compiles. I know I could simply change the return type of displayInt to Void and then return null. However, there may be situations where it's not possible to alter the method I want to pass somewhere else. Is there an easy way to reuse displayInt as it is?
You are trying to use the wrong interface type. The type Function is not appropriate in this case because it receives a parameter and has a return value. Instead you should use Consumer (formerly known as Block)
The Function type is declared as
interface Function<T,R> {
R apply(T t);
}
However, the Consumer type is compatible with that you are looking for:
interface Consumer<T> {
void accept(T t);
}
As such, Consumer is compatible with methods that receive a T and return nothing (void). And this is what you want.
For instance, if I wanted to display all element in a list I could simply create a consumer for that with a lambda expression:
List<String> allJedi = asList("Luke","Obiwan","Quigon");
allJedi.forEach( jedi -> System.out.println(jedi) );
You can see above that in this case, the lambda expression receives a parameter and has no return value.
Now, if I wanted to use a method reference instead of a lambda expression to create a consume of this type, then I need a method that receives a String and returns void, right?.
I could use different types of method references, but in this case let's take advantage of an object method reference by using the println method in the System.out object, like this:
Consumer<String> block = System.out::println
Or I could simply do
allJedi.forEach(System.out::println);
The println method is appropriate because it receives a value and has a return type void, just like the accept method in Consumer.
So, in your code, you need to change your method signature to somewhat like:
public static void myForEach(List<Integer> list, Consumer<Integer> myBlock) {
list.forEach(myBlock);
}
And then you should be able to create a consumer, using a static method reference, in your case by doing:
myForEach(theList, Test::displayInt);
Ultimately, you could even get rid of your myForEach method altogether and simply do:
theList.forEach(Test::displayInt);
About Functions as First Class Citizens
All been said, the truth is that Java 8 will not have functions as first-class citizens since a structural function type will not be added to the language. Java will simply offer an alternative way to create implementations of functional interfaces out of lambda expressions and method references. Ultimately lambda expressions and method references will be bound to object references, therefore all we have is objects as first-class citizens. The important thing is the functionality is there since we can pass objects as parameters, bound them to variable references and return them as values from other methods, then they pretty much serve a similar purpose.
When you need to accept a function as argument which takes no arguments and returns no result (void), in my opinion it is still best to have something like
public interface Thunk { void apply(); }
somewhere in your code. In my functional programming courses the word 'thunk' was used to describe such functions. Why it isn't in java.util.function is beyond my comprehension.
In other cases I find that even when java.util.function does have something that matches the signature I want - it still doesn't always feel right when the naming of the interface doesn't match the use of the function in my code. I guess it's a similar point that is made elsewhere here regarding 'Runnable' - which is a term associated with the Thread class - so while it may have he signature I need, it is still likely to confuse the reader.
Set return type to Void instead of void and return null
// Modify existing method
public static Void displayInt(Integer i) {
System.out.println(i);
return null;
}
OR
// Or use Lambda
myForEach(theList, i -> {System.out.println(i);return null;});

I'm studying Head First Java, but I can't understand Page 544

"When you declare a type parameter for the class, you can simply use that type any place that you'd use a real class or interface type. The type declared in the method argument is essentially replaced with the type you use when you instantiate the class.
If the class itself doesn't use a type parameter, you can still specify one for a method, by declaring it in a really unusual (but available) space-before the return type, This method says that T can be "any type of Animal"."
Can you explain?
What it means is that in a generic class, you can write methods like so:
public T doSomething () {
}
Note that the return type is 'T'.
At compile-time, the return type of that method will be whatever you have passed to the generic class when you instantiated it.
class Zoo<T> {
static void putAnimal(T animal) {
// do stuff
}
}
Zoo<Ape> apeZoo = new Zoo<Ape>(); // you can now put apes (and chimps) here
Zoo<Reptile> monkeyZoo = new Zoo<Reptile>(); // this zoo takes reptiles
apeZoo.putAnimal(new Chimp());
monkeyZoo.putAnimal(new Tortoise());
For the first paragraph, this is just how generics work for classes. For instance, for list, you can create a list of a generic type, such as integer, e.g.:
ArrayList<Integer> list = new ArrayList<Integer>();
(in real code you'd use List<Integer> of course)
Now ArrayList will be defined as:
public class Arraylist<T> { // implements....
// ...
public T get(int index) {
// ...
}
}
Which is what makes it possible to use the get method on list and get an Integer (because we made a class of type ArrayList<Integer> so T = Integer). Otherwise the compiler would have no idea what types of objects the list was storing and you'd have to get the method to return an Object, which is how it used to be.
What the second paragraph means is that you can add type parameters to methods just as you can to classes. e.g.:
public <T> void noOp(T element) {
// code here
}
This would allow you, for instance, to create a static utility method that returns something of type T. To return the first element of a List of T's:
public static <T> T getFirst (List<T> list) {
return list.get(0);
}
And you could use this method in a strongly typed fashion. Suggestions for better examples welcome. :-)
edit: I just realised I once wrote something that uses this functionality. I was using the JPA API and getting really annoyed at all the times you have to return something (a list, or a single item) from a query, and running into unchecked type warnings because there's no way to infer the type here. If you're like me and trying to avoid warnings in your code, you'd have to suppress the warnings every single time. So I wrote this method to suppress the warnings for me:
#SuppressWarnings("unchecked")
public static <T> List<T> returnResultList(Query query) {
return (List<T>)query.getResultList();
}
Which through the magic of type inference works on:
List<Integer> list = returnResultList(query);

Categories