How to pass a function through parameters using generics - java

Given the following code:
static <U,V> List<V> map(Iterable<U> l, Function<U,V> f) {
return null;
}
I need to pass an arraylist in the first parameter and a hash function in the second which takes a string and outputs a type int.
I'm trying the following but get the following error message.
map(names,<String,Integer> hashCode());
map(names,hash());
Error message:Not applicable for the arguments int
Need to pass a hash function so I can use this function inside the method.

Here:
hashCode()
isn't a function! It is simply a method invocation. You would rather need a lambda, something like:
x -> x.hashCode()
or, as you are probably using the hashcode of the current object:
this::hashCode
But that actually depends on the object on which you intend to invoke the hashCode method. And of course, there is also difference regarding the interface you intend to "use", be it a Function or Supplier (that second method reference example would be a supplier for example).

Related

Method Reference of Java

According to Oracle Documentation, the String::compareToIgnoreCase is also a valid method reference, my question is that compareToIgnoreCase is not a static method, in other words, compareToIgnoreCase must be attached to a specific String instance. So how does JDK know which instance of String I refer when I use String::compareToIgnoreCase ?
Consider the following example using toUpperCase which is also an instance method.
It works in this case because the Stream item that is being handled is of the same type as the class of the method being invoked. So the item actually invokes the method directly.
So for
Stream.of("abcde").map(String::toUpperCase).forEach(System.out::println);
the String::toUpperCase call will be the same as "abcde".toUpperCase()
If you did something like this:
Stream.of("abcde").map(OtherClass::toUpperCase).forEach(System.out::println);
"abcde" is not a type of OtherClass so the OtherClass would need to look like the following for the stream to work.
class OtherClass {
public static String toUpperCase(String s) {
return s.toUpperCase();
}
}
String::compareToIgnoreCase is not used such as str1.compareToIgnoreCase(str2) would be.
It actually is used as a comparator.
E.g. you could compare it to
Arrays.sort(someIntegerArray, Collections.reverseOrder())
but in this case it would be
Arrays.sort(someStringArray, String::compareToIgnoreCase)
It is like there is an additional parameter, the actual instance, involved.
Example for String::compareToIgnoreCase:
ToIntBiFunction<String, String> func = String::compareToIgnoreCase;
int result = func.applyAsInt("ab", "cd"); // some negative number expected
We get a ToIntBiFunction - a two parameter function returning int - since the result is an int, the first parameter correspond to this of compareToIgnoreCase and the second function parameter is the parameter passed to compareToIgnoreCase.
maybe a bit easier:
ToIntFunction<String> f = String::length; // function accepting String, returning int
int length = f.applyAsInt("abc"); // 3
length does not accept any parameter, but the first argument of the function is used as the instance length is called on
The examples above are very abstract, just to show the types involved. The functions are mostly used directly in some method call, no need to use an intermediate variable

Java 8 BiPredicate automatically calling method on first argument?

