Pass method as parameter for another method - java

I want to do something like this:
public class Myclass() {
ArrayList<Object> objects;
public Myclass() {
this.objects = new ArrayList<>();
}
public ArrayList<Object> callObjectAndMethod(Method method, String string) {
ArrayList<Object> returnlist = new ArrayList<>();
// call method for given object reference. I also assume that return value of the method is String
String output = object.method();
for (Object object : this.objects) {
if (object.method.contains(string)) {
returnlist.add(object.method());
}
return returnlist;
}
}
Is it possible to pass method as parameter for another method ? Also i would like to do this sort of iteration for multiple variable types. int,String,double is there way to create method that works with multiple input types. (probably not) but i am only trying to reduce the amount of lines i have to write. i will have a lot to write if i write this thing for all the methods i want to compare or use copy-paste technique and change little things (which is not good).

You could use java-8 functional Programming. It allows using Function Interfaces to create such implementations called lambda expressions. These lambda expressions could be passed as variables to other methods. For example
Predicate isLengthTen = string -> string.length() == 10;
Now this could be passed as a parameter to any method. Hence, you could use java 8 functional programming easily to pass the code as parameter basically.
boolean testTruth(Predicate<T> predicate,T dataUnderTest){
predicate.test(dataUnderTest);
}
Hope it helps!
Quick read about how to use is here

Related

Change Type of Method Reference

My code:
class BlogPost {
String title;
String author;
BlogPostType type;
int likes;
public BlogPost(String title, String author, BlogPostType type, int likes) {
this.title = title;
this.author = author;
this.type = type;
this.likes = likes;
}
//getter setter
}
and:
public enum BlogPostType {
NEWS,
REVIEW,
GUIDE
}
and:
public static void main(String[] args) {
List<BlogPost> posts = Arrays.asList(new BlogPost("Start Java", "Ram", BlogPostType.NEWS, 11),
new BlogPost("Start Java 8", "Rajou", BlogPostType.REVIEW, 101),
new BlogPost("Functional programming", "Das", BlogPostType.REVIEW, 111),
new BlogPost("Lambda", "Ramos", BlogPostType.GUIDE, 541));
Map<BlogPostType, List<BlogPost>> Blist = posts.stream().collect(groupingBy(BlogPost::getType));
System.out.println(Blist);
}}
I have three classes one is BlogPost , BlogPostType and Main.
I am making a map of Map<BlogPostType, List<BlogPost>> Blist by using groupingBy() and it works perfectly fine. i used a method reference there BlogPost::getType , i can use lambda expression also (x) -> x.getType().
But when i try to change the type of Map , i.e Map<String, List<BlogPost>> Blist1 then i cannot use Method reference. Is there any possible way to use method reference and get the type also changed??
I am thinking why cant we use like this: BlogPost::getType.toString() or (String)BlogPost::getType while we can do this in lambda (x) -> x.getType().toString().
Any possible ways to use Method reference and get along with conversion of type also?
you can use Function.identity() to chain method references (as many as you want). For example, put the following function in groupingBy:
Function.<BlogPost>identity()
.andThen(BlogPost::getType)
.andThen(BlogPostType::toString)
but it's better to use lambda
Method reference in place of lambda expression makes your code more
readable, hence it is advised to replace lambda expression with method
reference, Whenever Possible.
Remember a method reference replace a single method invocation , in your case BlogPost::getType will work fine while BlogPost::getType.toString() will not work as it is not single method invocation.
A method reference replace a single method invocation, so it can’t simply replace a lambda expression consisting of more than one method invocation.
You can do it with two method references as follows, but I'd stick with the lambda expression, which is much simpler.
Map<String, List<BlogPost>> Blist =
posts.stream()
.collect(Collectors.groupingBy(((Function<BlogPost,BlogPostType>)BlogPost::getType).andThen(BlogPostType::toString)));
or
Function<BlogPost,BlogPostType> getType = BlogPost::getType;
Map<String, List<BlogPost>> Blist =
posts.stream()
.collect(Collectors.groupingBy(getType.andThen(BlogPostType::toString)));
A method reference is just that: a "reference" to some specific method.
There is no implicit conversion or anything. Just a method that has a certain signature, and syntactic shortcut to express that without writing down a lambda expression.
If you want to use a method reference, that thing must exist as method. In other words, you would need to a new method like
String getTypeAsString()
to your BlogPost class. Only then you can go and directly invoke that method via a method reference.
But in your case, simply use that lambda expression instead that calls toString() explicitly. It sounds wrong to have a special method there that does "almost" the same as another method, just to enable you to write down a method reference.
Alternatively, follow the interesting approach pointed out in Eran's answer to use andThen().
In the end, your focus should be to write code that is easy to read and understand for you and your team. My personal recommendation would be to use the lambda right there, as all other solutions just add a lot of noise for no real gain.

