java run method on every element of arraylist - java

I have a large number of methods that need to be applied to each member of a given arrayList. The problem is that I'm at compile time uncertain which methods need to be applied to the arrayList and applying all of them each time (with a check) would be to costly (realtime application). So I'm now looking for a way to give the list a number of methods (a la function programming) and have them run. I know I could create special classes where each class uses only a uses a single method on each of it's members but there are roughly 50 methods so that would quickly escalate into 50 different classes. Which would add a lot of unnecessary complexity to the project. Is there another way?
So what I'm looking for is something like this:
public void runMethode(Function f,ArrayList<ObjectWithF> al){
for(ObjectWithF o:al){
o.f();
}
}
Does such a thing exist in java? Or am I going to have to either call all 50 methods or create 50 different classes? Or would a wrapper pattern work here?

In Java 8, this functionality is provided via the Stream#forEach(Consumer) method in a very convenient form.
If you don't have Java 8 yet, then you can create an interface, and create instances of anonymous classes implementing this interface. This is a bit more verbose, but still better than 50 named classes.
It may be beneficial to design this interface in a way that is structurally equal to the Consumer interface that is used in Java 8, so that it may simply be changed to use the Java 8 version once you do the update.
This example shows a comparison of both approaches:
import java.util.ArrayList;
import java.util.List;
class Person
{
void sayHello()
{
System.out.println("Hello from "+this);
}
void sayGoodbye()
{
System.out.println("Goodbye from "+this);
}
}
// This interface already exists as java.util.function.Consumer in Java 8
interface Consumer<T>
{
void accept(T t);
}
public class ForEachTest
{
public static void main(String[] args)
{
List<Person> persons = new ArrayList<Person>();
for (int i=0; i<5; i++)
{
persons.add(new Person());
}
runJava8(persons);
runJava7(persons);
}
private static void runJava8(List<Person> persons)
{
persons.stream().forEach(Person::sayHello);
persons.stream().forEach(Person::sayGoodbye);
}
private static void runJava7(List<Person> persons)
{
runMethodJava7(persons, new Consumer<Person>()
{
#Override
public void accept(Person person)
{
person.sayHello();
}
});
runMethodJava7(persons, new Consumer<Person>()
{
#Override
public void accept(Person person)
{
person.sayGoodbye();
}
});
}
public static void runMethodJava7(
List<Person> persons, Consumer<? super Person> consumer)
{
for(Person person : persons)
{
consumer.accept(person);
}
}
}

