So the situation is something like this:
private void myMethod()
{
System.out.println("Hello World"); //some code
System.out.println("Some Other Stuff");
System.out.println("Hello World"); //the same code.
}
We don't want to be repeating our code.
The technique described here works pretty well:
private void myMethod()
{
final Runnable innerMethod = new Runnable()
{
public void run()
{
System.out.println("Hello World");
}
};
innerMethod.run();
System.out.println("Some other stuff");
innerMethod.run();
}
But what if I want to pass in a parameter to that inner method?
eg.
private void myMethod()
{
final Runnable innerMethod = new Runnable()
{
public void run(int value)
{
System.out.println("Hello World" + Integer.toString(value));
}
};
innerMethod.run(1);
System.out.println("Some other stuff");
innerMethod.run(2);
}
gives me: The type new Runnable(){} must implement the inherited abstract method Runnable.run()
While
private void myMethod()
{
final Runnable innerMethod = new Runnable()
{
public void run()
{
//do nothing
}
public void run(int value)
{
System.out.println("Hello World" + Integer.toString(value));
}
};
innerMethod.run(1);
System.out.println("Some other stuff");
innerMethod.run(2);
}
gives me The method run() in the type Runnable is not applicable for the arguments (int).
Nope, that isn't a method but an anonymous object. You can create an extra method to use for the object.
Thread thread = new Thread( new Runnable()
{
int i,j;
public void init(int i, int j)
{
this.i = i;
this.j=j;
}
});
thread.init(2,3);
thread.start();
And wrap runnable in a Thread, and call start! Not run().
Because you can't call the constructor of an anonymous class, as pointed out by #HoverCraft you could extend a named class that implements Runnable.
public class SomeClass implements Runnable
{
public SomeClass(int i){ }
}
Looks like you just want inner methods. Java does't let you have them, so the Runnable hack you describe lets you sort-of declare an inner method.
But since you want more control over it, why not define your own:
interface Inner<A, B> {
public B apply(A a);
}
Then you can say:
private void myMethod(..){
final Inner<Integer, Integer> inner = new Inner<Integer, Integer>() {
public Integer apply(Integer i) {
// whatever you want
}
};
// then go:
inner.apply(1);
inner.apply(2);
}
Or use some library that provides functor objects. There should be many. Apache Commons has a Functor that you can use.
Related
I am trying to learn multi-threading using the runnable interface but I am having some trouble figuring out how to pass information. Basically, in the example below, I want to remove the static reference from the Hashmap but if I do that, the program breaks. How do I pass the hashmap to the runnable interface class without using the static keyword?
public class ThreadDemo {
static HashMap <String, Integer>map = new HashMap<>();
public String Hi() {
return "hi";
}
public String Hello() {
return "Hello";
}
public void addToMap(String item) {
if (map.containsKey(item)) {
map.put(item, map.get(item) + 1);
} else {
map.put(item, 1);
}
}
public static void main(String[] args) throws InterruptedException {
ArrayList<Thread> all = new ArrayList<>();
for (int i = 0; i < 50; ++i) {
threader threader = new threader();
all.add(new Thread(threader));
}
for (Thread thread : all) {
thread.start();
}
for (Thread thread : all) {
thread.join();
}
ThreadDemo td = new ThreadDemo();
System.out.println(td.map);
}
}
And a class that implements Runnable
public class threader implements Runnable {
ThreadDemo td = new ThreadDemo();
#Override
public void run() {
synchronized(td.map) {
td.addToMap(td.Hi());
td.addToMap(td.Hello());
}
}
}
A class instance is all about information.
public class threader implements Runnable {
final private ThreadDemo td;
public threader(ThreadDemo td) {
this.td = td;
}
#Override
public void run() {
..
}
}
then to use (details omitted, just the idea):
ThreadDemo theTd = new ThreadDemo();
for (...) {
threader threader = new threader(theTd);
all.add(new Thread(threader));
}
....
Of course, all threads are using the same ThreadDemo, with the same map, so you'll need to ensure access is interlocked in some way, e.g., by using synchronized. The ThreadDemo.addToMap method should be synchronized in this example, rather than the caller of addToMap. This puts the responsibility for the "care of the map" into the place that actually owns the map, and is consequently a better design.
I chose to share the ThreadDemo rather than just the map inside the ThreadDemo, since it looks to me that the intent of ThreadDemo is just to be a wrapper around the map.
This is my test code:
Activity activityMock = Mockito.mock(TestActivity.class);
doAnswer(new Answer() {
#Override
public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
Object[] args = invocationOnMock.getArguments(); // ->>>> args contains one Foo instance called "foo"
return invocationOnMock;
}
}).when(activityMock).runOnUiThread(any(Runnable.class));
runDialogOnUiThread(activityMock, new Foo());
To the following production code:
public static void runDialogOnUIThread(final Activity activity, final Foo foo) {
activity.runOnUiThread(new Runnable() {
#Override public void run() {
doSmth();
}
});
}
See my comment in the test code. I expect invocationOnMock.getArguments() to return the Runnable instance, but it is returning the Foo instance (Which makes absolutely no sense to me)?
I thought
doAnswer(new Answer(){..}).when(b).bMethod(any(C.class))
intercepts when bMethod() is called anywhere on b and it will pass the instance of C.class to the doAnswer() to make it available in the "new Answer().."-Callback..
How can I access the anonymous Runnable instance, which is created in the production code?
I'm guessing that your anonymous Runnable instance is defined in Foo, right?
Here's some code I wrote to try to reproduce your issue:
public class MockitoTest {
#Test
public void test() {
final Activity activityMock = Mockito.mock(TestActivity.class);
doAnswer(new Answer() {
#Override
public Object answer(final InvocationOnMock invocationOnMock) throws Throwable {
final Object[] args = invocationOnMock.getArguments();
System.out.println("Is argument a Runnable? " + (args[0] instanceof Runnable));
System.out.println("What is the argument toString()? " + args[0].toString());
return invocationOnMock;
}
}).when(activityMock).runOnUiThread(any(Runnable.class));
runDialogOnUIThread(activityMock);
}
public void runDialogOnUIThread(final Activity activity) {
final Runnable r = new Runnable() {
#Override public void run() {
System.out.println("***");
}};
activity.runOnUiThread(r);
}
public static interface Activity {
void runOnUiThread(Runnable r);
}
public static class TestActivity implements Activity {
#Override
public void runOnUiThread(final Runnable r) { r.run(); }
}
}
Pretty much the same thing, but it is trimmed down to illustrate where I think you are getting confused.
The output is:
Is argument a Runnable? true
What is the argument toString()? stackoverflow.MockitoTest$2#6b143ee9
Note that the second output contains MockitoTest for the toString() output and nothing about it being a Runnable. That's because the toString() method is not being explicitly defined in the anonymous Runnable.
Let's change the Runnable as follows:
final Runnable r = new Runnable() {
#Override public void run() {
System.out.println("***");
}
#Override public String toString() {
return "ANON RUNNABLE";
}
};
Then the output is:
Is argument a Runnable? true
What is the argument toString()? ANON RUNNABLE
What I suspect you were getting tripped up on is that the toString() output looked like the same class name as the class that the anonymous Runnable was created in.
Here is the best way I could summarise my situation:
Class1 makes new Thread(new Class2)
Is there a way from inside objects 2 code I can access non-static public methods from object 1?
Not sure if I have explained myself enough but I can answer any questions that could help describe it better
Edit: To elaborate Class1 is a multithreaded server and Class2 is the WorkerClass and i want to access Class1.stop() to stop the server from inside the workerClass
There are at least 3 ways to do this:
(1) Use an anonymous inner class:
public class Class1 {
public void foo() {}
public void bar() {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
foo();
}
});
}
}
(2) Use a named inner class:
public class Class1 {
public void foo() {}
public void bar() {
Thread t = new Thread(new MyRunnable());
}
private class MyRunnable implements Runnable {
#Override
public void run() {
foo();
}
}
}
(3) Pass this to the constructor of another top-level class:
public class Class1 {
public void foo() {}
public void bar() {
Thread t = new Thread(new MyRunnable(this));
}
}
class MyRunnable implements Runnable {
private Class1 class1;
public MyRunnable(Class1 class1) {
this.class1 = class1;
}
#Override
public void run() {
class1.foo();
}
}
I have created interface with one method:
public interface ResultCallback {
void onResult(String message);
}
And I have object with method that has interface as parameter:
public class Command() {
public void methodWithCallback(int param1, String param2, ResultCallback callback) {
// There are some calculations
callback.onResult(param2);
}
}
Then In my Main Java file I write this:
public class Main() {
public static void main(String[] args) {
Command c = new Command();
c.methodWithCallback(int 0, "SOME STRING", new ResultCallback() {
#Override
public void onResult(String str) {
// work with str
outsideMethod(str);
}
});
}
public void outsideMethod(String str) {
// some code
}
}
Does this code can be considered as async? And is it safe to call outsideMethod to handle params?
As said, it is not async. For the call to be async the method should execute on another thread.
You can't call outsideMethod since it's called from a static method. You need an instance of main to be able to call outsideMethod. If it is safe or not depends on what the code is doing.
One way to make it async is the following:
public class Command {
private ExecutorService iExecutor;
public Command(ExecutorService executor) {
iExecutor = executor;
}
public void methodWithCallback(final int param1, final String param2, final ResultCallback callback) {
iExecutor.execute(new Runnable() {
#Override
public void run() {
// There are some calculations
callback.onResult(param2);
}
});
}
}
You have to know what you're doing if using threads. Things have to be thread safe etc depending on how you are doing stuff. To run Command on a single thread create a single thread Executor and pass same Executor to all Commmand, like so:
ExecutorService executor = Executors.newSingleThreadExecutor();
Command command1 = new Command(executor);
Command command2 = new Command(executor);
suppose we have these classes and read the comments
class Work {
void doWork(){ }
void commit(){}
}
class MyRunable implements Runnable {
run(){
Work work=new Work();
work.doWork();
//i can't write work.commit() here, because sometimes i want Thread runs both methods
//and sometimes runs only doWork()
}
}
class Tasks{
main(){
MyRunable myRunable=new MyRunable();
Thread t=new Thread(myRunable);
t.start();
//suppose now i need to call commit() method by the same thread (t)
//how can i do that
}
}
also i don't want to use constructor to determine if i want to call both method or not
You could try using a thread pool with a single thread and keep enqueuing methods as needed:
class Tasks {
public static void main(String[] args) {
ExecutorService exec = Executors.newSingleThreadExecutor();
final Work work = new Work();
exec.submit(new Runnable() {
public void run() {
work.doWork();
}
});
// later
exec.submit(new Runnable() {
public void run() {
work.commit();
}
});
}
}
This way, both methods will be executed in a sequence by the same thread, but separately.
Add parameter to your class MyRunnable. Call this parameter "runingMode". It could be an enum:
enum RunningMode {
DO_WORK {
public void work(Work work) {
work.doWork();
}
},
COMMIT {
public void work(Work work) {
work.commit();
}
};
public abstract void work();
}
Now your class MyRunnable should have list of modes:
class MyRunable implements Runnable {
private Collection<RunningMode> modes;
MyRunable(Collection<RunningMode> modes) {
this.modes = modes;
}
}
Implement run() method as following:
Work work=new Work();
for (RunningMode mode : modes) {
mode.work(work);
}
work.doWork();
Create instance of your class passing to it the mode you currently need:
MyRunable myRunable=new MyRunable(Arrays.asList(RunningMode.DO_WORK, RunningMode.COMMIT));
You could use an anonymous class.
final boolean condition = ...
Thread t = new Thread(new Runnable() {
public void run() {
Work work=new Work();
work.doWork();
if(condition)
work.commit();
}});
t.start();