Should functional interfaces be called directly?

I built a few classes that implement functional interfaces so that they can be reused, these include Predicates, Functions, etc.
These work great when I pass a new instance into a collection stream, for example:
myList.stream().filter(new PrimeNumberPredicate())...
Today I found the usage of a predicate by creating and calling a predicate directly:
boolean result = new PrimeNumberPredicate().test(myData);
I find this code a bit verbose, and I'd like to ask if there is another way to write this so that I could do the test without explicitly calling test() on a single object.
I wouldn't do either. The fun of functional interfaces is that you don't have to explicitly implement any particular interface, nor create useless objects. All you need is a method that does what you want and you can bend it to your functional will.
Define the predicate function staticly:
class PrimeNumbers {
public static boolean isPrime(int number) {
...
}
}
Then use it in a stream like so:
myList.stream().filter(PrimeNumbers::isPrime)...
Non-functional code like your co-worker's could skip instantiating an object and call the function directly:
boolean result = PrimeNumbers.isPrime(myData);
This has the advantage of letting you name the class and method naturally, rather than "predicate" or "test" or "apply".
As an alternative, you can declare test as a static method, and use a method reference when an actual Predicate is required:
public class PrimeNumberCheck {
public static boolean test(BigInteger n) {...}
}
myList.stream().filter(PrimeNumberCheck::test)
boolean result = PrimeNumberCheck.test(myData);
Although there is nothing wrong with calling test, you could use an equally verbose method that uses streams:
boolean result = Stream.of(myData).anyMatch(new PrimeNumberPredicate());
You could also make a single instance of PrimeNumberPredicate, and reuse it instead of creating new one all the time:
class PrimeNumberPredicate {
public static final PrimeNumberPredicate Instance = new PrimeNumberPredicate();
...
}
Now the call would look like this:
boolean result = Stream.of(myData).anyMatch(PrimeNumberPredicate.Instance);

How to organize java 8 code with Functional interfaces

I have recently started reading about java 8 features and i am confused with what seems like a very basic thing. How to organize code in 'Functional style' ?
Whatever i do, it looks very object oriented to me.
Best to explain what i ask with an example.
#FunctionalInterface
public interface SubstringOperator {
String splitAtLastOccurence(String plainText, String delimiter);
}
Let's say that in certain class i always need exactly one specific implementation of the SubstringOperator interface. I could provide implementation in the constructor like below:
public class SomeClass {
private SubstringOperator substringOperator;
public SomeClass() {
substringOperator = (s, d) -> { return s.substring(s.lastIndexOf(d)+1);};
}
}
I could now use this implementation in any method within SomeClass like this:
//...
String valueAfterSplit = substringOperator.splitAtLastOccurence(plainText, "=");
If i now wish to add another class which reuses that specific SubstringOperator implementation, should i create another class which exposes the implementation via getters?
Am i missing something obvious, or:
functions must be contained in classes in order to reuse them ?
How is that any different than object oriented paradigm ?
Put aside Stream API and other thingies, i would like to get basic understanding about code organization in java 8 for Functional style programming.
Usually it's better to reuse existing functional interfaces instead of creating new ones. In your case the BinaryOperator<String> is what you need. And it's better to name the variables by their meaning, not by their type. Thus you may have:
public class SomeClass {
private BinaryOperator<String> splitAtLastOccurence =
(s, d) -> s.substring(s.lastIndexOf(d)+1);
}
Note that you can simplify single-statement lambda removing the return keyword and curly brackets. It can be applied like this:
String valueAfterSplit = splitAtLastOccurence.apply(plainText, "=");
Usually if your class uses the same function always, you don't need to store it in the variable. Use plain old method instead:
protected static String splitAtLastOccurence(String s, String d) {
return s.substring(s.lastIndexOf(d)+1);
}
And just call it:
String valueAfterSplit = splitAtLastOccurence(plainText, "=");
Functions are good when another class or method is parameterized by function, so it can be used with different functions. For example, you are writing some generic code which can process list of strings with additional other string:
void processList(List<String> list, String other, BinaryOperator<String> op) {
for(int i=0; i<list.size(); i++) {
list.set(i, op.apply(list.get(i), other));
}
}
Or more in java-8 style:
void processList(List<String> list, String other, BinaryOperator<String> op) {
list.replaceAll(s -> op.apply(s, other));
}
In this way you can use this method with different functions. If you already have splitAtLastOccurence static method defined as above, you can reuse it using a method reference:
processList(myList, "=", MyClass::splitAtLastOccurence);

