Issue with thread safety- Not getting the answer expected - java

I am attempting to add up
a sequence of double precision floating point numbers which are given as Strings in an
array. The addition of these numbers is carried out in a separate background thread.
Running the code calculates the sum of the array of numbers and also gives the time that
the system took to calculate this in seconds.
I am not sure how to implement synchronization and conditional synchronization to this class:
public class SerialAdder implements Adder {
private String[] values;
private double sum;
private boolean ready = false;
public void run() {
synchronized (this) {
sum = 0.0;
for (int i = 0; i < values.length; i++) {
sum = sum + Double.valueOf(values[i]);
}
ready = true;
}
}
public synchronized void setValues(String[] values) {
this.values = values;
}
public synchronized void setThreads(int threads) {
// This does nothing since this is the single-threaded version.
}
public synchronized double getSum() {
return sum;
}
}
This should not be changed but is here for reference.
public interface Adder extends Runnable {
void setValues(String[] values);
void setThreads(int threads);
double getSum();
}
This is the main
import java.io.*;
public class Main {
/**
* All this data is "statistically initialized" and hence visibility to all threads in the running application.
*/
private static final String[] DATA1 = {"1.0", "2.0", "3.0", "4.0"};
private static final String[] DATA2 = {"100000000000000000000.0", "-100000000000000000000.0", "1.0", "2.0"};
private static final String[] DATA3 = {"1.0", "2.0", "100000000000000000000.0", "-100000000000000000000.0"};
/**
* This is an Example of more complex "static initialization" that guarantees data visibility to all threads.
*/
private static final String[] DATA4;
static {
/*** TASK3: CHANGE THIS VALUE SO THAT YOUR COMPUTER TAKES SEVERAL SECONDS FOR THE SERIAL CASE ***/
final int POWER = 10;
final int N = (int)Math.pow(2, POWER);
DATA4 = new String[N];
for (int i = 0; i < N; i++) {
DATA4[i] = String.valueOf(1.0/N);
}
}
public static void main(String[] args) throws InterruptedException, IOException {
// Start the timer ...
long startTime = System.currentTimeMillis();
/*** TASK 2 - CHANGE THIS LINE TO SEE HOW THE CODE BEHAVES WITH DIFFERENT DATA INPUTS. ***/
String[] values = DATA1;
/*** TASK 3 - CHANGE THE FOLLOWING SINGLE LINE TO CHANGE TO USING A MULTITHREADED VERSION OF THE ADDER. ***/
// This is an example of "programming to an interface" ... so only a single line
// needs to be changed to change the implementation used in the rest of the code.
Adder adder = new SerialAdder(); // = MultithreaderAdder();
adder.setValues(values);
new Thread(adder).start();
System.out.println("Answer = " + adder.getSum());
// Printed answer ... stop the timer.
long endTime = System.currentTimeMillis();
// Nanoseconds to seconds ...
System.out.println("Time = " + (endTime - startTime)/1000.0 + " seconds.") ;
}
}
And the multithreaded adder:
public class MultithreadedAdder implements Adder {
public void run() {};
public void setValues(String[] values) {};
public void setThreads(int threads) {};
public double getSum() {
return 0.0;
}
}
I am using the current data {“1.0”, “2.0”, “3.0”, “4.0”} and so expect answer of 10.0 however I am getting 0.

I would suggest some simplifications:
Drop the Adder interface. Implement the Callable interface instead. It allows you to return a value.
I'd advise against the setThreads() method. Give your Callable instance to a pooled Executor.
If one of those Strings in the array does not parse as a Double your sum will fail. What do you plan to do about it? I'd have a try/catch block.
import java.util.Arrays;
import java.util.concurrent.Callable;
public class DoubleStreamAdder implements Callable<Double> {
private final String [] values;
public DoubleStreamAdder(final String [] v) {
this.values = new String[v.length];
System.arraycopy(v, 0, this.values, 0, v.length);
}
#Override
public Double call() throws Exception {
return Arrays.stream(this.values).mapToDouble(Double::valueOf).sum();
}
}
You could do all of this using Java functional programming without the classes: see the single line in my call() method. That is what you're trying to do. The less code you write, the fewer bugs you'll have. You can eliminate more than 17 lines of code by deleting your interface and the class and writing a single line of code. Much better.

