When testing toString, why is calling toString required? - java

I've overwritten the toString method of my class. When testing the toString method, I've been left wondering why calling toString is required.
Let me elaborate -
toString in class People:
#Override
public String toString() {
return ("This Object is called " + this.name + ". For a list of weekdays: " + this.dates);
}
Working Test Case:
#Test
Human Tom = new Human("Tom"); // constructor creates an ArrayList<weekDay> named dates
weekDay someDay = new weekDay("Thursday");
Tom.addDate(someDay); // adds someDay to the ArrayList
String result = ("This Object is called " + this.name + ". For a list of weekdays: " + Tom.dates);
assertEquals(Tom.toString(), result);
assertEquals(Tom.toString(), result) will work fine. But, when instead I try assertEquals(Tom, result) eclipse will write something like "expected x" but was "y". Yet, "y" has the exact same content as "x". Why is the need for explicitly calling toString()?

assertEquals(Tom.toString(), result);
This is equivalent to writing:
Tom.toString().equals(result);
Which compares the two String values. When you attempt to do this:
assertEquals(Tom, result);
This is equivalent to:
Tom.equals(result);
Which is now invoking the .equals() method on your People class (if you defined one), or Object#equals if you did not.
Eclipse is printing out the toString() method after your test fails to give you details of the error, which is unfortunately confusing in this scenario.

Related

Why is it common practice to override the method toString() in java to print the instance variables of the class?

As I've been learning and even some IDEs have it embeded in it, to override the toString() method to print out all instance variables of the class.
The original toString() defined in object.java is defined as follows:
public String toString() {
return getClass().getName() + "#" + Integer.toHexString(hashCode());
}
And it's common practice to override it as:
public String toString() {
return "className{" +"var1="+var1+", var2="+var2+'}';
}
Why don't we keep the original functionality of the toString() method and create a new method (with a different name) with this functionality?
We could. But how will other classes, that know absolutely nothing about your subclasses with your myNewToString method, know how to print a string that textually represents, in a concise but informative way, arbitrary subclasses?
The toString method was designed to be overridden to do that. Yes, it does have default behavior but it's not very useful. Its authors wanted you to override it. Overriding it to return what's commonly practiced is more useful, but you don't have to do that. A toString method for an EmailAddress class can return
public String toString() {
return "EmailAddress{localPart = " + localPart + ", domainName = " + domainName + "}";
}
but it's usually more useful to return something like
public String toString() {
return localPart + "#" + domainName;
}
The reason to override toString() is that toString() is called implicit by the compiler every time an object which is not of type String, is added to a string.
So if you have
MyObject o=new MyObject();
C="Hello " + o;
Then the compiler will call o.toString() in order to get a string it can concat to "Hello "
And I should note that it checks if o is null before calling toString() on o. And if o is null, it just generate the string "null"
Opinion: The toString() method should in general and in most cases only be used for debugging (Print/Log) and not as part of the normal program flow.

Implementing an ArrayQueue in java need toString method

I have an ArrayQueue I am implementing for a class in the java language.
I am storing transaction objects in the ArrayQueue and I am getting stuck at the display() method (aka my own toString()). But it is only returning the reference.
Here is my method:
//display the elements in the current queue
public String display() {
String result = "";
if(isEmpty()) {
throw new EmptyQueueException("Queue is empty.");
} else {
for (int i = 0; i < count; i++) {
result += "[" + Q[(front + i) % capacity] + "] ";
}
}
return result;
}
Does this mean I need a toString() method for my object and call it like: System.out.println(arrayqueue.display().toString())?
If you override toString() for your ArrayQueue class, you can use:
System.out.println(arrayqueue);
But if you choose to call it display(), then yes you need this:
System.out.println(arrayqueue.display())
How else is the runtime environment supposed to know you wanted the string representation instead of the object reference?
Does this mean I need a toString() method for my object and call it like: System.out.println(arrayqueue.display().toString())?
No, since display() returns a String, arrayqueue.display() should be sufficient. Are you perhaps trying to print the toString() value of arrayqueue? Without overriding toString(), it will return the class name and hash code by default.
When you call the code
result += "[" + Q[(front + i) % capacity] + "] ";
You are calling the toString() method on the object contained at that location in the Q array. Default object toString() will print its memory location. If you have different data already declared by your object to print, such as object.getClass() to print the objects class name for instance you won't have to override toString() but instead call that method within the above code. Of course if you want a custom string that better represents your object than its memory location, its good to override toString() within that object's class.