Lazy Collection in Java

Consider a problem, in which I'm developing a tree like Collection.
One of the main functionality of my Collection is to trace all the stored items one by one and then call a given function for each item until a given criteria has been met (lazy Collection).
So the function should have the following signatures:
void Trace(function func, criteria crit)
{
item i = firstItem();
while (i != endItem())
{
i = nextItem();
func(i);
if (crit(i))
return;
}
}
in C++ function pointers can be used for func and crit.
in C#, yield keyword is exactly the solution to this problem, I believe.
How can I get the same thing in Java?
In Java, you would pass references to objects of classes that implement applicable functions, or use Commons Collections instead:
Use Predicate implementations for the crit part.
Use Closure implementations for the func part.
For example:
Closure c = new Closure() {
public void execute(Object obj) {
...
}
};
Predicate p = new Predicate() {
public boolean evaluate(Object obj) {
...
}
}
Trace(c, p);
What you're looking for here is the Strategy design pattern.
The goal of this pattern to to abstract the implementation of an algorithm into a Strategy object. Here, your algorithms are the func and crit functions that you're looking to pass in.
So, you'd have an interface called something like TraceStrategy. You'd then pass implementations of this interface in to your collection. Your code would then look something like
void Trace(TraceStrategy traceStrategy)
{
item i = firstItem();
while (i != endItem())
{
i = nextItem();
traceStrategy.func(i);
if (traceStrategy.crit(i))
return;
}
}
and
interface TraceStrategy {
public boolean crit(item i);
public void func(item i);
}
You'd probably want to make this generic, so that you weren't tied to item... but you get the idea.
Create an interface that declares the methods, and require a reference to an object implementing the interface as argument. The caller can create the object using an anonymous inner class.
You can make this trace function work just fine in Java by combining a couple of techniques:
Instead of "function pointers", your parameters func and crit should be object instances that implement a specific interface. You can then call a function in this interface on the object i. In effect, this is a Vistor Pattern with two different vistor parameters.
You also need some way to traverse the tree. You could implement an Iterator - this gives you a nice way to traverse the entire structure. Alternatively you could make trace recursive (it calls itself on left and right branches of the tree) and then you wouldn't need an iterator.
The iterator version would look something like this:
public void trace(IFunction func, ICriteria crit) {
for (T i: this) {
func.call(i);
if (crit.test(i)) return;
}
}
Here T is the item type of the collection, and call and test are the function definitions in the IFunction and ICriteria interfaces respectively.

call a method with a concatenated string

In Java I want to call a method in a for loop
for(int i = 0; i < 5; i++ ){
myMethod.get + Integer.toString(i)(theValue);
}
where the method called is named myMethod.get1, myMethod.get2, myMethod.get3 ...
Can this be done?
In principle this is possible through reflection. However, a question like this is often a symptom that your program is badly designed. Most likely you would be much better off storing your data in a data structure such as a List or an array, which allows you to get values out of it by index, or maybe a Map.
encapsulate your processing logic like this
interface Worker {
void doWork(Object param);
}
class Test {
private HashMap<Integer, Worker> map = new HashMap<Integer, Worker>();
public Test() {
map.put(1, new Worker() {
#Override
public void doWork(Object param) {
// do something for 1
}
});
map.put(2, new Worker() {
#Override
public void doWork(Object param) {
// do something for 2
}
});
}
public void invoke(int id, Object param){
map.get(id).doWork(param);
}
}
I don't think this is generally a good idea, but you can use the reflection API:
Class has a method called getMethod, which takes a string argument, the method's name (also some optional arguments for the parameter types), then you can call it by calling invoke on it.
look at Java Reflection API
Yes, you can use reflection API for this. See java.lang.reflect.Method class and use its invoke method
I think you should instead of hitting different methods, which i beleive you are doing for certain set of operations, you should create class for each functionality. All these classes should be extending a common class or better will be to implement an interface. This interface can have a method get() which will be implemented in each of the clases.
Now you need to create an array/list of references of these objects. And call the get() method of each of these classes in the for loop.
Of course you can use reflection otherwise.

Categories

Resources