I have the following code:
public class BiPredicateTest {
public static void main(String[] args) {
BiPredicate<List<Integer>, Integer> listContains = List::contains;
List aList = Arrays.asList(10, 20, 30);
System.out.println(listContains.test(aList, 20)); // prints true magically?
}
}
In the statement listContains.test(aList, 20), how is it that the method "contains" is getting called on the first argument and the second argument is passed in as a parameter? Something equivalent to:
System.out.println(aList.contains(20));
In other words, how does the statement listContains.test(aList, 20) get translated to aList.contains(20)?
Is this how java 8 BiPredicate work? Could someone explain how the magic is happening (with some references)?
This is not a duplicate post. This differs from "What does “an Arbitrary Object of a Particular Type” mean in java 8?" in that its not explicitly passing method reference around. It is very clear how method reference is being passed around in the post you reference. The array instance on which the method is being called is passed as an argument to Arrays.sort(). In my case, how the method "contains" is being called on aList is not apparent. I am looking for a reference or explanation as to how its working.
It seems some individuals prefer to down vote instead of provide reference or explanation. They give the impression that they have knowledge but refuse to share it.
BiPredicate is an interface which has only one method, test.
public interface BiPredicate<A,B> {
boolean test(A a, B b);
}
Interfaces which have only one method are called functional interfaces. Previous to Java 8, you would often times have to implement these interfaces using an anonymous class, just to create a wrapper for a certain method call with the same signature. Like this:
BiPredicate<List<Integer>,Integer> listContains = new BiPredicate<>() {
#Override
public boolean test(List<Integer> list, Integer num) {
return list.contains(num);
}
};
In Java 8, method references were added, which allowed for a much shorter syntax and more efficient bytecode for this pattern. In a method reference, you can specify a method or constructor which has the same signature as the type arguments for the interface. When you make a method reference using a class type, it assigns the class type as the first generic argument of the functional interface being used. This means whatever parameter which uses that generic type will need to be an instance of the class.
Even if the instance method normally doesn't take any parameters, a method reference can still be used which takes an instance as the parameter. For example:
Predicate<String> pred = String::isEmpty;
pred.test(""); // true
For more information, see the Java Tutorial for Method References.

Replacing chained method call using method reference

"Java 8 Lambdas: Pragmatic Functional Programming" has an example for using peek method in Stream API. This piece of code prints artist nationalities whose name starts with "The":
Set<Nationality> nationalities = album.getMusician()
.filter(artist -> artist.getName().startsWith("The"))
.map(artist -> artist.getNationality())
.peek(nation -> System.out.println(nation))
.collect(Collectors.toList());
I want to rewrite this code with method references:
Set<Nationality> nationalities = album.getMusician()
.filter(artist -> artist.getName().startsWith("The"))
.map(Artist::getNationality)
.peek(System.out::println)
.collect(Collectors.toList());
Is there any solution to rewrite filter(artist -> artist.getName().startsWith("The"))?
You need to create a separate method that takes an Artist and returns a boolean:
private boolean nameStartsWithThe(Artist a) {
return a.getName().startsWith("The");
}
Set<Nationality> nationalities = album.getMusician()
.filter(this::nameStartsWithThe)
or with a static method:
private static boolean nameStartsWithThe(Artist a) {
return a.getName().startsWith("The");
}
Set<Nationality> nationalities = album.getMusician()
.filter(MyClass::nameStartsWithThe)
You'd need something that composes the two methods. There are some methods for composing methods (IntUnaryOperator has compose and andThen methods that can compose two IntUnaryOperators into a new IntUnaryOperator). But the ones I've found all seem specialized for certain types of functional interfaces; defining compose methods for every possible pair of functional interface types would be too unwieldy.
I did get something to work that would compose a Function and a Predicate to get a new Predicate:
static <T,U> Predicate<T> functionPredicate(Function<T,U> func, Predicate<U> pred) {
return obj -> pred.test(func.apply(obj));
}
That is, it can compose a predicate that operates on T from a function that takes a T and returns U, and a predicate that operates on U. This would almost work on your example, except that startsWith needs another parameter. But this does work:
static boolean startsWithThe(String s) {
return s.startsWith("The");
}
Predicate<Artist> pred = functionPredicate(Artist::getName, ThisClass::startsWithThe);
where ThisClass is whatever class contains startsWithThe. This works. If you want to avoid writing a new method (like startsWithThe), you could probably write a "parameterized predicate" generic method so that you write something like
Predicate<Artist> pred = functionPredicate(Artist::getName, parameterizedPredicate(String::startsWith, "The"));
but I haven't tried it.
So it seems it's possible to come up with something that will let you use method references instead of lambdas. I question whether it's worthwhile. To me, a method reference is just a shorthand for certain kinds of lambdas; and unless you can do what you want with a simple method reference, I'd think using a lambda is concise and clear enough, and you don't need to add all the extra rigmarole like my functionPredicate method. I've seen several questions that ask something like "How can I use a method reference for this instead of a lambda?", and I honestly don't understand why.
There is no way to replace that line with a method reference.
Method reference works by using the fact that there is only one object being used in entire lambda expression and the compiler can infer it (reference does not matter and type can be inferred) using target typing.
So,
artist -> artist.getNationality()
is replaced with
Artist::getNationality
Here Artist::getNationality method matches with the target type without requiring any further information.
In case of artist -> artist.getName().startsWith("The"), there are two method calls in the lambda expression. The order, parameters are important, and have to be specified.
It looks as if the artist reference should be inferred, but the compiler won't know what object should the startsWith("The") method be called on.
Hope this helps.

