Say, for example, I have a double variable in Java:
double alpha = 3;
However, I wanted to create a String variable, including that Double Variable:
String beta = "Alpha has a value of " + alpha;
So that the output would be
//Output
Alpha has the value of 3
However, it will not let me do so, as it says the double value cannot be included in the string value.
As I am doing this for around 150 variables, I want to know how to do it the simplest and shortest way.
Thanks
I am doing this for around 150 variables
A common way of simplifying a repeated task is defining a helper method for it:
String description(String name, Object obj) {
return name + " has a value of " + obj;
}
Now you can use it like this:
String beta = description("Alpha", alpha);
Doing this for 150 variables sounds suspicious - chances are, you have an opportunity to make an array. You can define an array of names, then pair them up with values, like this:
String[] names = new String[] {
"Alpha", "Beta", "Gamma", ...
}
double[] values = new double[] {
1.2, 3.4, 5.6, ...
}
for (int i = 0 ; i != names.length() ; i++) {
System.out.println(description(names[i], values[i]));
}
You can use Double.toString(double).
String beta = "Alpha has a value of " + Double.toString(alpha);
When you need to convert a double to a string, use
Double.toString(double);
Where double is the name of the variable.
Related
I'm making a program that find sums multiple values that are in a single string. For example you put H2O in and it will return the molar mass value for that chemical (2*H + O). So I copied the periodic table and listed the values e.g "private double H = 1.008;". So the problem is I need to get that value based on the name of the variable. Here is an example.
private double H = 1.008;
System.out.println(multMass(2, H));
// should print 2.016
public static double multMass(int multiplier, String chem){
return double(chem) * multiplier;
} /\
||
where the double would go(in this case 'double H')
Don't use raw variables for this. Use a Map instead:
Map<String, Double> elemWeights = new HashMap<>();
// Associate an element symbol and a weight
// This would be your "double H = 1.008"
elemWeights.put("H", 1.008);
elemWeights.put("Li", 6.94);
...
public static double multMass(int multiplier, String chem) {
double weight = elemWeights.get(chem); // And do a lookup
return weight * multiplier;
}
Or, a little neater:
Map<String, Double> elemWeights = Map.ofEntries(
entry("H", 1.008),
entry("Li", 6.94)
...
);
Or see here for other ways this can be written based on the version of Java that you're using.
I have an Item[] items which contains some basic stats about itself.
public float getAttackDamage() {
float bonus = 0;
for(int i = 0 ; i < items.length; i++){
if(items[i] != null){
bonus += items[i].getAttackDamage();
}
}
return baseAttackDamage + attackDamageScaling * level + bonus;
}
The above code is how I currently loop through my characters items and apply their getAttackDamage() to the return result.
Is there a way I can rewrite this to use a lambda expressions instead? I tried the follow:
public float getAttackDamage() {
float bonus = 0;
Arrays.stream(items).forEach(i -> bonus += i.getAttackDamage());
return baseAttackDamage + attackDamageScaling * level + bonus;
}
But it didn't work (compiler error).
Is this possible?
Yes, you could have the following:
double bonus = Arrays.stream(items)
.filter(Objects::nonNull)
.mapToDouble(Item::getAttackDamage)
.sum();
You should remember that forEach is probably not the method you want to call. It breaks functional programming (refer to Brian Goetz's comment). In this code, a Stream of each of your item is created. The non-null elements are filtered and mapped to a double value corresponding to the attack damage.
I wrote some code to understand what would happen if I store a mixture of primitives, objects mutable or immutable into an Array object. Could I amend them after storage and see if it Dereferenced these things correctly and returned their amended values. I did not get what I had expected my code to do ? I think I know why and would like to clarify whether this understanding is correct. Here is the code.
public class DriverApp3 {
private static String CYEAR = "2014" ;
private static StringBuffer CYEARFLG = new StringBuffer("1914") ;
public double money = 2.13 ;
public static void main(String args[])
{
Integer j = 12 ;
DriverApp3 d = new DriverApp3();
StringBuffer sb = new StringBuffer("Unicorn");
MutableInteger mi = new MutableInteger(67);
int i = 76 ;
Object[] parseXML = new Object[]{j,DriverApp3.CYEAR,d, d.money,DriverApp3.CYEAR, sb, mi, DriverApp3.CYEARFLG,i};
// 0 1 2 3 4 5 6 7 8
System.out.println("======chng of all original values ==========");
j = 13 ;
d.money = 3.14 ;
parseXML[4]="2015";
DriverApp3.CYEAR = "2013";
mi.set(9);
sb.replace(3,5,"KO");
DriverApp3.CYEARFLG.replace(0,4,"1939");
i = 7 ;
Object[] chngdO = new Object[]{j,DriverApp3.CYEAR,d, d.money,DriverApp3.CYEAR, sb, mi, DriverApp3.CYEARFLG,i};
int cnt = 0 ;
for (Object m : parseXML)
{
Integer s_objid = m.hashCode();
String clsType = "Type="+m.getClass().getTypeName();
String clsName = "SimplName="+m.getClass().getSimpleName();
String canName = "CanonName="+m.getClass().getCanonicalName();
Object n = chngdO[cnt];
Integer ns_objid = n.hashCode();
String nclsType = "Type="+n.getClass().getTypeName();
String nclsName = "SimplName="+n.getClass().getSimpleName();
String ncanName = "CanonName="+n.getClass().getCanonicalName();
System.out.println(cnt + ": Hashcode=" + s_objid + ":" + clsType + ":" + m + "\n " + ": Hashcode=" + ns_objid + ":" + nclsType /*+ ":"+ clsName+ ":"+ canName*/+ ":" + n + "\n" );
cnt++ ;
}
}
#Override
public String toString()
{
return "Hashcode="+this.hashCode() + "," + DriverApp3.CYEAR ;
}
}
The mutable class is also here .....
/**
*
* #author code snippet from stackoverflow.com
* Not thread safe
*/
public class MutableInteger {
private int value;
public MutableInteger(int value) {
this.value = value;
}
public void set(int value) {
this.value = value;
}
public int intValue() {
return value;
}
public String toString()
{
return "id="+this.hashCode()+" val=" + this.value ;
}
}
The output of my application is .....
======chng of all original values ==========
0: Hashcode=12:Type=java.lang.Integer:12
: Hashcode=13:Type=java.lang.Integer:13
1: Hashcode=1537249:Type=java.lang.String:2014
: Hashcode=1537248:Type=java.lang.String:2013
2: Hashcode=366712642:Type=xander.DirRefOrCopy.DriverApp3:Hashcode=366712642,2013
: Hashcode=366712642:Type=xander.DirRefOrCopy.DriverApp3:Hashcode=366712642,2013
3: Hashcode=815979831:Type=java.lang.Double:2.13
: Hashcode=300063655:Type=java.lang.Double:3.14
4: Hashcode=1537250:Type=java.lang.String:2015
: Hashcode=1537248:Type=java.lang.String:2013
5: Hashcode=1829164700:Type=java.lang.StringBuffer:UniKOrn
: Hashcode=1829164700:Type=java.lang.StringBuffer:UniKOrn
6: Hashcode=2018699554:Type=xander.DirRefOrCopy.MutableInteger:id=2018699554 val=9
: Hashcode=2018699554:Type=xander.DirRefOrCopy.MutableInteger:id=2018699554 val=9
7: Hashcode=1311053135:Type=java.lang.StringBuffer:1939
: Hashcode=1311053135:Type=java.lang.StringBuffer:1939
8: Hashcode=76:Type=java.lang.Integer:76
: Hashcode=7:Type=java.lang.Integer:7
Index 0
For the Integer j, it is immutable, so as soon as I amend it outside the array the 0th one is still pointing to the one with value 12 since it is still alive on wherever Java keeps it's immutable single copy for that Integer. This is apparently an area where all runtime constants for each class or interface is kept. In this case it is the String literal area. The amended j is pointing to a new Immutable single copy of value 13. See Hashcodes differ as well.
Index 1
Same issue like above. Just because it is a member of DriverApp3 you would have expected to have amended itself but it does not because the array has stored an old value of the memory address String in wherever java stores the single copy of that immutable. Since, that address is still "alive" it keeps pointing to that memory address within the array. Very very unintuitive - not sure whether there are other patterns or languages that handle this better. It could be a source of error. Want to make sure you reflect your changes then - use MUTABLE objs within it instead of IMMUTABLE. Or, you have the additional thinking overhead of having to remember that Java might Autobox your primitive (if you were storing a primitive ) into an Object literal depending on whether it is a String, Integer, Double etc.
Index 2
Everything works as expected - it is pointing to the array. So, it continues to point to the same mutable object address when it was changed.
Index 3
Again the double gets Autoboxed into a immutable Double. So, it is the same issue like String and Integer because it is an Object Array. Surely, been like this since Java 1 - btw - I am using Java 8 compiler here.
Index 4
parseXML[4]="2015";
Well here we are directly overwriting the address with the address of the immutable String literal 2015
Index 5 & 6
StringBuffer and MutableInteger reflect amendments correctly because they still point to the same address. Java does not create a new copy because they are meant to mutable by the very nature of they have been defined.
Index 7
Reflects the changes because it is a mutable StringBuffer and not a shared immutable literal !!
Index 8
Suffers from the same issue of a primitive being autoboxed into a immutable shared single copy literal.
So, if you want the contents of your stored Array to reflect your amended changes outside of the array use Mutable Objects. And, beware of the trap of automatic Autoboxing into immutable Object literals.
for (a = 0; a < filename; a++) {
Map<Double,String> m = new HashMap<Double,String>();
String pre = "abc";
String post = ".txt";
for (int ii = 0; ii < 11; ii++) {
m.put(similarityScore[a],pre + a + post + '\n');
}
SortedSet<Double> set = new TreeSet<Double>(m.keySet());
for (Double d : set) {
System.out.println(d + " " + m.get(d));
}
}
Output :
0.5773502691896258 abc0.txt
0.5773502691896258 abc1.txt
0.5773502691896258 abc2.txt
NaN abc3.txt
0.5773502691896258 abc4.txt
NaN abc5.txt
NaN abc6.txt
NaN abc7.txt
NaN abc8.txt
0.5773502691896258 abc9.txt
NaN abc10.txt
This code should be able to sort the double values. But it displays the output on top. What happen ?
The problem is almost certainly NaN.
This is, as the name suggests, not a realy number, and behaves very strangely in terms of comparisons. Is NaN greater than, equal to, or less than 0.5773502691896258? It could be any of those results, and isn't even required to be consistent within a single execution of the program. NaN is not even equal to itself, which says something about how preconceptions of the laws of equality, and strong ordering, go out of the window when NaN is involved.
So the fix is not to use a non-numeric and expect Double.compareTo() to do what you want with it. Depending on what NaN means when returned from similarityScore(), there are several approaches you could take. If it means that it's not a match at all, you could have that method return a Double (rather than a double), return null in these cases, and then only add non-null results to the map. If these results should be displayed anyway, then perhaps you could use a result of 0.0 or -1.0, assuming that's less than any "real" similarity score. If you want something more finessed, then returning something as pure and straightforward as a primitive double is likely going to be the problem, and you may need to return your own (simple) domain class instead.
As an aside - why on earth do you create and populate a HashMap, then use a TreeSet to get the iteration order over the keys? If you simply create m as a TreeMap<Double, String> you get exactly the iteration order you want, so can just iterate overm.entrySet()`. It's clearer, more idiomatic (thus more understandable), and more efficient, so there's no reason not to do this.
for (int ii = 0; ii < 11; ii++) {
m.put(similarityScore[a],pre + a + post + '\n');
}
This puts the same value into the map 11 times - you're not referencing ii inside the loop.
for (Double d : set) {
System.out.println(d + " " + m.get(d));
}
This prints the single entry in the map.
You do the above for values 0..filename - Adding a value to the map several times, then printing it and restarting with a new map.
Map<Double,String> m = new HashMap<Double,String>();
for (a = 0; a < filename; a++) {
String pre = "abc";
String post = ".txt";
m.put(similarityScore[a],pre + a + post + '\n');
}
SortedSet<Double> set = new TreeSet<Double>(m.keySet());
for (Double d : set) {
System.out.println(d + " " + m.get(d));
}
This creates a map, populates it with values for 0..filename, then prints it sorted. You'll still have issues with NaN which isn't really sortable.
Map<Double,String> m = new TreeMap<Double,String>();
for (a = 0; a < filename; a++) {
String pre = "abc";
String post = ".txt";
m.put(similarityScore[a],pre + a + post + '\n');
}
for (Double d : m.keySet()) {
System.out.println(d + " " + m.get(d));
}
And this uses a TreeMap - No need for the intermediate Set
For any Collection to sort, the type of the value on which you are sorting should be same. And should implement comparable interface.
In your case you have NaN and Double values to sort.
Your loop means you're sorting for each filename separately. You'll need to pull the sorting out of the loop to get those values sorted. (Ooops, #Eric beat me to it.)
This is a follow up question from Problem with array assignment
I now have addcube done like so.. and all works as expected, when I print the array. but when I print the same index's AFTER assignment in another class It tells me their equal to 0. So the values are not 'saving'. Why is this? How would I correct this?
public void addcube(float highx, float lowx, float highz, float lowz){
//Constructing new cube...
System.out.println("f = " + f);
Global.cubes++;
float y = 1.5f;
System.out.println("highx = " + highx + "lowx = " + lowx + "highz = " + highz + "lowz = " + lowz);
//FRONT
Global.camObjCoord[Global.i] = highx;
Global.i++;
System.out.println("cube i = " + Global.i);
}
In both cases I'm printing like so...
int p = 0;
while(p < 72){
System.out.println(Global.camObjCoord[p]);
p++;
}
Global.i = 0 at the beginning.
The only other places the array is being referenced is the following..
cubeBuff = makeFloatBuffer(Global.camObjCoord);
FloatBuffer makeFloatBuffer(float[] arr) {
ByteBuffer bb = ByteBuffer.allocateDirect(arr.length*4);
bb.order(ByteOrder.nativeOrder());
FloatBuffer fb = bb.asFloatBuffer();
fb.put(arr);
fb.position(0);
return fb;
}
There is no further refrences to the array in my code.
Thanks.
I would seriously question your design. You're always refering to that Global class, which apparantly seems to be changed from everywhere, and hence you run into such problems (for instance previously with your NullPointerException).
Try seperate things clearly using encapsulation and do not just use one global state that is operated on by different classes. If classes strictly operate only on their own members then dependencies are reduced and it is much easier to track where data is manipulated.
My guess is that your code looks something like this:
System.out.println(Global.camObjCoord[Global.i]);
addcube(/* values here */);
System.out.println(Global.camObjCoord[Global.i]);
and it's printing out 0. Well, that's not printing out the same index after assignment, because Global.i changes value during addcube. For example, suppose Global.i is 3 before the call to addcube. The call to addcube will set Global.camObjCoord[3] to a value, but then set Global.i to 4, so the final line will print out Global.camObjCoord[4] - i.e. not the value which is just been set.
This sort of thing is precisely why global variables are a bad idea...