Should toString() ever return null? [duplicate] - java

This question already has answers here:
When we override the toString() method we should always return a string representation of the object?
(6 answers)
Closed 4 years ago.
Should the method toString() in java ever return null if no conversion could be done or should it return an empty string in that case instead?

null is not String so it is not allowed to return here. Check Java Docs:
Returns a string representation of the object. In general, the toString method returns a string that "textually represents" this object. The result should be a concise but informative representation that is easy for a person to read. It is recommended that all subclasses override this method.
it should return a meaningful string representation of the object. I wrote an example of how to use it and why it is useful:
public class Car {
private String make;
private int year;
public Car(String make, int year) {
this.make = make;
this.year = year;
}
#Overrride
public String toString() {
return "Car Make:" + make + "; Built Year: " + year;
}
}
Example:
Car myCar = new Car("Nissan", 1999);
Car yourCar = new Car("BMW", 2018);
System.out.println(myCar); // call toString() implicitly
System.out.println(yourCar);
It will print 2 lines and you can easily read the text and know which is your car!
Car Make:Nissan; Built Year: 1999
Car Make:BMW; Built Year: 2018

toString() returning null would be very bad API design. Clearly, if you are able to call toString() on it, the object is clearly not null. Otherwise, there would be a NullPointerException.
It really depends on the Object and what the use case is. Empty string is ok if you are using toString() to do real logic - e.g, if you use toString() as the key to a key-value store. If it is simply used for debugging/logging. Just print out all the fields. e.g, something like what MoreObjects.toStringHelper() does.

The Java API documentation, every recent version I have checked, says:
Returns:
a string representation of the object.
In other words null is not a defined return value. If you don't override the toString() method then you will always get a string that at least gives you the Object's ID.
Although this does not rule out that possibility of an overriding method returning null, any programmer who does this should expect a lot of NPEs from tools and frameworks that might be operating on that code.
My opinion: don't do it.
My question: what kind of object could not be represented by a string?

Related

Why do we use `this` in CompareTo in Comparable implementations?

I am somewhat new to java and very new to the Collection framework. I know that this refers to the current object
public class Student implements Comparable <Student> {
String name;
int grade;
public Student(String name, int grade) {
this.name = name;
this.grade = grade;
}
public int compareTo(Student s) {
return this.name.compareTo(s.name);
}
public String toString() {
return this.name + ", " + this.grade;
}
}
Here this.name is null and s.name does have a value, so what are we trying to do by comparing this.name.compareTo(s.name);
Also what really happens when we do Collections.sort(studentList); ?
The code snippet is just for demo purposes
You are asking two different questions, so I will answer them seperately
First one which is what are we trying to by comparing this.name.compareTo(s.name);
When the compareTo method is called on an object of class Student, the this becomes the calling object. Since the calling object (hopefully) has been initialized properly this.name will be the name of the calling object.
s.name is the name of the Student object passed in to the compareTo method which is again (hopefully) initialized properly and has a name.
What is boils down to is a String variable calling compareTo passing in a String variable to compare with
Second is what really happens when we do Collections.sort(studentList);
Here is the JavaDocs on the Collections.Sort method but you are likely asking about what it does relative to your implementation of Comparable. In short it uses your compareTo method when doing the comparisons for the sort
Since it seems that the name is an important property of a Student the first thing you should ask yourself is "What is a valid name for a student?" Is null valid? Is an empty string valid? If not, you need to prevent the initialization of a Student with an invalid name by using a setter:
public void setName(String name) {
if (name is invalid) {
throw error;
}
this.name = name; // name is valid, so this is safe now
}
Now, call the setter in your constructor and you'll be sure that if you have a Student, he'll have a valid name.
One problem with having an invalid name is that if you don't prevent null values you'll get a NullPointerException every time you call the compareTo() method. You'll essentially be calling null.compareTo() and obviously null doesn't have such a method, it doesn't have any methods.
Now, to the sort() method. How do you sort Students? If you don't tell Java how to compare one Student to another Student, how should it order them? It can handle numbers (2 is less than 3) and strings ("a" is before "b"), but it can't know how to compare a custom class you created. Therefore, you need to let it know - using the compareTo() method. Calling sort() on a collection of objects which cannot be compared will cause an exception. Calling sort() on a collection of Student will order them using the rules you provided in compareTo() which is by name (regular string comparison).
As for the sorting mechanism itself, it's implementation specific, but it's usually a combination of several algorithms, a hybrid. In Java I believe it's Timsort, in C# it's introspective sort. In any case, in order to sort a collection like this, you need to compare elements, two by two (hence the requirement to implement Comparable). The trick is how to do this so as to reduce the number of comparisons performed. There are a lot of good sources out there that explain different sorting methods, but it all boils down to being able to compare elements and tell which should come before which.

Why are my list objects locations in memory? [duplicate]