How nested method call works

Can anybody explain this how this line of code works:
Rational sum = a.add(b).add(c);
I don't understand how object b (which is an argument) is receiving a method?
This is called method chaining. The method add() actually returns a reference of the currently modified object or a new object of the same type on which the method was invoked. Say suppose the object referred to by a is a BigInteger , when you invoke a.add(b) , it returns a BigInteger object whose value is a+b , and hence you can invoke .add(c) on that object again.
Rational sum = a.add(b).add(c);
// is equivalent to
Rational temp = a.add(b);
Rational sum = temp.add(c);
Method chaining is not required. It only potentially improves readability and reduces the amount of source code. It is the core concept behind building a fluent interface.
A sample illustration:
This practice is used mostly in Builder pattern, you can find this pattern in API itself in StringBuilder class.
I don't understand how object b (which is an argument) is receiving a method?
No your understanding is wrong , a.add(b) means you are invoking method add() on object a and passing it a reference of object b . The resultant object which the method a.add(b) returns is of the same type as a , and then in succession you call the method .add(c) on the returned object passing a reference of object c to that method.
Its fluent chaining
Each method in the chain has to return a class or an interface. The next method in the chain has to be a part of the returned class.
in your case a.add(b) returning some calss/interface and then calling add(c) on that and that method returns your sum

is it possible to get the class of the interface <Set>

Am having some arguments say (String a, Treeset b, Set c)
and I try to get the class by arguments[i].getClass(); of the above arguments..
is Iit possible to get the class of the interface <Set>.
For example:
Class[] argumentTypes = new Class [arguments.length];
for (int i = 0 ; i < arguments.length ; i++)
{
argumentTypes[i] = arguments[i].getClass();
}
The code you've given will find the classes of the arguments (i.e. the values provided to the method) - but those can never be interfaces; they'll always be concrete implementations. (You can never pass "just a set" - always a reference to an object which is an instance of an implementation of the interface, or a null reference.)
It sounds like you want the types of the parameters - which you'd get via reflection if you absolutely had to, finding the Method and then getting the parameters from that with getParameterTypes. But given that you're within the method, you already know the parameter types, because they're at the top of the method... I'm not sure the best way of finding "the currently executing" method, if that's what you're after.
If you're just trying to get the class associated with Set, you can use Set.class of course. But again, it's not really clear what you're trying to do.
EDIT: Okay, judging from your comment, there are some logical problems with what you're trying to do. Going from the values of arguments to which method would be invoked is impossible in the general case, because you've lost information. Consider this, for example:
void foo(String x) {}
void foo(Object y) {}
foo("hello"); // Calls first method
foo((Object) "hello"); // Calls second method
Here the argument values are the same - but the expressions have a different type.
You can find all methods which would be valid for the argument values - modulo generic information lost by type erasure - using Class.isAssignableFrom. Does that help you enough?
Note that you'll also need to think carefully about how you handle null argument values, which would obviously be valid for any reference type parameter...
You can use http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Class.html#getInterfaces()
You will get the class what the caller provided.
I mean,in below class you will get HashSet.
Set set=new HashSet();
System.out.println(set.getClass());
You can do this in two ways given below
Set s = new //any class that implements it for example HashSet or TreeSet etc.;
s.getClass().getName(); //This will return the name of the subclass which is refered by s.
or if in other way can do it
Set s = null;
s.getClass();//This causes NullPointer Exception

Categories