Related

Array sum ForkJoin implementation slower than the serial implementation

So I am trying to understand how Java ForkJoin framework works. The simplest thing I could think of implementing was an array sum. However my parallel implementation is 3-4 times slower than the serial implementation. I must obviously be doing something wrong, but I am not sure what.
To measure the performance, I created a set of classes and interfaces (I used Lombok annotations for generating boilerplate code).
interface Result<T> {
T getValue();
}
#AllArgsConstructor(staticName = "of")
#Value
class MeasuredResult<T> implements Result<T> {
T value;
long elapsedTimeMillis;
}
#AllArgsConstructor(staticName = "of")
class CombinedResult<T> implements Result<T> {
private final MeasuredResult<T> parallelResult;
private final MeasuredResult<T> serialResult;
public double getParallelizationFactor() {
return (double) serialResult.getElapsedTimeMillis() / parallelResult.getElapsedTimeMillis();
}
public T getParallelValue() {
return parallelResult.getValue();
}
public T getSerialValue() {
return parallelResult.getValue();
}
#Override
public T getValue() {
return getSerialValue();
}
public boolean isDifferent() {
return !isSame();
}
public boolean isSame() {
return parallelResult.getValue().equals(serialResult.getValue());
}
}
interface Parallelizable<T> {
T processParallelly();
T processSerially();
default CombinedResult<T> getResult() {
MeasuredResult<T> parallelResult = measureParallel();
MeasuredResult<T> serialResult = measureSerial();
return CombinedResult.of(parallelResult, serialResult);
}
default MeasuredResult<T> measure(Supplier<T> supplier) {
long startTime = System.currentTimeMillis();
T value = supplier.get();
long endTime = System.currentTimeMillis();
return MeasuredResult.of(value, endTime - startTime);
}
default MeasuredResult<T> measureParallel() {
return measure(this::processParallelly);
}
default MeasuredResult<T> measureSerial() {
return measure(this::processSerially);
}
}
The idea was that by implementing the Parallelizable interface, I'd define the serial and parallel versions of the code and use the getResult() function to get a CombinedResult object with the values and time measurement to unit test with. Here's my implementation of the array sum.
#AllArgsConstructor
public class ArraySum implements Parallelizable<Integer> {
private final int[] nums;
#Override
public Integer processParallelly() {
return new ParallelForkJoinImpl(0, nums.length).compute();
}
#Override
public Integer processSerially() {
int sum = 0;
for (int num : nums) {
sum += num;
}
return sum;
}
#AllArgsConstructor()
private class ParallelForkJoinImpl extends RecursiveTask<Integer> {
private static final int THRESHOLD = 1_000;
private final int start;
private final int end;
#Override
protected Integer compute() {
if (end - start <= THRESHOLD) {
int sum = 0;
for (int i = start; i < end; i++) {
sum += nums[i];
}
return sum;
}
int mid = (start + end) / 2;
ForkJoinTask<Integer> left = new ParallelForkJoinImpl(start, mid).fork();
ForkJoinTask<Integer> right = new ParallelForkJoinImpl(mid, end).fork();
return left.join() + right.join();
}
}
}
From what I understand, calling fork() on the RecursiveTask implementation should give me a Future object as response which will block on computation when the join() function is called on it. Also use the common ForkJoinPool will automatically be used when fork() is called.
But like I said, the value for elapsedTimeMillis for the parallel implementation is 3-4 times larger than the serial implementation, and I don't know why. What did I do wrong here?

How to efficiently update probabilities within an EnumeratedDistribution instance?

