I was looking for some good patterns to have possibility to express distance in different units. I found Martin Fowler article about quantities and I programmed something like:
Here is Distance class ( I think it is not necessery to make it abstract ):
public class Distance {
double mValue;
DistanceUnit mUnit;
public Distance(double value, DistanceUnit unit){
this.mValue = value;
this.mUnit = unit;
}
public Distance toUnit(DistanceUnit unit){
double factor = this.mUnit.getMetresFactor()/unit.getMetresFactor();
double newValue = this.mValue * factor;
Distance distance = new Distance(newValue, unit);
return distance;
}
#Override
public String toString(){
return String.valueOf(mValue);
}
}
It looks very simple. Conversion toUnit is based on DistanceUnit method getMetresFactor. Each Unit class implements DistanceUnit interface and has method getMetresFactor() like:
public interface DistanceUnit {
double getMetresFactor();
}
public class Inch implements DistanceUnit {
#Override
public double getMetresFactor() {
return 0.0254;
}
}
public class Kilometer implements DistanceUnit {
#Override
public double getMetresFactor() {
return 1000.0;
}
}
And the usage is for example:
Distance inches = new Distance(300.0, new Inch());
Distance kilometres = inches.toUnit(new Kilometres());
So it returns the correct value.
Is it good way to store distance in this way? Maybe you know some weaknesses of this approach. Maybe is a good idea to use here a FactoryMethod pattern to construct distance based on unit shortcut like "m" for meter. I think about the amount of classes if I would have a lot of units... Is it good idea to have factory which return factor of meters based on unit name? There will be no classes for units then?
Hm, i would use enum instead of DistanceUnit classes, because there is no different instances of them.
You can set a value to enum like here
and then call enum.getValue() instead of unit.getMetresFactor().
Also it is a little bit confusing, is the mValue value in meters or in DistanceUnit's, if in meters, you must have
double factor = unit.getMetresFactor();
there
Ok and now with any convertion function support:
import java.util.HashMap;
import java.util.Map;
public abstract class MeasureConverter {
public abstract double valueToBasic(double value);
public abstract double basictoValue(double basic);
/**
*
*/
public static Map<String, MeasureConverter> converters;
public static Map<String, MeasureConverter> getConverters() {
if (converters == null) {
converters = new HashMap<String, MeasureConverter>();
converters.put("kilo", new MeasureConverter() {
#Override
public double valueToBasic(double value) {
return value * 1000;
}
#Override
public double basictoValue(double basic) {
return basic / 0.001;
}
});
// taking the basic temperature value in kelvines
converters.put("kelvine", new MeasureConverter() {
#Override
public double valueToBasic(double value) {
return value;
}
#Override
public double basictoValue(double basic) {
return basic;
}
});
converters.put("celsius", new MeasureConverter() {
#Override
public double valueToBasic(double value) {
return value + 273.15;
}
#Override
public double basictoValue(double basic) {
return basic - 273.15;
}
});
converters.put("faren", new MeasureConverter() {
#Override
public double valueToBasic(double value) {
return value * 1.8 - 459.67 ; // or whatever is there?
}
#Override
public double basictoValue(double basic) {
return (basic + 459.67 ) / 1.8;// or whatever is there?
}
});
}
return converters;
}
}
And then :
import java.util.Objects;
public class MeasurePattern {
double value;
String name;
public MeasurePattern(double value, String name) {
this.value = value;
this.name = name;
}
#Override
public String toString() {
return "MeasurePattern{" + "value=" + value + ", name=" + name + '}';
}
#Override
public int hashCode() {
int hash = 7;
hash = 29 * hash + (int) (Double.doubleToLongBits(this.value) ^ (Double.doubleToLongBits(this.value) >>> 32));
hash = 29 * hash + Objects.hashCode(this.name);
return hash;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final MeasurePattern other = (MeasurePattern) obj;
if (Double.doubleToLongBits(this.value) != Double.doubleToLongBits(other.value)) {
return false;
}
if (!Objects.equals(this.name, other.name)) {
return false;
}
return true;
}
public MeasurePattern convertTo(String converter) {
MeasureConverter mycon = MeasureConverter.getConverters().get(name);
MeasureConverter hiscon = MeasureConverter.getConverters().get(converter);
double basic = mycon.valueToBasic(value);
double hisValue = hiscon.basictoValue(basic);
return new MeasurePattern(hisValue, converter);
}
public static void main(String[] args) {
//trying temperatures;
MeasurePattern temp = new MeasurePattern(10, "celsius");
MeasurePattern kelvine = temp.convertTo("kelvine");
MeasurePattern faren = kelvine.convertTo("faren");
MeasurePattern cels = faren.convertTo("celsius");
System.out.println("kelvine = " + kelvine);
System.out.println("faren = " + faren);
System.out.println("cels = " + cels);
}
}
Output:
kelvine = MeasurePattern{value=283.15, name=kelvine}
faren = MeasurePattern{value=412.67777777777775, name=faren}
cels = MeasurePattern{value=9.999999999999943, name=celsius}
You can implement it analog to java.util.concurrent.TimeUnit as an enum. E.g.
public enum DistanceUnit {
KILOMETER {
#Override
protected double conversionFactor(DistanceUnit toDistanceUnit) {
switch (toDistanceUnit) {
case KILOMETER:
return 1;
case MILE:
return 0.621371;
default:
throw new UnsupportedOperationException(toDistanceUnit + " is not supported");
}
}
},
MILE {
#Override
protected double conversionFactor(DistanceUnit toDistanceUnit) {
switch (toDistanceUnit) {
case KILOMETER:
return 1.60934;
case MILE:
return 1;
default:
throw new UnsupportedOperationException(toDistanceUnit + " is not supported");
}
}
};
public double toDistance(double value, DistanceUnit targetDistance) {
return value * conversionFactor(targetDistance);
}
protected abstract double conversionFactor(DistanceUnit toDistanceUnit);
}
change your Distance class to
public class Distance {
double mValue;
DistanceUnit mUnit;
public Distance(double value, DistanceUnit unit){
this.mValue = value;
this.mUnit = unit;
}
public Distance toUnit(DistanceUnit unit){
double newValue = mUnit.toDistance(mValue, unit);
Distance distance = new Distance(newValue, unit);
return distance;
}
#Override
public String toString(){
return String.valueOf(mValue);
}
}
and the client code will look very clear
public class Main {
public static void main(String[] args) {
Distance kilometers = new Distance(265.35, DistanceUnit.KILOMETER);
Distance miles = kilometers.toUnit(DistanceUnit.MILE);
System.out.println(miles);
}
}
will output
164.88079485000003
Java convention does not use a m(ember) prefix (but say a this. qualification), and convention is taken quite seriously in java (as opposed to C++ for instance).
toString misses the unit.
JScience offers more, the capability to calculate in different units, m/s², and so on. Your class is a nice abstraction. But in a wider context, you probably will want to have math operations, powers of units (-2 for s above).
Take a look at your own usage ideas first:
(Just garbage:)
U speedUnit = U.of(Distance::km, Time::h.up(-1));
double timeInS = U.mile(40).div(speedunit(30)).in(U.m);
I think you should use the "Strategy" pattern.
An interface:
public interface DistanceUnit {
double getDistance(int metres);
}
The Inch class:
public class Inch implements DistanceUnit {
#Override
public double getDistance(int metres) {
return meters*39; //do conversion here
}
}
The Kilometers class:
public class Kilometres implements DistanceUnit {
#Override
public double getDistance(int metres) {
return meters/1000; //do conversion here
}
}
Then:
List<DistanceUnit> distanceList = new ArrayList<>();
distanceList.add(new Inch());
distanceList.add(new Kilometres());
for (DistanceUnit item : distanceList) {
System.out.println(item.getDistance(1000));
}
If I understand you, I think it is a simple and clean solution.
You can follow this model for conversion between others units.
Related
I wrote my own AtomicDouble class and I also have a BankAccount class that does two simple withdrawals and deposits operations and it has an AtomicDouble instance(balance). The problem with my code is that when I call the addAndGet method in deposit(), the program falls into an infinite loop, and compareAndSet() never returns the true value, but when I debugged this, currentValue and the value from atomic.get () were equal, but this method does not understand.
The interesting thing is that when I put if (atomic.get()==currentValue) instead of if (atomic.compareAndSet(currentValue, nextValue)), the program runs properly.
public class AtomicDouble extends Number {
private final AtomicReference<Double> atomic;
public AtomicDouble() {
this(0.0);
}
public AtomicDouble(double initialValue) {
atomic = new AtomicReference<>(initialValue);
}
public final double addAndGet(double delta) {
while (true) {
double currentValue = atomic.get();
double nextValue = currentValue + delta;
if (atomic.compareAndSet(currentValue, nextValue))
return nextValue;
}
}
public final double incrementAndGet() {
return addAndGet(1);
}
public final void set(double newValue) {
atomic.set(newValue);
}
public final double get() {
return atomic.get();
}
public final double getAndSet(double newValue) {
return atomic.getAndSet(newValue);
}
public float floatValue() {
return (float) get();
}
#Override
public double doubleValue() {
return get();
}
public int intValue() {
return (int) get();
}
public long longValue() {
return (long) get();
}
public String toString() {
return Double.toString(get());
}
}
public class BankAccount {
private final AtomicDouble balance;
private String accountNumber;
public BankAccount(double balance, String accountNumber) {
this.balance = new AtomicDouble(balance);
this.accountNumber = accountNumber;
}
public void deposit(double number, String color) {
System.out.println(color + "deposit " + number + " current balance=" + balance.addAndGet(number));
}
public void withdraw(double number, String color) {
if (this.balance.get() - number >= 0) {
System.out.println(color + "Withdraw " + number + " current balance=" + balance.addAndGet(-number));
return;
}
System.out.println(color + "Not enough balance");
}
public static void main(String[] args) {
BankAccount bankAccount = new BankAccount(1000.0, "4234236");
ExecutorService threadsPool = Executors.newFixedThreadPool(2);
threadsPool.execute(new Runnable() {
#Override
public void run() {
bankAccount.deposit(300.0, ThreadColor.ANSI_YELLOW);
bankAccount.withdraw(50.0, ThreadColor.ANSI_YELLOW);
}
});
threadsPool.execute(new Runnable() {
#Override
public void run() {
bankAccount.deposit(203.75, ThreadColor.ANSI_BLUE);
bankAccount.withdraw(100.0, ThreadColor.ANSI_BLUE);
}
});
threadsPool.shutdown();
}
}
output: There is no output
I would suppose it is because of autoboxing. You can't have a reference to double, you have a reference to Double.
The operands get "reboxed" each time around the loop and therefore references are never identical. That is, the reference in currentValue is never the same as the reference in atomic.
Try using currentValue reference types.
public final double addAndGet(double delta) {
while (true) {
Double currentValue = atomic.get();
Double nextValue = currentValue + delta;
if (atomic.compareAndSet(currentValue, nextValue))
return nextValue;
}
}
(Fortunately, Double is an immutable type, otherwise this would have a race hazard)
How to make for example list of Plane per each different airport?
I would like to create in this example the airport and when its this particular object(airport) , I would like to add a plane to collection of this airport.
How to make for example list of Plane per each diffrent airport?
I would like to create in this example the airport and when its this particual object(airport) i would like to add a plane to collection of this airport.
For example:
public class Airport {
private Plane plane;
Queue<Plane> queueOfPlanes = new ArrayDeque<Plane>();
public Airport(Plane plane) {
this.plane = plane;
queueOfPlanes.add(plane);
}
I am creating an airport, and when I have this specific airport I would like to gather the plane in the Queue for this one airport.
You start by having a different interface for your Airport.
Like:
private Plane plane; ...
public Airport(Plane plane) {
That is already wrong. An Airport doesn't need a specific single plane to be an airport.
Rather go:
class Airport {
private final List<Plane> currentPlanes = new ArrayList<>();
private final String name;
public Airport(String name) {
this.name = name;
}
public void addPlane(Plane plane) { currentPlanes.add(plane); }
public void removePlane(Plane plane) { currentPlanes.remove(plane); }
The idea here: an Airport has specific properties that don't change (like its name, location, ...). But the planes come and go. So your airport objects need a way to store which planes are currently associated to it.
There are many ways to do it but I think HashMaps are the best for your scenario, Let's see an example.
HashMap<String, ArrayList<Plane>> mAirPorts = new HashMap<String, ArrayList<Plane>>();
Now you need to create Object Plane
public class Plane
{
private double maxWeight;
private double emptyWeight;
private double loadWeight;
private double travelSpeed;
private double flyHours;
private double consumption;
private double maxFuel;
private double kerosinStorage;
public Plane( double maxWeight, double emptyWeight, double loadWeight,
double travelSpeed, double flyHours, double consumption,
double maxFuel, double kerosinStorage )
{
this.maxWeight = maxWeight;
this.emptyWeight = emptyWeight;
this.loadWeight = loadWeight;
this.travelSpeed = travelSpeed;
this.flyHours = flyHours;
this.consumption = consumption;
this.maxFuel = maxFuel;
this.kerosinStorage = kerosinStorage < this.maxFuel
? kerosinStorage
: this.maxFuel;
}
public double getMaxWeight()
{
return maxWeight;
}
public double getEmptyWeight()
{
return emptyWeight;
}
public double getLoadWeight()
{
return loadWeight;
}
public double getTravelSpeed()
{
return travelSpeed;
}
public double getFlyHours()
{
return flyHours;
}
public double getConsumption()
{
return consumption;
}
public double getMaxFuel()
{
return maxFuel;
}
public double getKerosinStorage()
{
return kerosinStorage;
}
public void setMaxWeight(double maxWeight)
{
this.maxWeight = maxWeight;
}
public void setEmptyWeight(double emptyWeight)
{
this.emptyWeight = emptyWeight;
}
public void setLoadWeight(double loadWeight)
{
this.loadWeight = loadWeight;
}
public void setTravelSpeed(double travelSpeed)
{
this.travelSpeed = travelSpeed;
}
public void setFlyHours(double flyHours)
{
this.flyHours = flyHours;
}
public void setConsumption(double consumption)
{
this.consumption = consumption;
}
public void setMaxFuel(double maxFuel)
{
this.maxFuel = maxFuel;
}
public void setKerosinStorage(double kerosinStorage)
{
this.kerosinStorage = this.kerosinStorage + kerosinStorage > maxFuel
? maxFuel : this.kerosinStorage + kerosinStorage;
}
/*
Returns the total weight of the plane. Which is: emptyWeight +
weight of load + weight of kerosin.
Expect 1 liter Kerosin as 0.8 kg.
*/
public double getTotalWeight ()
{
return emptyWeight + loadWeight
+ (kerosinStorage * 0.8);
}
/*
How far can the plane fly with the current kerosin storage?
*/
public double getMaxReach ()
{
return (kerosinStorage / consumption) * travelSpeed;
}
/*
Prevent flying further then possible (with the current kerosin) !
*/
public boolean fly (double km)
{
if (km <= 0 || getMaxReach() < km || getTotalWeight() > maxWeight)
{
return false;
}
flyHours += (km / travelSpeed);
kerosinStorage -= (km / travelSpeed) * consumption;
return true;
}
/*
! The parameter 'liter' can be a negative number.
Doesn't have to be overfilled.
Prevent a negative number as value of the 'kerosinStorage' property !
*/
public void fillUp (double liter)
{
if ((kerosinStorage + liter) > maxFuel)
{
kerosinStorage = maxFuel;
}
else if ((kerosinStorage + liter) < 0)
{
kerosinStorage = 0;
}
else
{
kerosinStorage += liter;
}
}
/*
Prevent illogical value-assignments !
*/
public boolean load (double kg)
{
if ((loadWeight + emptyWeight + kg) > maxWeight)
{
return false;
}
else if ((emptyWeight + kg) < 0)
{
loadWeight = 0;
return true;
}
else
{
loadWeight += kg;
return true;
}
}
// Display flying hours, kerosin storage & total weight on t. terminal.
public void info ()
{
System.out.println("Flying hours: " + flyHours + ", Kerosin: "
+ kerosinStorage + ", Weight: " + getTotalWeight());
}
}
Now simply add objects to your HashMap like:
mAirPorts.put("airport_key", ArrayListContainingPlanes);
You can now get planes by your airport key like:
ArrayList<Plane> mPlanes = mAirPorts.get("airport_key");
if (mPlanes != null) {
...
} else {
//No such airport
}
After researching a little bit, I couldn't figure out how to create a obj1 distance to be able to compare with obj2. All these methods were given in assessment I had so, no chance to change logic of it. I suppose to return 3 Strings answer depending of the data. Thanks a lot in advance guys. I've attached a pease of pic.
enter image description here
public class Main {
public static void main(String[] args) {
Distance dist1 = new DistanceImplementation();
Distance obj2 = new DistanceImplementation();
dist1.setFeetAndInches(1, 8);
obj2.setFeetAndInches(3, 5);
System.out.println(dist1.getDistanceComparison(obj2));
}
}
public abstract class Distance {
protected int feet;
protected float inches;
abstract public void setFeetAndInches(int feet, float inches);
abstract public int getFeet();
abstract public float getInches();
abstract String getDistanceComparison(Distance dist2);
}
class DistanceImplementation extends Distance {
#Override
public void setFeetAndInches(int feet, float inches) {
this.feet = feet;
this.inches = inches;
}
#Override
public int getFeet() {
return this.feet;
}
#Override
public float getInches() {
return this.inches;
}
#Override
String getDistanceComparison(Distance dist2) {
// if (dist2) { ????????????
return null;
}
}
Well, after reading the assessment, I think that you can safely assume that 1 foot = 12 inches. So, in order to correctly implement the getDistanceComparison method, you could calculate the total distance in inches for both the current object and the parameter, compare them and then return the corresponding string value.
Suppose you have the following method:
private float getTotalInches() {
return (float) feet * 12.0 + inches;
}
This method returns the total inches of this DistanceImplementation instance, taking into account the feet and the inches attributes.
Please note that for the total result to be of type float, we need to first cast the feet attribute to float, so that it actually becomes of type float. Then, we multiply by 12.0 (note the .0, it's important because it indicates that the 12.0 literal value is also a float). Then, we are summing two float values, which yields a result of type float. While all this casting and convertions are not always necessary (sometimes the compiler is smart enough as to guess the correct types and preserve decimal precision), it's considred good practice to make your intentions crystal-clear, so that future developers that will maintain your code know what you have tried to accomplish.
Then, once you have this method, it would be easy to compare the total inches of both DistanceImplementation instances and return the corresponding string:
#Override
String getDistanceComparison(Distance dist2) {
float myTotalInches = getTotalInches();
float otherTotalInches = dist2.getTotalInches();
if (myTotalInches > otherTotalInches) {
// return ...
} else if (myTotalInches < otherTotalInches) {
// return ...
} else {
// return ...
}
}
Here is the solution on which I was working and it might be useful as well
package com.prog;
import java.util.Scanner;
abstract class Distance {
protected int feet;
protected float inches;
abstract public void setFeetAndInches(int feet, float inches);
abstract public int getFeet();
abstract public float getInches();
abstract String getDistanceComparison(Distance dist2);
}
public class DistanceCalculator {
private static final Scanner scan = new Scanner(System.in);
public static void main(String[] args) {
Distance dist1 = new DistanceImplementation();
Distance dist2 = new DistanceImplementation();
int feet1 = 1;
float inches1 = (float) 2.0;
int feet2 = 3;
float inches2 = (float) 4.1;
dist1.setFeetAndInches(feet1, inches1);
dist2.setFeetAndInches(feet2, inches2);
System.out.println(dist1.getDistanceComparison(dist2));
}
}
package com.prog;
public class DistanceImplementation extends Distance {
#Override
public void setFeetAndInches(int feet, float inches) {
this.feet=(int) (feet+ (inches/12));
this.inches=inches+ (feet*12);
}
#Override
public int getFeet() {
return feet;
}
#Override
public float getInches() {
return inches;
}
#Override
String getDistanceComparison(Distance dist2) {
String ret;
int dist1a=this.getFeet();
System.out.println(dist1a);
int dist2a=dist2.getFeet();
if(dist1a > dist2a)
return "First is greater";
else if(dist1a < dist2a)
return "Second is greater";
else
return "Both are equal";
}
}
I'm working on a homework assignment, and I'm having a really hard time wrapping my head around how to compare two of the same subclass objects.
Basically I have this superclass Magnitude:
class Magnitude {
public boolean lessThan(Magnitude m) {
}
public boolean lessThanEqualTo(Magnitude m) {
}
public boolean equalTo(Magnitude m) {
}
public boolean greaterThan(Magnitude m) {
}
public boolean notEqual(Magnitude m) {
}
}
And then I have a subclass Currency that extends Magnitude ( I am only allowed to override the lessThan() method):
class Currency extends Magnitude {
double amount;
public Currency(double amt) {
this.amount = amt;
}
#Override
public boolean lessThan(Magnitude m) {
Currency other_currency = (Currency) m;
if (this.amount < other_currency.amount) {
return true;
}
else {
return false
}
}
public void print() {
System.out.println(amount);
}
}
What exactly is the way that I should implement these methods for the super and subclass so that I can compare 2 objects of the same subclass?
You can make use of the fact that you can call lessThan() also from m and use this as the other argument.
abstract class Magnitude {
public abstract boolean lessThan(Magnitude m);
public boolean lessThanEqualTo(Magnitude m) {
return this.lessThan(m) || this.equalTo(m);
}
public boolean equalTo(Magnitude m) {
return ((!this.lessThan(m))&&(!m.lessThan(this)));
}
public boolean greaterThan(Magnitude m) {
return m.lessThen(this);
}
public boolean notEqual(Magnitude m) {
return !this.equal(m);
}
}
You then need to have
class Currency extends Magnitude {
double amount;
public Currency(double amt) {
this.amount = amt;
}
#Override
public boolean lessThan(Magnitude m) {
Currency other_currency = (Currency) m;
if (this.amount < other_currency.amount) {
return true;
}
else {
return false
}
}
public void print() {
System.out.println(amount);
}
}
Simply rewrite the methods at the subclass.
Now, if you create two instances of the subclass and compare them, it'll use the subclass method
Currency c1 = new Currency();
Currency c2 = new Currency();
c1.lessThan(c2); //will call Currency.lessThan method
To use parent's class method, use this way
c1.lessThan((Magnitude) c2);
See this form more info.
If I understand your question correctly, you want to know how to implement and override the lessThan() method in your Currency class, knowing you can only compare currencies but not magnitudes, but what you receive is a Magnitude type parameter.
In that case, you need to check if the Magnitude object you received as a paramether is actually an instance of Currency wrapped in a Magnitude class. To do that, you use the instanceof comparison operator and then cast the object to Currency:
#Override
public boolean lessThan(Magnitude m) {
if(m instanceof Currency) {
return this.amount < ((Currency)m).amount;
} else {
throw new IllegalArgumentException("Parameter is not a Currency");
}
}
I'm developing a graphical user interface in Java and relying on the standard MVC design pattern in which I have a View which should provide an up-to-date representation of the state of the Model.
I have an ObserverTextField class within the View which subclasses JTextField and registers itself as an observer of part of the Model. When this part of the Model changes, it calls this observer's notify method, passing the integer value. The class then sets its displayed text to the user.
However, I would like to be able to control the representation of the number at run-time. I could pass a NumberFormat to the class, but that doesn't seem able to represent the value as, say, 1/1000th of its actual value.
E.g. if the model stores the value of a current in milliamps, and I want it shown to the user in terms of amps, is there some kind of object I could construct and pass to the ObserverTextField to let it do that?
Below is an example of the code using an instance of NumberFormat, which I would like to replace with something more powerful:
public class ObserverTextField extends JTextField implements Observer {
private static final long serialVersionUID = 1L;
private NumberFormat formatter;
#Override
public void notify(Object value) {
if(formatter == null) {
setText(String.valueOf(value));
} else {
setText(formatter.format((int)value));
}
}
public NumberFormat getFormat() {
return formatter;
}
public void setFormat(NumberFormat formatter) {
this.formatter = formatter;
}
}
If there isn't such a thing, I could create my own, but I'd prefer to make sure something like that doesn't already exist in Java's standard library first.
Your Observer can have a utility function that will Format your value as so:
private static DecimalFormat df = new DecimalFormat("#.000");
public static String getFormattedValue(double value, double factor) {
return df.format(value * factor);
}
Here is an example in main
public static void main(String[] args) throws Exception {
double value = 3560;
System.out.println(value + " milliamps");
//Milliamps to centiamps is a factor of .1
System.out.println(getFormattedValue(value, .1) + " centiamps");
//Milliamps to deciamps is a facotr of .01
System.out.println(getFormattedValue(value, .01) + " deciamps");
//Milliamps to amps is a factor of .001
System.out.println(getFormattedValue(value, .001) + " amps");
}
The output:
3560.0 milliamps
356.000 centiamps
35.600 deciamps
3.560 amps
Java 8 promises a nice solution:
textField.setFormat((n) -> (n.intValue() / 1000) + " mA");
private Function<Number, String> formatter = (n) -> n + " A";
#Override
public void notify(Object value) {
setText(formatter.apply((Number)value));
}
public void setFormat(Function<Number, String> formatter) {
this.formatter = formatter;
}
Judging from the answers, there doesn't seem to be an in-built method in Java for performing arbitrary conversions on numbers, so I put together a simple but usable custom implementation. I created a utility class MathSequence:
import java.util.LinkedList;
import java.util.List;
public class MathSequence {
private interface MathOperation {
double operate(double value);
}
private class AddOperation implements MathOperation {
private double operand;
public AddOperation(double operand) {
this.operand = operand;
}
public double operate(double value) {
return value + operand;
}
}
private class SubtractOperation implements MathOperation {
private double operand;
public SubtractOperation(double operand) {
this.operand = operand;
}
public double operate(double value) {
return value - operand;
}
}
private class MultiplyOperation implements MathOperation {
private double operand;
public MultiplyOperation(double operand) {
this.operand = operand;
}
public double operate(double value) {
return value * operand;
}
}
private class DivideOperation implements MathOperation {
private double operand;
public DivideOperation(double operand) {
this.operand = operand;
}
public double operate(double value) {
return value / operand;
}
}
private List<MathOperation> operations;
public MathSequence() {
operations = new LinkedList<MathOperation>();
}
public void appendAddOperation(double operand) {
operations.add(new AddOperation(operand));
}
public void appendSubtractOperation(double operand) {
operations.add(new SubtractOperation(operand));
}
public void appendMultiplyOperation(double operand) {
operations.add(new MultiplyOperation(operand));
}
public void appendDivideOperation(double operand) {
operations.add(new DivideOperation(operand));
}
public void clearOperations() {
operations.clear();
}
public double process(double value) {
for(MathOperation operation : operations) {
value = operation.operate(value);
}
return value;
}
}
Then I changed my ObserverTextField class:
public class ObserverTextField extends JTextField implements Observer {
private static final long serialVersionUID = 1L;
private NumberFormat formatter;
private MathSequence sequence;
public ObserverTextField() {
formatter = new DecimalFormat("");
sequence = new MathSequence();
}
#Override
public void notify(Object value) {
int integerValue = (int)value;
setText(formatter.format(sequence.process(integerValue)));
}
public NumberFormat getFormat() {
return formatter;
}
public void setFormat(NumberFormat formatter) {
this.formatter = formatter;
}
public MathSequence getSequence() {
return sequence;
}
public void setSequence(MathSequence sequence) {
this.sequence = sequence;
}
}
I can then write code like the following:
MathSequence sequence = new MathSequence();
sequence.appendDivideOperation(1000);
NumberFormat formatter = new DecimalFormat("0.000");
ObserverTextField actuatorCurrentTextField;
actuatorCurrentTextField = new ObserverTextField();
actuatorCurrentTextField.setSequence(sequence);
actuatorCurrentTextField.setFormat(formatter);
This will display the representation as I like it. Because of this approach, I don't hardcode the representation of values within the ObserverTextField classes themselves, and so I'm free to vary the representation at run-time and re-use code pretty easily. This is why I couldn't accept suggestions along the lines of "why not just do (int)value/1000?".
I'll accept one of the other answers even though I'll likely stick with this one for the time being, since they're pretty informative.