arraylist returning random numbers and not proper data

so I've got an arraylist
private static ArrayList<Job> teamNoOne = new ArrayList<Job>();
Of type Job, which has
public class Job {
//public long time;
public int teamNo;
public String regNo;
public String gridRef;
}
Then I'm getting data from a textField
Job job = new Job();
job.gridRef = tfGridRef.getText();
This all works, printed it to system etc.
When I add it to the arraylist, and print it out using the following code:
teamNoOne.add(job);
System.out.println(teamNoOne.get(0));
I just get this: Job#1c79dfc
cannot for the life of me figure out why,
Cheers
When a object is printed using sysout, its toString method is called. If toString method is not overridden in the class, then its default implementation will be used. Default implementation of an object toString method prints the class name and the unsigned hexadecimal representation of the hash code of the object separated by # symbol.
You need to override the toString method in your Job class in order to print the object in a pretty way. Most of the IDEs provide a way to auto- generate the toString method. Here is one generated through eclipse:
#Override
public String toString() {
return "Job [teamNo=" + teamNo + ", regNo=" + regNo + ", gridRef="
+ gridRef + "]";
}

How does System.out.print() work?

I have worked with Java for a quite a long time, and I was wondering how the function System.out.print() works.
Here is my doubt:
Being a function, it has a declaration somewhere in the io package. But how did Java developers do that, since this function can take in any number of arguments and any argument types no matter how they are arranged? e.g:
System.out.print("Hello World");
System.out.print("My name is" + foo);
System.out.print("Sum of " + a + "and " + b + "is " + c);
System.out.print("Total USD is " + usd);
No matter what is the datatype of variables a, b, c, usd, foo or how they are passed, System.out.print() never throws an error.
For me, I have never worked on any project where the requirement was like this. Provided, if I get a requirement like this, I really don't know how to solve it.
Can anyone explain to me how it's done?
System.out is just an instance of PrintStream. You can check its JavaDoc. Its variability is based on method overloading (multiple methods with the same name, but with different parameters).
This print stream is sending its output to so called standard output.
In your question you mention a technique called variadic functions (or varargs). Unfortunately that is not supported by PrintStream#print, so you must be mistaking this with something else. However it is very easy to implement these in Java. Just check the documentation.
And if you are curious how Java knows how to concatenate non-string variables "foo" + 1 + true + myObj, it is mainly responsibility of a Java compiler.
When there is no variable involved in the concatenation, the compiler simply concatenates the string. When there is a variable involved, the concatenation is translated into StringBuilder#append chain. There is no concatenation instruction in the resulting byte code; i.e. the + operator (when talking about string concatenation) is resolved during the compilation.
All types in Java can be converted to string (int via methods in Integer class, boolean via methods in Boolean class, objects via their own #toString, ...). You can check StringBuilder's source code if you are interested.
UPDATE: I was curious myself and checked (using javap) what my example System.out.println("foo" + 1 + true + myObj) compiles into. The result:
System.out.println(new StringBuilder("foo1true").append(myObj).toString());
Even though it look as if System.put.print...() take a variable number of arguments it doesn't. If you look closely, the string is simply concatenated and you can do the same with any string. The only thing that happens is, that the objects you are passing in, are implicitily converted to a string by java calling the toString() method.
If you try to do this it will fail:
int i = 0;
String s = i;
System.out.println(s);
Reason is, because here the implicit conversion is not done.
However if you change it to
int i = 0;
String s = "" + i;
System.out.println(s);
It works and this is what happens when using System.put.print...() as well.
If you want to implement a variable number of arguments in java to mimimc something like C printf you can declare it like this:
public void t(String s, String ... args)
{
String val = args[1];
}
What happens here is that an array of Strings is passed in, with the length of the provided arguments. Here Java can do the type checking for you.
If you want truly a printf then you have to do it like this:
public void t(String s, Object ... args)
{
String val = args[1].toString();
}
Then would you have to cast or interpret the arguments accordingly.
It is a very sensitive point to understand how System.out.print works.
If the first element is String then plus(+) operator works as String concate operator. If the first element is integer plus(+) operator works as mathematical operator.
public static void main(String args[]) {
System.out.println("String" + 8 + 8); //String88
System.out.println(8 + 8+ "String"); //16String
}
Evidently, the compiler was made in a confusing way although the compiler developers thought they added some smartness. The true smartness they should really add is to look entire argument and interpret + operator consistently. For example, System.out.println(1+2+"hello"+3+4); should output 3hello7 instead of 3hello34
I think you are confused with the printf(String format, Object... args) method. The first argument is the format string, which is mandatory, rest you can pass an arbitrary number of Objects.
There is no such overload for both the print() and println() methods.
Its all about Method Overloading.
There are individual methods for each data type in println() method
If you pass object :
Prints an Object and then terminate the line. This method calls at first String.valueOf(x) to get the printed object's string value, then behaves as though it invokes print(String) and then println().
If you pass Primitive type:
corresponding primitive type method calls
if you pass String :
corresponding println(String x) method calls
You can convert anything to a String as long as you choose what to print. The requirement was quite simple since Objet.toString() can return a default dumb string: package.classname + # + object number.
If your print method should return an XML or JSON serialization, the basic result of toString() wouldn't be acceptable. Even though the method succeed.
Here is a simple example to show that Java can be dumb
public class MockTest{
String field1;
String field2;
public MockTest(String field1,String field2){
this.field1=field1;
this.field2=field2;
}
}
System.out.println(new MockTest("a","b");
will print something package.Mocktest#3254487 ! Even though you only have two String members and this could be implemented to print
Mocktest#3254487{"field1":"a","field2":"b"}
(or pretty much how it appears in the debbuger)
#ikis, firstly as #Devolus said these are not multiple aruements passed to print(). Indeed all these arguments passed get
concatenated to form a single String. So print() does not teakes multiple arguements (a. k. a. var-args). Now the concept that remains to discuss is how print() prints any type of the arguement passed
to it.
To explain this - toString() is the secret:
System is a class, with a static field out, of type PrintStream. So you're calling the println(Object x) method of a
PrintStream.
It is implemented like this:
public void println(Object x) {
String s = String.valueOf(x);
synchronized (this) {
print(s);
newLine();
}
}
As wee see, it's calling the String.valueOf(Object) method. This is implemented as follows:
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
And here you see, that toString() is called.
So whatever is returned from the toString() method of that class, same gets printed.
And as we know the toString() is in Object class and thus inherits a default iplementation from Object.
ex: Remember when we have a class whose toString() we override and then we pass that ref variable to print, what do you see printed? - It's what we return from the toString().
The scenarios that you have mentioned are not of overloading, you are just concatenating different variables with a String.
System.out.print("Hello World");
System.out.print("My name is" + foo);
System.out.print("Sum of " + a + "and " + b + "is " + c);
System.out.print("Total USD is " + usd);
in all of these cases, you are only calling print(String s) because when something is concatenated with a string it gets converted to a String by calling the toString() of that object, and primitives are directly concatenated.
However if you want to know of different signatures then yes print() is overloaded for various arguments.

Java array, prints something else

I'm trying to print the items from my array, but when I run the program, it prints out Orders:testorder#4, testorder#5 and so on. Any tips on how I can fix it so it writes 123 Buy?
package hej;
public class TestOrder {
public static void main(String[] args) {
Order order1 = new Order("123", "Buy");
Order order2 = new Order("456", "Sell");
Order order3= new Order("231", "Buy");
Order order4= new Order("987", "Buy");
OrderRegister orderregister = new OrderRegister();
orderregister.addOrder(order1);
orderregister.addOrder(order2);
orderregister.addOrder(order3);
orderregister.addOrder(order4);
System.out.println("Orders: ");
for (int i = 0; i < orderregister.getArrayList().size(); i++){
System.out.println(orderregister.getArrayList().get(i) + "-");
}
}
}
Because you don't have a toString() method defined for your Order class.
When Java tries to print an Object, it attempts to call the toString() method for that Object, if it can't find one it uses the toString() from the Object superclass.
And the Object toString() by default does this:
getClass().getName() + '#' + Integer.toHexString(hashCode())
which is exactly what you are seeing as output.
Have TestOrder override the toString() method.
When you concatenate an object with a String (like in your System.out.println(...) statements), the toString() method is called on the object to convert it to a String first.
You need to override the toString() method on your Order class and have it generate the string form of the order.
This is exactly what you should expect, given that you haven't told Java any other way to convert an Order to a String. Override Order.toString() if you want Java to use some particular way of converting an Order to a String.
You could/should try overriding the toString() method(which is called implicitly in your example) as others have suggested.
For example:
#Override public String toString()
{
return String.format("%s , %s", this.getID(), this.getAction());
}

Categories