Question Summary
Is there any way of updating the probabilities within an existing instance of the class EnumeratedIntegerDistribution without creating an entirely new instance?
Background
I'm trying to implement a simplified Q-learning style demonstration using an android phone. I need to update the probabilities for each item with each loop through the learning process. Currently I am unable to find any method accessible from my instance of enumeratedIntegerDistribution that will let me reset|update|modify these probabilities. Therefore, the only way I can see to do this is to create a new instance of EnumeratedIntegerDistribution within each loop. Keeping in mind that each of these loops is only 20ms long, it is my understanding that this would be terribly memory inefficient compared to creating one instance and updating the values within the existing instance. Is there no standard set-style methods to update these probabilities? If not, is there a recommended workaround (i.e. using a different class, making my own class, overriding something to make it accessible, etc.?)
A follow up would be whether or not this question is a moot effort. Would the compiled code actually be any more/less efficient by trying to avoid this new instance every loop? (I'm not knowledgeable enough to know how compilers would handle such things).
Code
A minimal example below:
package com.example.mypackage.learning;
import android.app.Activity;
import android.os.Bundle;
import org.apache.commons.math3.distribution.EnumeratedIntegerDistribution;
public class Qlearning extends Activity {
private int selectedAction;
private int[] actions = {0, 1, 2};
private double[] weights = {1.0, 1.0, 1.0};
private double[] qValues = {1.0, 1.0, 1.0};
private double qValuesSum;
EnumeratedIntegerDistribution enumeratedIntegerDistribution = new EnumeratedIntegerDistribution(actions, weights);
private final double alpha = 0.001;
int action;
double reward;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
while(true){
action = determineAction();
reward = determineReward();
learn(action, reward);
}
}
public void learn(int action, double reward) {
qValues[selectedAction] = (alpha * reward) + ((1.0 - alpha) * qValues[selectedAction]);
qValuesSum = 0;
for (int i = 0; i < qValues.length; i++){
qValuesSum += Math.exp(qValues[i]);
}
weights[selectedAction] = Math.exp(qValues[selectedAction]) / qValuesSum;
// *** This seems inefficient ***
EnumeratedIntegerDistribution enumeratedIntegerDistribution = new EnumeratedIntegerDistribution(actions, weights);
}
}
Please don't focus on the absence of the determineAction() or determineReward() methods, as this is simply a minimal example. You could easily just sub in fixed values there (e.g. 1, and 1.5) if you wanted a working example.
Also, I'm well aware of the infinite while loop that would be troublesome for a GUI, but again, just trying to reduce the code I have to show here to get the point across.
Edit:
In response to a comment I'm posting what I had for a similar class below. Note I haven't used this in over a year and things may be broken. Just posting for reference:
public class ActionDistribution{
private double reward = 0;
private double[] weights = {0.34, 0.34, 0.34};
private double[] qValues = {0.1, 0.1, 0.1};
private double learningRate = 0.1;
private double temperature = 1.0;
private int selectedAction;
public ActionDistribution(){}
public ActionDistribution(double[] weights, double[] qValues, double learningRate, double temperature){
this.weights = weights;
this.qValues = qValues;
this.learningRate = learningRate;
this.temperature = temperature;
}
public int actionSelect(){
double sumOfWeights = 0;
for (double weight: weights){
sumOfWeights = sumOfWeights + weight;
}
double randNum = Math.random() * sumOfWeights;
double selector = 0;
int iterator = -1;
while (selector < randNum){
try {
iterator++;
selector = selector + weights[iterator];
}catch (ArrayIndexOutOfBoundsException e){
Log.e("abcvlib", "weight index bound exceeded. randNum was greater than the sum of all weights. This can happen if the sum of all weights is less than 1.");
}
}
// Assigning this as a read-only value to pass between threads.
this.selectedAction = iterator;
// represents the action to be selected
return iterator;
}
public double[] getWeights(){
return weights;
}
public double[] getqValues(){
return qValues;
}
public double getQValue(int action){
return qValues[action];
}
public double getTemperature(){
return temperature;
}
public int getSelectedAction() {
return selectedAction;
}
public void setWeights(double[] weights) {
this.weights = weights;
}
public void setQValue(int action, double qValue) {
this.qValues[action] = qValue;
}
public void updateValues(double reward, int action){
double qValuePrev = getQValue(action);
// update qValues due to current reward
setQValue(action,(learningRate * reward) + ((1.0 - learningRate) * qValuePrev));
// update weights from new qValues
double qValuesSum = 0;
for (double qValue : getqValues()) {
qValuesSum += Math.exp(temperature * qValue);
}
// update weights
for (int i = 0; i < getWeights().length; i++){
getWeights()[i] = Math.exp(temperature * getqValues()[i]) / qValuesSum;
}
}
public double getReward() {
return reward;
}
public void setReward(double reward) {
this.reward = reward;
}
}
Unfortunately it is not possible to update the existing EnumeratedIntegerDistribution. I have had similar issue in the past and I ended up re-creating the instance everytime I need to update the chances.
I won't worry too much about the memory allocations as those will be short-lived objects. These are micro-optimisations you should not worry about.
In my project I did implement a cleaner way with interfaces to create instances of these EnumeratedDistribution class.
This is not the direct answer but might guide you in the right direction.
public class DistributedProbabilityGeneratorBuilder<T extends DistributedProbabilityGeneratorBuilder.ProbableItem> {
private static final DistributedProbabilityGenerator EMPTY = () -> {
throw new UnsupportedOperationException("Not supported");
};
private final Map<Integer, T> distribution = new HashMap<>();
private DistributedProbabilityGeneratorBuilder() {
}
public static <T extends ProbableItem> DistributedProbabilityGeneratorBuilder<T> newBuilder() {
return new DistributedProbabilityGeneratorBuilder<>();
}
public DistributedProbabilityGenerator build() {
return build(ProbableItem::getChances);
}
/**
* Returns a new instance of probability generator at every call.
* #param chanceChangeFunction - Function to modify existing chances
*/
public DistributedProbabilityGenerator build(Function<T, Double> chanceChangeFunction) {
if (distribution.isEmpty()) {
return EMPTY;
} else {
return new NonEmptyProbabilityGenerator(createPairList(chanceChangeFunction));
}
}
private List<Pair<Integer, Double>> createPairList(Function<T, Double> chanceChangeFunction) {
return distribution.entrySet().stream()
.map(entry -> Pair.create(entry.getKey(), chanceChangeFunction.apply(entry.getValue())))
.collect(Collectors.toList());
}
public DistributedProbabilityGeneratorBuilder<T> add(int id, T item) {
if (distribution.containsKey(id)) {
throw new IllegalArgumentException("Id " + id + " already present.");
}
this.distribution.put(id, item);
return this;
}
public interface ProbableItem {
double getChances();
}
public interface DistributedProbabilityGenerator {
int generateId();
}
public static class NonEmptyProbabilityGenerator implements DistributedProbabilityGenerator {
private final EnumeratedDistribution<Integer> enumeratedDistribution;
NonEmptyProbabilityGenerator(List<Pair<Integer, Double>> pairs) {
this.enumeratedDistribution = new EnumeratedDistribution<>(pairs);
}
#Override
public int generateId() {
return enumeratedDistribution.sample();
}
}
public static ProbableItem ofDouble(double chances) {
return () -> chances;
}
}
Note - I am using EnumeratedDistribution<Integer>. You can easily change it to be EnumuratedIntegerDistribution.
The way I use the above class is as follows.
DistributedProbabilityGenerator distributedProbabilityGenerator = DistributedProbabilityGeneratorBuilder.newBuilder()
.add(0, ofDouble(10))
.add(1, ofDouble(45))
.add(2, ofDouble(45))
.build();
int generatedObjectId = distributedProbabilityGenerator.generateId();
Again, this is not a direct answer to your question but more of a pointer towards how you can use these classes in a better way.