reflect can help.
see the code blow :
String obj = "abc";
String methodName = "toString";
try {
Method method = obj.getClass().getMethod("toString");
System.out.println(method.invoke(obj));
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
we have a obj, and given a method, we can run this method on that object.
And, you can also consider define a interface, and all your objects in the list implements the interface. and iterate the list, call those methods which defined in the interface.

As of Java 8, use may use Consumer class:
public void runMethod(Consumer<ObjectWithF> consumer, ArrayList<ObjectWithF> al) {
for (ObjectWithF o : al) {
consumer.accept(o);
}
}
...
// for example
runMethod (o -> System.out.println (o), listOfObjectsWithF);
// or
runMethod (System.out::println, listOfObjectsWithF);
// or even
listOfObjectsWithF.forEach(System.out::println);
If it's not Java8, you may create this interface yourself and realize it for every method:
interface Consumer {
public void apply(ObjectWithF o);
}
public void runMethod(Consumer consumer, ArrayList<ObjectWithF> al) {
for (ObjectWithF o : al) {
consumer.apply(o);
}
}
...
runMethod(new Consumer() {
public void apply(ObjectWithF o) {
//for example
System.out.println (o.toString());
}
}, listOfObjectsWithF);

Related

Java Lambdas: Sending method name as parameter

I've run into a problem in which my class contains several methods with a lot of duplicated code. The reason behind this is that each method traverses a list of entries and calls specific entry method.
In code...
The LowLevelClass class has the following structure:
public class LowLevelClass {
// constructor omitted
public boolean doSomethingA() {
// some non-duplicated code
return true;
}
public boolean doSomethingB() {
// some non-duplicated code
return true;
}
public boolean doSomethingC() {
// some non-duplicated code
return true;
}
}
The top level class contains a List of LowLevelClasses and has the same number of methods, but this time, with a lot of duplications:
public class HighLevelClass {
private List<LowLevelClass> classes = new ArrayList<>();
public HighLevelClass() {
this.classes.add(new LowLevelClass(/* params */));
this.classes.add(new LowLevelClass(/* params */));
this.classes.add(new LowLevelClass(/* params */));
}
public void doA() {
System.out.println("Doing ...");
for (LowLevelClass entry : classes) {
System.out.println("Doing something...");
entry.doSomethingA();
System.out.println("Done");
}
}
public void doB() {
System.out.println("Doing ...");
for (LowLevelClass entry : classes) {
System.out.println("Doing something...");
entry.doSomethingB();
System.out.println("Done");
}
}
public void doC() {
System.out.println("Doing ...");
for (LowLevelClass entry : classes) {
System.out.println("Doing something...");
entry.doSomethingC();
System.out.println("Done");
}
}
}
My goal is to have something in form of:
public class HighLevelClass {
private List<LowLevelClass> classes = new ArrayList<>();
public HighLevelClass() {
this.classes.add(new LowLevelClass());
this.classes.add(new LowLevelClass());
this.classes.add(new LowLevelClass());
}
public void doSomething(Lambda /* Functional interface*/ operation) {
System.out.println("Doing A");
for (LowLevelClass entry : classes) {
System.out.println("Doing something...");
entry.operation; // or something else...
System.out.println("Done");
}
}
public void doSomethingA() {
// my goal... and maybe in totally wrong direction is to send something in form of...
return doSomething(LowLevelClass::doSomethingA);
}
// etc
}
Can this be done in Java 8 with Lambdas? In other words, can I define the method to perform on each entry of the given list?
EDIT 1
The answers provided by Jorn Vernee and Joffrey are correct!
Ultimately, the solution was to use Predicate. (see EDIT 2 why I didn't use Consumer in the end...)
public class HighLevelClass {
private List<LowLevelClass> classes = new ArrayList<>();
public HighLevelClass() {
this.classes.add(new LowLevelClass());
this.classes.add(new LowLevelClass());
this.classes.add(new LowLevelClass());
}
public boolean doSomething(Predicate<LowLevelClass> function) {
System.out.println("Doing A");
for (LowLevelClass entry : classes) {
System.out.println("Doing something...");
boolean val = function.test(entry);
System.out.println("Done " + val);
}
return someEndVerdict;
}
public boolean doSomethingA() {
return doSomething(LowLevelClass::doSomethingA);
}
// etc
}
EDIT 2
My initial methods in HighLevelClass didn't contain boolean return type. That's the reason why I used Predicate (Predicate, as a contast to Consumer, returns boolean value which suited me better - and which I forgot to initially mention :((( )
Thanks for help and time!
You should not confuse the way you call a method, which may or may not involve a lambda, and the way you write a method, which involves finding the right argument types.
When you write a method, you need to focus on your arguments' types. If one of them is an object representing a function, what you need is to understand the appropriate signature that this function should match, and this will give you the functional interface you should put as type of your param.
In your case, you expect a function that takes 1 argument of type LowLevelClass and returns no value. You might be surprised by that, but you need to think of instance methods as functions that take an instance of the class (this) as an extra first argument (as opposed to static methods).
Therefore, the Consumer<LowLevelClass> interface is what you want:
public void doSomething(Consumer<LowLevelClass> operation) {
System.out.println("Doing A");
for (LowLevelClass entry : classes) {
System.out.println("Doing something...");
operation.accept(entry); // or something else...
System.out.println("Done");
}
}
public void doSomethingA() {
return doSomething(LowLevelClass::doSomethingA);
}

Is there a solution to make a method call functions a dynamic amount of parameters by method references?

So, I have the following classes:
public class MainClass{
public void run(String infoOne, String infoTwo, String infoThree, String infoFour, String infoFive, String infoSix){
SomeClass someClass = new SomeClass();
someClass.runSomeMethod();
someClass.runSomeMethodTwo( infoOne);
someClass.runSomeMethodThree( infoThree, infoOne, infoSix);
someClass.runSomeMethodFour( infoTwo, infoFive);
someClass.runSomeMethodFive(infoThree, infoFive, infoOne, infoSix);
}
}
‌‌
public class SomeClass{
public boolean runSomeMethod(){
// do something
}
public boolean runSomeMethodTwo(String arg){
// do something
}
public boolean runSomeMethodThree(String argOne, String argTwo, String argThree){
// do something
}
public boolean runSomeMethodFour(String argOne, String argTwo){
// do something
}
public boolean runSomeMethodFive(String argOne, String argTwo, String argThree, String argFour){
// do something
}
}
As you can see it's a bunch of methods taking only Strings as parameters (but a different amount every time). What I want now is to wrap each single method in a try catch block and log some results. To do that I wanted to put a method in between that handles the logging:
log(SomeClass::runSomeMethodFour);
public void log(????? method, String...args){
try{
if(method.execute(args);
System.out.println("Success!");
} else {
System.out.println("Failed to execute!");
}
} catch (Exception e){
e.printStackTrace();
}
}
Is this possible in some way? To pass a dynamic number of arguments to a lambda function? Or could I do something with generics?
There is no need to create a complicated Reflection-based solution. Your problems stem from the unnecessary attempt to separate the method and the parameter arguments, instead of just encapsulating the entire action like
public class MainClass {
public void run(String infoOne, String infoTwo, String infoThree,
String infoFour, String infoFive, String infoSix) {
SomeClass someClass = new SomeClass();
log(() -> someClass.runSomeMethod());
log(() -> someClass.runSomeMethodTwo(infoOne));
log(() -> someClass.runSomeMethodThree(infoThree, infoOne, infoSix));
log(() -> someClass.runSomeMethodFour(infoTwo, infoFive));
log(() -> someClass.runSomeMethodFive(infoThree, infoFive, infoOne, infoSix));
}
public void log(BooleanSupplier method) {
try {
if(method.getAsBoolean()) {
System.out.println("Success!");
} else {
System.out.println("Failed to execute!");
}
} catch (Exception e ){
e.printStackTrace();
}
}
}
For the work of the log method, only the boolean return value is relevant, which matches the functional signature of BooleanSupplier.
JLS described Method Reference Expression:
The compile-time declaration of a method reference is the method to which the expression refers. In special cases, the compile-time declaration does not actually exist, but is a notional method that represents a class instance creation or an array creation. The choice of compile-time declaration depends on a function type targeted by the expression, just as the compile-time declaration of a method invocation depends on the invocation's arguments.
A method reference expression is compatible in an assignment context, invocation context, or casting context with a target type T if T is a functional interface type (§9.8) and the expression is congruent with the function type of the ground target type derived from T.
the method reference expression must be assign an exactly Function Interface at compile time. and Function Interface is a SAM Interface. so you can't bind a method handler dynamically by method reference expression at runtime.
but you can using reflection or invoke api to achieve it.
let see each method expression refer to a Function Interface in your SomeClass results in refers to different Function Interface type:
SomeClass it = new SomeClass();
BooleanSupplier first1 = it::runSomeMethod;//bound
Predicate<SomeClass> first2 = SomeClass::runSomeMethod;//unbound
Predicate<String> second1 = it::runSomeMethodTwo;//bound
BiPredicate<SomeClass, String> second2 = SomeClass::runSomeMethodTwo;//unbound
...
Hearing about "reflection" as a comment by Oliver Charlesworth I came up with the following solution:
public class Test {
static Test testLogger = new Test(); //This should be another class ofcourse, but it doesn't matter for this example
public static void main(String[] args) throws NoSuchMethodException, SecurityException{
Test test = new Test();
run(test, "something", "hi", "hai", "blaa");
}
public static void run(Object pageObjectModel, String methodName, String...arguments){
Class<String>[] args = new Class[arguments.length];
Arrays.fill(args, String.class);
try {
testLogger.log(pageObjectModel, pageObjectModel.getClass().getMethod(methodName, args), arguments);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
}
private void log(Object pageObjectModel, Method method, String...arguments) {
try {
if((Boolean)method.invoke(pageObjectModel, (Object[])arguments)){
System.out.println("Success!");
} else {
System.out.println("Fail!");
}
} catch (Exception e){
e.printStackTrace();
}
}
public boolean something(String one, String two, String three){
System.out.println(one+", "+two+", "+three);
return true;
}
}
This seems to be perfect for what I'm trying to achieve. Although I don't really like reflection due to having bad experiences with it (giving problems with obfuscated code) I think it's fine for this project.
Thanks for helping me in the right direction!

Java: Use the same code with two different versions of a dependent class

Consider a Java class Foo that uses a library Bar. Foo should be distributed as a binary .class file and use the version of Bar that is already existing on a clients classpath.
There are two different versions of Bar that only differ in its method signatures. Foo should be compatible with both of them.
Example code:
public class Foo {
public static void main(String[] args){
Bar.librarycall("hello from foo");
//or
Bar.librarycall("hello from foo",1);
}
}
//v1
public class Bar {
public static void librarycall(String argument){
System.out.println("Bar1: " + argument);
}
}
//v2
public class Bar {
public static void librarycall(String argument,int i){
for(int j = 0; j < i; j++)
System.out.println("Bar2: " + argument);
}
}
I want to avoid reflection if possible. How would you propose to create a class Foo that is compatible with both versions of Bar?
[Edit]
This problem originates in a project I am working on. Bar corresponds to an external library I am using but cannot be modified for the code to work (I don't have the source code and the license doesn't allow modifications).
A refelective solution.
Class<?> c;
try {
c = Class.forName("Bar");
Method meths[] = c.getMethods();
Method v1method = null;
Method v2method = null;
for(Method m:meths) {
if(!m.getName().equals("librarycall")) continue;
if(!Modifier.isStatic(m.getModifiers())) {
System.out.println("Should be static");
continue;
}
Class<?> params[] = m.getParameterTypes();
if(params.length == 1 && params[0].equals(String.class) )
v1method = m;
if(params.length == 2 && params[0].equals(String.class) && params[1].equals(Integer.TYPE) )
v2method = m;
}
if(v2method!=null) {
v2method.invoke(null,"V2",5);
}
else if(v1method!=null) {
v1method.invoke(null,"V1");
}
else
System.out.println("No method found");
} catch (ClassNotFoundException e) {
System.out.println(e);
} catch (IllegalArgumentException e) {
System.out.println(e);
} catch (IllegalAccessException e) {
System.out.println(e);
} catch (InvocationTargetException e) {
System.out.println(e);
}
You could use c = Bar.class; or if you already have an instance bar of Bar c = bar.getClass(). The invoke syntax is for static methods if its non static you need v1method.invoke(bar,"V1");.
Reflection does seem like the simplest way. The alternative would be to try calling the second version and catch a NoSuchMethodException.
public class Foo {
public static void main(String[] args){
try {
Bar.librarycall("hello from foo",1);
catch(NoSuchMethodException e) {
Bar.librarycall("hello from foo");
}
}
This is ugly, and slower, use Reflection its what its there for.
It sounds like this one task that is handled by the strategy pattern.
I'm assuming that:
You cannot change any of the versions of the Bar class files
You have the ability to write new Foo files
For some reason, you really want to avoid using Reflection
The two Bar files have the same package name
You may need to distribute two versions of the Foo class, as mentioned by JB Nizet in the comment to your question.

Call Methods in Sequence

I have 5 different methods like this
public void met1(){}
public void met2(){}
public void met3(){}
public void met4(){}
public void met5(){}
I want to call this method from 1 to 5 is there any convinient way to do this.
I don't want to call one by one or I don't want to put method call inside other method.
How Can I do this??
I believe you could do it with reflection with something like:
YourClass classInstance = new YourClass();
for (int i = 1; i < 6; i++) {
Method yourMethod = YourClass.class.getMethod("met" + i);
method.invoke(instance);
}
Haven't tested it out, so no guarantees.
Have you looked into fluent design patterns? http://www.javacodegeeks.com/2013/01/fluent-object-creation.html
Example would be something like this:
myObject.met1().met2().met3().met4().met5().result();
You can use the Execute Around Method pattern.
public class Resource {
private Resource(){}
public void opc1(){
System.out.println("Opc1");
// use can use cascade pattern( return this)
}
public void opc2(){
System.out.println("Opc2");
// use can use cascade pattern( return this)
}
public void opc3(){
System.out.println("Opc3");
// use can use cascade pattern( return this)
}
public void closeResource(){
System.out.println("Release resource");
}
public static void use(Consumer<Resource> consumer){
Resource resource =new Resource();
consumer.accept(resource);
resource.closeResource(); // force to execute closeResource method
}
public static void main(String[] args) {
Resource.use(resource -> {
resource.opc1();
resource.opc3();
resource.opc2();
});
}
}
More info at https://agiledeveloper.com/
You could do this with reflection as other answers have previously mentioned. Reflection is generally avoided if possible.
In reality the most common design pattern to address your concern would be Chain of Responsibility.
http://en.wikipedia.org/wiki/Chain-of-responsibility_pattern
The only way to call methods by name is through reflection. See this article for how to do this:
How do I invoke a Java method when given the method name as a string?
Something like this should work:
for (int i = 1; i < 6; i++){
java.lang.reflect.Method method;
try {
method = this.getClass().getMethod("met" + i);
method.invoke(this);
} catch (SecurityException e) {
// ...
} catch (NoSuchMethodException e) {
// ...
}
}

How to make Virtual static methods or a functional equivalent with reflection in java

I have a tree of projectile classes I am trying to use some reflection to not implement every combination possible by hand when most of it would be copy paste or at best a lot of one liner virtual methods to override attributes.
Basically I have different weapon types that shoot in different patterns such as twin linked, alternating or just a single weapon, and a number of different projectiles such as missiles, bullets, sniper bullets.
The syntax is currently the flavor of:
public Bomber() {
weapons.add(new TwinLinkedWeapon<Missile>(Missile.class));
weapons.add(new Weapon<Bullet>(Bullet.class));
}
and Weapon looks like:
public class Weapon<T extends Projectile> {
long lastShot;
protected Constructor<? extends T> ctor;
public Weapon(Class<? extends T> projectileType) {
try {
ctor = projectileType.getDeclaredConstructor(actor.Actor.class);
} catch (SecurityException e) {
e.printStackTrace();
return;
} catch (NoSuchMethodException e) {
e.printStackTrace();
return;
}
lastShot = 0;
}
protected long getLastShotTime() {
return lastShot;
}
protected T newProjectile(actor.Actor ship){
T projectile = null;
try {
projectile = ctor.newInstance(ship);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return projectile;
}
protected void setLastShotTime(long time) {
lastShot = time;
}
public void shoot(Actor ship) {
//calculates time passed in milliseconds
if((System.currentTimeMillis() - getLastShotTime()) > T.getShotCoolDown()) {
game.Game.getActors().add(newProjectile(ship));
setLastShotTime(System.currentTimeMillis());
}
}
public String getWeaponName(){
return "" + getClass().getName() + " " + ctor.getName();
}
}
My issue is fairly simple to understand. On the line if((System.currentTimeMillis() - getLastShotTime()) > T.getShotCoolDown())
T is an abstract Projectile class instead of a derived class such as Bullet or Missile so when I call the static method T.getShotDelay() it always calls Projectile.getShotDelay() instead of the derived class.
My only solution is to make an instance of T with ctor and have that attribute be instance based instead of class based, but that seems like a 'less than ideal' solution.
I am new to java reflection and am unsure of the syntax to achieve this. I would appreciate any input.
You can get static methods from Class objects and invoke them on null, no need to call constructors. Just take the runtime class of T, that is:
T t = something;
Class<?> tClass = t.getClass();
Method staticMethod = tClass.getMethod("methodName");
staticMethod.invoke(null); // Static methods can be invoked on null.
You should use instance methods to get the functionality that you want.
Maybe you should consider using abstract factory pattern.
You can have IProjectileFactory interface that is implemented by MissileFactory and BulletFactory.
The factories are able to create new projectiles Missile and Bullet that implement the IProjectile interface. The projectile factories are given as parameters when you create new weapon instances (i.e. new TwinLinkedWeapon(new MissileFactory())).

Categories