This question already has answers here:
How do I print my Java object without getting "SomeType#2f92e0f4"?
(13 answers)
Closed 6 years ago.
I'm trying to convert a list of objects into json but the values are the location in memory.
public class User {
private String name;
private int score;
public User(String name, int score){
this.name = name;
this.score = score;
}
User user1= new User("Luke", 50);
User user2 = new User("Ryan", 70);
List<User> list = Arrays.asList(user1, user2);
Gson gson = new Gson();
String json = gson.toJson(list);
System.out.println(list);
The last line is supposed to show my objects in json but instead i just get [User#579bb367, User#1de0aca6], why is this? thanks
You meant
System.out.println(json);
What you did was to print the List, that, without a toString, will just print a default hash
You just print the hashcode of the list. When you call System.out.println() method, it will call toString() method of List. It is
getClass().getName() + '#' + Integer.toHexString(hashCode())
You need to implement a toString() method for the Object inside your list, or you will get the hash codes.
When you print a list, you're in fact (implicitly) calling its toString() method, which usually just calls each of its element's toString()s, concatinates them with commas and encloses them in brackets. If your User class does not override toString() it will use Object's implementation that just prints the class' simple name and its default hashCode(), which is typically the memory address. If you want something more intelligent there, you'd have to override toString(). E.g.:
#Override
public String toString() {
return String.format("[User name %s, score %d]", name, score);
}

What are the reasons and benefits of overriding toString() for string representation of an object? [duplicate]

This question already has answers here:
Why to use Polymorphism?
(13 answers)
What are the original reasons for ToString() in Java and .NET?
(4 answers)
Closed 8 years ago.
When we need a String representation of an object, we can override the toString() method. However, what are the real benefits and reasons for overriding toString() when we can just define a new method to return the string?
Please see example below:
class One
{
private String name;
public One(String _name)
{
name = _name;
}
#Override public String toString()
{
return name;
}
}
class Two
{
private String name;
public Two(String _name)
{
name = _name;
}
public String printMyClass() //Self-defined to print class details
{
return name;
}
}
In the above example, printMyClass() which is self-defined seemed to does the same thing as toString().
So my question is: Why do we still use toString() ?
The main benefits are that libraries expect this behaviour and use it.
If for example you log "funcX called with ("+param1+", "+param2+")" then toString() will automatically be called for you.
Additionally this means that you always know that the toString() method is available (since it is defined in so you can call it on every object without needing to worry about whether it is present or not.
A better question for you is why not use it? It's provided for you so why do you not want to use it?
Easy conversion to String type that is used in String concatenation with + operator.
The benefit is that you don't have to write printMyClass() multiple times.
This is shorter
obj1 + " " + obj2
than this
obj1.printMyClass() + " " + obj2.printMyClass()
I do sometimes use it to help debugger show more readable output, but that's a little eccentric.
Because toString is used by all other Java code to get a String representation of the Object.
Consider, for example, parametrised logging in SLF4j, here we use a format String and arguments to create a logging statement:
log.info("User {} has just logged in.", user);
The logging library will, if the logging level is low enough, take the format String and call toString on user in order to get the final logging message.
This is just one example of something that can generally be called a "call back". Since toString is part of the Java API many libraries use it to convert an Object to String. Doing the same, for example, deferred evaluation logging, would have required aninterface` and an anonymous class (pre Java 8) which is very messy.
In the most simple example consider String concatenation and implicit String conversion:
final String string = "User is " + user;
Without the toString method how would this even be possible?

Custom 'String' Class

I'm trying to figure out how java classes work.
When I create a StringBuilder:
StringBuilder testString = new StringBuilder("Hello World!);
If I want to, say, get the value that testSting holds a reference to, I can simply call it like: System.out.println(testString);
This is cool behavior, but I'm unsure how to replicate it in classes that I make.
For instance, if I were to try and re-implement my own version of StringBuilder, the approach I would take (as a beginner), would be this:
class MyBuilder {
char[] string;
public MyBuilder(String s) {
string = new char[s.length()];
string = s.toCharArray();
}
So, to make the string an array I had to store it in a data field of the class. But then, to access this in my code, I can't print it by simply calling the variable name. I would have to use .property syntax. Thus, to duplicate the above example, I would have to type System.out.println(testString.value); Which isn't nearly as pretty.
How do you make a class such that it behaves like String or StringBuilder and returns its value without manually accessing the data fields?
Implement a toString method.
toString is a method on Object, so every java object inherits one. The default implementation that you inherit is only useful for getting the class type, and for distinguishing one object from another; the format is: ClassName#HashCode. There are no details unique to your implementation.
In your own classes, to get the description that you want you'll need to override the toString method, so that in contexts where a String is expected, e.g. when you call System.out.println(myObject.toString());, your own format is used.
It's often a good idea to do this, for a more readable description of your object. You can always call super.toString to include the output from the default - ClassName#HashCode - in your own output.
You can override Object.toString() in your object MyBuilder. System.out.println calls on this method for every object used. For example here, you could use:
#Override
public String toString() {
return Arrays.toString(string);
}
Overwrite the toString-Method
private String value;
public MyClass(String value) {
this.value = value;
}
public String toString() {
return value;
}

Override of toString() that makes use of the overridden toString()

Basically this is what I am trying to achieve.
classname#address(?)[original toString()], object's name, object's age
#Override public String toString()
{
return String.format("%s , %s , %d", this.toString(), this.getName(),this.getAge());
}
Problem, toString() gets called recursively.
I can't call super.toString() because that's not what I want. I want 'this' to call the original toString().
This
this.super.toString()
doesn't work for obvious reasons.
I'm running out of steam, can this be done once a method gets overridden? I.e. call the original implementation ?
(my edit) Basically what I need is: override toString to display two properties of 'this' object, and I also want to have 'this' call the original toString.
This is not a project , or work. Just playing(learning) with Java language. Thanks
You're looking for super.toString().
Actually, I was trying to achieve the same thing, where super.toString() wasn't exactly what I wanted. I believe that this is not possible.
Specifically, I have a domain class in Groovy/Grails, and I wanted to override its toString() method to add some extra information:
class Child extends Parent {
public String toString() {
return super.toString(this) + extra_info // not possible!!!
}
}
This is not identical to return super.toString() + extra_info. In one case I get e.g.
com.example.domain.Parent : 15, extra_info. (Wrong. The instance is the same, but toString includes type information.)
In the other:
com.example.domain.Child : 15, extra_info. (Correct, but not possible.)

Categories