How to add the value of all the objects?

Let's say we have a class SCORE. It has three objects s1,s2 and s3. SCORE has an attribute RUNS. How to add the runs of all the objects ? SCORE has an internal method int TOTALSCORE(). so when that method is called, it should return the total score .
How should i call that method ? Like s1.TOTALSCORE() ? Or any other way?
In rare cases the thing that you want could be reasonably, but normally the class is not aware of all it's elements. A total Score is for a Collection of Score elements, maybe a List or a Set.
So you would do:
class Score {
int value;
// ...
public static int totalScore(Collection<Score> scores){
int sum = 0;
for (Score s: scores){
sum += s.value;
}
return sum;
}
}
And outside you would have
List<Score> myBagForScores = new ArrayList<>();
Score e1 = new Score...
myBagForScores.add(e1);
// e2, e3 and so on
int sum = Score.totalScore(myBagForScores);
Hope that helps!
Here is a small Proof-Of-Concept:
public class Score {
private static ReferenceQueue<Score> scoreRefQueue = new ReferenceQueue<Score>();
private static List<WeakReference<Score>> runs = new ArrayList<WeakReference<Score>>();
static { // remove references to instances that are Garbage Collected
new Thread(new Runnable() {
#Override
public void run() {
while(true) try {
Object scoreRef = scoreRefQueue.remove(); // blocks until next reference is available
synchronized(runs) { // synch access with summing iterator
runs.remove(scoreRef);
}
} catch(Throwable t) {
// ignore
}
}
}).start();
}
/**
* The factory method
*/
public static Score getInstance() {
final Score score = new Score();
final WeakReference<Score> scoreRef = new WeakReference<Score>(score, scoreRefQueue);
synchronized(runs) {
runs.add(scoreRef);
}
return score;
}
private int total;
private Score() {
// prevent creating instances outside this class
}
/**
* The service method
*/
public static int totalScore() {
int totalScore = 0;
synchronized(runs) { // synch access with cleanup thread
for(WeakReference<Score> scoreRef : runs) {
final Score score = scoreRef.get();
if(score != null) {
totalScore += score.total;
}
}
}
return totalScore;
}
}
The idea is not to allow creating instances outside your factory method #getInstance(). The instances are tracked using WeakReferences to allow their Garbage Collection. The list is update by a service thread waiting on the reference queue. Hope this helps.

JAVA: How to simulate concurrency

I have to create an application which simulates concurrent threads. The "server" creates a number of "threads" and stores them in a queue. Each "thread" has defined a time to finish his execution. The server polls each "thread" from the queue to do his job for 10 ms. If the thread has finished his job, it is removed from the queue. If not, it is added at the end of the queue. I used for this application PriorityQueue. The problem is that the code i wrote is not giving the expected output; a "thread" is executed until his execution time ends.
How can I solve this problem?
SimulatedThread class
public class SimulatedThread {
private int executionTime;
private Integer id;
private int executedTime;
private boolean finished;
public SimulatedThread(){
executedTime = 0;
executionTime = 0;
setFinished(false);
}
//getters and setters
}
Server class
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Random;
public class Server {
final int TIME = 10;
final int TH_NO = 10;
//priority
final int MIN_P = 1;
final int MAX_P = 100;
//execution time
final int MIN_E = 10;
final int MAX_E = 100;
private PriorityQueue<SimulatedThread> activeThreads;
public Server() {
Comparator<SimulatedThread> comparator = new SimulatedThreadComparator();
activeThreads = new PriorityQueue<SimulatedThread>(10,comparator);
}
public void createThreads(){
for( int i = 0; i < TH_NO; i++){
SimulatedThread th = new SimulatedThread();
th.setExecutionTime(generator(MAX_E, MIN_E));
th.setId(generator(MAX_P,MIN_P));
System.out.println("New thread has been created");
System.out.println(th.toString());
activeThreads.add(th);
}
}
public void executeThreads(){
while(!activeThreads.isEmpty()){
SimulatedThread th = activeThreads.poll();
if(!th.isFinished()){
try {
Thread.sleep(TIME);
th.setExecutedTime(th.getExecutedTime() + TIME);
System.out.println(th.toString());
if((th.getExecutionTime() - th.getExecutedTime()) <= 0 ){
th.setFinished(true);
} else{
activeThreads.add(th);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
activeThreads.removeAll(activeThreads);
}
private int generator(int max, int min){
Random rand = new Random();
return rand.nextInt((max - min) + 1) - min;
}
public static void main(String[] args){
Server s = new Server();
s.createThreads();
s.executeThreads();
}
EDIT
SimulatedThreadComparator class
import java.util.Comparator;
public class SimulatedThreadComparator implements Comparator<SimulatedThread> {
#Override
public int compare(SimulatedThread o1, SimulatedThread o2) {
return o1.getId().compareTo(o2.getId());
}
}
That explains it: since the priority is the ID, the last thread that was activated will return to the head of the queue, and be the next activated, until it's finished.
Perhaps you should compare the executed time instead of the ID?

How to return 2 values from a Java method?

I am trying to return 2 values from a Java method but I get these errors. Here is my code:
// Method code
public static int something(){
int number1 = 1;
int number2 = 2;
return number1, number2;
}
// Main method code
public static void main(String[] args) {
something();
System.out.println(number1 + number2);
}
Error:
Exception in thread "main" java.lang.RuntimeException: Uncompilable source code - missing return statement
at assignment.Main.something(Main.java:86)
at assignment.Main.main(Main.java:53)
Java Result: 1
Instead of returning an array that contains the two values or using a generic Pair class, consider creating a class that represents the result that you want to return, and return an instance of that class. Give the class a meaningful name. The benefits of this approach over using an array are type safety and it will make your program much easier to understand.
Note: A generic Pair class, as proposed in some of the other answers here, also gives you type safety, but doesn't convey what the result represents.
Example (which doesn't use really meaningful names):
final class MyResult {
private final int first;
private final int second;
public MyResult(int first, int second) {
this.first = first;
this.second = second;
}
public int getFirst() {
return first;
}
public int getSecond() {
return second;
}
}
// ...
public static MyResult something() {
int number1 = 1;
int number2 = 2;
return new MyResult(number1, number2);
}
public static void main(String[] args) {
MyResult result = something();
System.out.println(result.getFirst() + result.getSecond());
}
Java does not support multi-value returns. Return an array of values.
// Function code
public static int[] something(){
int number1 = 1;
int number2 = 2;
return new int[] {number1, number2};
}
// Main class code
public static void main(String[] args) {
int result[] = something();
System.out.println(result[0] + result[1]);
}
You could implement a generic Pair if you are sure that you just need to return two values:
public class Pair<U, V> {
/**
* The first element of this <code>Pair</code>
*/
private U first;
/**
* The second element of this <code>Pair</code>
*/
private V second;
/**
* Constructs a new <code>Pair</code> with the given values.
*
* #param first the first element
* #param second the second element
*/
public Pair(U first, V second) {
this.first = first;
this.second = second;
}
//getter for first and second
and then have the method return that Pair:
public Pair<Object, Object> getSomePair();
You can only return one value in Java, so the neatest way is like this:
return new Pair<Integer>(number1, number2);
Here's an updated version of your code:
public class Scratch
{
// Function code
public static Pair<Integer> something() {
int number1 = 1;
int number2 = 2;
return new Pair<Integer>(number1, number2);
}
// Main class code
public static void main(String[] args) {
Pair<Integer> pair = something();
System.out.println(pair.first() + pair.second());
}
}
class Pair<T> {
private final T m_first;
private final T m_second;
public Pair(T first, T second) {
m_first = first;
m_second = second;
}
public T first() {
return m_first;
}
public T second() {
return m_second;
}
}
Here is the really simple and short solution with SimpleEntry:
AbstractMap.Entry<String, Float> myTwoCents=new AbstractMap.SimpleEntry<>("maximum possible performance reached" , 99.9f);
String question=myTwoCents.getKey();
Float answer=myTwoCents.getValue();
Only uses Java built in functions and it comes with the type safty benefit.
Use a Pair/Tuple type object , you don't even need to create one if u depend on Apache commons-lang. Just use the Pair class.
you have to use collections to return more then one return values
in your case you write your code as
public static List something(){
List<Integer> list = new ArrayList<Integer>();
int number1 = 1;
int number2 = 2;
list.add(number1);
list.add(number2);
return list;
}
// Main class code
public static void main(String[] args) {
something();
List<Integer> numList = something();
}
public class Mulretun
{
public String name;;
public String location;
public String[] getExample()
{
String ar[] = new String[2];
ar[0]="siva";
ar[1]="dallas";
return ar; //returning two values at once
}
public static void main(String[] args)
{
Mulretun m=new Mulretun();
String ar[] =m.getExample();
int i;
for(i=0;i<ar.length;i++)
System.out.println("return values are: " + ar[i]);
}
}
o/p:
return values are: siva
return values are: dallas
I'm curious as to why nobody has come up with the more elegant callback solution. So instead of using a return type you use a handler passed into the method as an argument. The example below has the two contrasting approaches. I know which of the two is more elegant to me. :-)
public class DiceExample {
public interface Pair<T1, T2> {
T1 getLeft();
T2 getRight();
}
private Pair<Integer, Integer> rollDiceWithReturnType() {
double dice1 = (Math.random() * 6);
double dice2 = (Math.random() * 6);
return new Pair<Integer, Integer>() {
#Override
public Integer getLeft() {
return (int) Math.ceil(dice1);
}
#Override
public Integer getRight() {
return (int) Math.ceil(dice2);
}
};
}
#FunctionalInterface
public interface ResultHandler {
void handleDice(int ceil, int ceil2);
}
private void rollDiceWithResultHandler(ResultHandler resultHandler) {
double dice1 = (Math.random() * 6);
double dice2 = (Math.random() * 6);
resultHandler.handleDice((int) Math.ceil(dice1), (int) Math.ceil(dice2));
}
public static void main(String[] args) {
DiceExample object = new DiceExample();
Pair<Integer, Integer> result = object.rollDiceWithReturnType();
System.out.println("Dice 1: " + result.getLeft());
System.out.println("Dice 2: " + result.getRight());
object.rollDiceWithResultHandler((dice1, dice2) -> {
System.out.println("Dice 1: " + dice1);
System.out.println("Dice 2: " + dice2);
});
}
}
You don't need to create your own class to return two different values. Just use a HashMap like this:
private HashMap<Toy, GameLevel> getToyAndLevelOfSpatial(Spatial spatial)
{
Toy toyWithSpatial = firstValue;
GameLevel levelToyFound = secondValue;
HashMap<Toy,GameLevel> hm=new HashMap<>();
hm.put(toyWithSpatial, levelToyFound);
return hm;
}
private void findStuff()
{
HashMap<Toy, GameLevel> hm = getToyAndLevelOfSpatial(spatial);
Toy firstValue = hm.keySet().iterator().next();
GameLevel secondValue = hm.get(firstValue);
}
You even have the benefit of type safety.
Return an Array Of Objects
private static Object[] f ()
{
double x =1.0;
int y= 2 ;
return new Object[]{Double.valueOf(x),Integer.valueOf(y)};
}
In my opinion the best is to create a new class which constructor is the function you need, e.g.:
public class pairReturn{
//name your parameters:
public int sth1;
public double sth2;
public pairReturn(int param){
//place the code of your function, e.g.:
sth1=param*5;
sth2=param*10;
}
}
Then simply use the constructor as you would use the function:
pairReturn pR = new pairReturn(15);
and you can use pR.sth1, pR.sth2 as "2 results of the function"
You also can send in mutable objects as parameters, if you use methods to modify them then they will be modified when you return from the function. It won't work on stuff like Float, since it is immutable.
public class HelloWorld{
public static void main(String []args){
HelloWorld world = new HelloWorld();
world.run();
}
private class Dog
{
private String name;
public void setName(String s)
{
name = s;
}
public String getName() { return name;}
public Dog(String name)
{
setName(name);
}
}
public void run()
{
Dog newDog = new Dog("John");
nameThatDog(newDog);
System.out.println(newDog.getName());
}
public void nameThatDog(Dog dog)
{
dog.setName("Rutger");
}
}
The result is:
Rutger
You can create a record (available since Java 14) to return the values with type safety, naming and brevity.
public record MyResult(int number1, int number2) {
}
public static MyResult something() {
int number1 = 1;
int number2 = 2;
return new MyResult(number1, number2);
}
public static void main(String[] args) {
MyResult result = something();
System.out.println(result.number1() + result.number2());
}
First, it would be better if Java had tuples for returning multiple values.
Second, code the simplest possible Pair class, or use an array.
But, if you do need to return a pair, consider what concept it represents (starting with its field names, then class name) - and whether it plays a larger role than you thought, and if it would help your overall design to have an explicit abstraction for it. Maybe it's a code hint...
Please Note: I'm not dogmatically saying it will help, but just to look, to see if it does... or if it does not.

Categories