Consider the custom toString() implementation of a bean:
#Override
public String toString() {
String.format("this is %s", this.someField);
}
This yields this is null if someField is null.
Is there a way to override the default null string representation of null-valued arguments to another text, i.e., ? without calling explicitly replaceAll(...) in the toString method?
Note: The bean inherits from a superclass that could implement Formattable (http://docs.oracle.com/javase/7/docs/api/java/util/Formattable.html) but I just don't seem to understand how to make this work.
EDIT: The snippet is over-simplified for the sake of example but I'm not looking for ternary operator solutions someField==null ? "?" : someField because:
there can be (potentially) a great many fields involved in toString() so checking all fields is too cumbersome and not fluent.
other people whom I have little control over (if any) are writing their own subclasses.
if a method is called and returns null that would either imply calling the method twice or declaring a local variable.
Rather, can anything be done using the Formattable interface or having some custom Formatter (which is final btw.)?
With java 8 you can now use Optional class for this:
import static java.util.Optional.ofNullable;
...
String myString = null;
System.out.printf("myString: %s",
ofNullable(myString).orElse("Not found")
);
For a Java 7 solution that doesn't require external libraries:
String.format("this is %s", Objects.toString(this.someField, "?"));
The nicest solution, in my opinion, is using Guava's Objects method, firstNonNull. The following method will ensure you will print an empty string if someField is ever null.
String.format("this is %s", MoreObjects.firstNonNull(this.someField, ""));
Guava docs.
A bit late on the subject, but this could be a quite clean-looking solution :
First, create your own format method...
private static String NULL_STRING = "?";
private static String formatNull(String str, Object... args){
for(int i = 0; i < args.length; i++){
if(args[i] == null){
args[i] = NULL_STRING;
}
}
return String.format(str, args);
}
Then, use it as will...
#Test
public void TestNullFormat(){
Object ob1 = null;
Object ob2 = "a test";
String str = formatNull("this is %s", ob1);
assertEquals("this is ?", str);
str = formatNull("this is %s", ob2);
assertEquals("this is a test", str);
}
This eliminates the need for multiple, hard-to-read, ternary operators.
If you don't want to use replaceAll(), You can assign a default text(String) for someField.
But if some time this may assign null again. So you can use validation for that case
this.someField == null ? "defaultText" : this.someField
To avoid repeating ternary operator you can wrap it in more readable method that will check if your object is null and return some default value if it is true like
static <T> T changeNull(T arg, T defaultValue) {
return arg == null ? defaultValue : arg;
}
usage
String field = null;
Integer id = null;
System.out.printf("field is %s %n", changeNull(field, ""));
System.out.printf("id is %d %n", changeNull(id, -1));
System.out.printf("id is %s %n", changeNull(field, ""));
output:
field is
id is -1
id is
You could just do
String.format("this is %s", (this.someField==null?"DEFAULT":this.someField));
From java 7, you can use Objects.toString(Object o, String nullDefault).
Applied to your example: String.format("this is %s", Objects.toString(this.someField, "?"));
public static String format(String format, Object... args){
for (int i=0;i<args.length;i++){
if (args[i]==null) args[i]="";
}
return String.format(format,args);
}
then use the method ,ok
To keep the original value of someField (in case null is a valid value), you can use a ternary operator.
String.format("This is %s", (this.someField == null ? "unknown" : this.someField));
Related
I need to create my own String class called MyString without using default String class/vector API. I have to work on some required methods, and their return types are predetermined. I can add other methods as long as String is not used.
Expected use would be:
(at main) System.out.println(str.toLowerCase()) - returns lower case of str
When I want to work with toLowerCase() method with return type MyString, I can't return the object content but only return the address.
Normally, this problem would require modification of toString(), but since this method requires return type of String by default, I can't use modification of toString() for the assignment.
The assignment is supposed to be not so hard and should not require complex extensions. My constructor may be the problem, but I can't specify which part is.
Code
public class MyString {
private char value[];
MyString(char[] arr){
this.value = Arrays.copyOf(arr, arr.length);
}
...
MyString toLowerCase() { // can't change return type
for (int i =0; i<value.length; i++) {
if ((int)value[i] > 64 && (int)value[i] < 91) {
value[i] = (char) (value[i]+32);
}
}
return this; // this returns address, and I can't override toString
}
Problem with System.out.println(str.toLowerCase()) is it ends up calling PrintStream.println(Object o), but that method internally at some point calls o.toString() which uses code inherited from Object#toString() (since you couldn't override toString as it expect as result String which is forbidden in your project) which result in form TypeInfo#hexHashCode.
This means you can't use System.out.println(MyString).
BUT PrintStream (which instance is held by System.out) allows us to provide data to print in different forms. In this case you can use println(char[]). All you need to do is adding to MyString method like toCharArray() which would return (preferably a copy of) array of characters held by MyString class.
This way you can use it like System.out.println(myStringInstance.toCharArray()) so code from your main method would need to look like
System.out.println(str.toLowerCase().toCharArray());
// ^^^^^^^^^^^--this should return char[]
Firstly, the String class is an immutable type, i.e. the methods of String do not change the internal state (i.e. the char array), instead they return a new instance of type String.
To mirror that behavior you could implement something like this:
public MyString toLowerCase() {
char temp = new char[value.length];
// [...] Your code performing the actual logic on temp
return new MyString(temp);
}
The immutability (and its implications) of the String class is very important to understand in practice. For example, the following code procudes the intended result:
String word = "Word";
System.out.println("I can produce upper case (" + word.toUpperCase() + ") " +
"and lower case (" + word.toLowerCase() + ") " +
"without any side-effects on the original (" + word + ").");
However, it's not possible (without "hacky" solutions) to implement a method like this:
void shortenString(String inputAndOutput);
Second, the assignment expects that the class/method must be used as follows:
System.out.println(str.toLowerCase());
The attribute out is effectively a PrintStream, which offers (besides other methods) the following two:
println(Object x) - Prints an Object and then terminate the line.
println(String x) - Prints a String and then terminate the line.
If the method is called with an Object parameter, the internal implementation calls toString() on the given object, thus the only way to satisfy the requirement is to override this method. Unfortunately, this is not allowed by the assignment.
However, if it is not explicitly stated that the solution has to use java.lang.System, you could simply implement your own System class which accepts MyString, e.g.:
public class System {
public static class MyPrintStream /* optional: extends PrintStream */ {
public void println(MyString x) {
java.lang.System.out.println(x.getCharArray());
}
}
public static final out = new MyPrintStream();
}
This would allow you to use it exactly as described in the assignment:
import my.package.System;
public class Main {
public static void main(String[] args) {
// [...] Instantiate str
System.out.println(str.toLowerCase());
}
}
How to remove the null after concatenation of two strings.
Ex:
String a = null;
String b = Hello;
a+=b;
System.out.println(a);// output is nullhello
here, i need output as only hello,
Thanks in advance.
You can use this
String a = null;
String b = "Hello";
a = ((a==null) ? "": a) + b;
System.out.println(a);
The Java designers thought it a good idea to treat the compound assignment by sum operator += when applied to a null lvalue java.lang.String reference as a special case by injecting a (rather arbitrary) textual stringification of nullness.
(I see it as a manifest act of utter madness: an alternative would include throwing a NullPointerException as would happen if += is applied to a numeric boxed type such as java.lang.Integer.)
If you don't want this behaviour then you need to program specifically to obviate it.
You can use custom method for this, this is one line of code:
public static String concat(String a, String b) {
return a == null ? b : b == null ? a : a + b;
}
It might be a bit of overhead, but you can use Objects.toString method:
String a = null;
String b = Hello;
System.out.println(Objects.toString(a,"").concat(Objects.toString(b,"")));
public static String toString(Object o,
String nullDefault)
Returns the result of calling toString on the first argument if the
first argument is not null and returns the second argument otherwise.
This will handle all the possible cases {(a == null, b!= null),(a != null, b == null),(a == null, b == null),(a != null, b!= null)}
other alternative will be using Optional
System.out.println(
Optional.ofNullable(a).orElse("")
.concat(Optional.ofNullable(b).orElse(""))
);
public T orElse(T other)
Return the value if present, otherwise return other.
This will be identical to the first solution. Both of this solutions has one common disadvantage: code needs to be duplicated for every additional variable. For example if now we need to concatenate 3 variables a,b and c. We will have to just copy and paste same code for c.
In this case we can use Streams
System.out.println(
Stream.of(a,b)
.filter(Objects::nonNull)
.collect(Collectors.joining())
);
It will create a stream consisting of strings a and b; will filter out all strings which are null and finally collect all remaining strings using empty delimiter. In case if there are more then 2 variables we will just add them to initial stream.
I hope you will find this helpful.
You may use Google's Guava library to get rid of null before concatenation.
String a = Strings.nullToEmpty(null);
String b = Strings.nullToEmpty("Hello");
a+=b;
System.out.println(a);// output is hello
It makes the code more explicit about the fact that you don't want null, IMO it's more readable as than a ternary expression.
I would like to write a function that would enable me to do the following
inputs: variable number of objects of any type
output: a string that would be NameObj1=ValueObj1, ..., NameObjN=ValueObjN
All objects I would pass to the function would have a toString() method.
Example:
double x=1.1; int y=2; ClassA a
theFunction(x,y,a)
=> this would output "x=1.1, y=1, a=[whatever a.toString() output]"
Is that possible ?
here's something close:
you can write a var-arg function like so:
public static String describeArguments (Object... arguments) {
StringBuilder output = new StringBuilder();
int counter = 1;
for (Object argument : arguments) {
output.append("object #").append(counter++).append(": ").append(argument.toString());
}
return output.toString();
}
strictly speaking method arguments dont have names. you could retrieve the argument parameter name using reflection if the symbol tables werent stripped out #compile time, but its brutish and ugly.
There's no way of getting what you wrote to be the "name" of a variable, because the only way of referencing it, is by itself, and by value is not possible as well.
As mentioned in other answers and comments there is no "name of an object". But if the objects you are interested in are all fields of one class, you could write a function that uses reflection to access that objects fields and prints their names.
Take a look at the reflection tutorial. There is also an example that is very close to what you might have in mind.
You can create a map like
Map<String,Object> map= new HashMap<String,Object>();
map.put("x", 1.1);
map.put("y",2);
map.put("a", MyClass.class);
And call theFunction(map), where theFunction is:
public void theFunction(HashMap<String,Object> list) {
StringBuilder sb = new StringBuilder();
for(String key:list.keySet()) {
try {
Object currentObject = list.get(key);
sb.append(key+"="+currentObject.getClass().getMethod("toString").invoke(currentObject)+" ");
}
catch(Exception e){}
}
System.out.println(sb.toString());
}
I want to get string values of my fields (they can be type of long string or any object),
if a field is null then it should return empty string, I did this with guava;
nullToEmpty(String.valueOf(gearBox))
nullToEmpty(String.valueOf(id))
...
But this returns null if gearbox is null! Not empty string because valueOf methdod returns string "null" which leads to errors.
Any Ideas?
EDIt: there are 100s fields I look for something easy to implement
You can use Objects.toString() (standard in Java 7):
Objects.toString(gearBox, "")
Objects.toString(id, "")
From the linked documentation:
public static String toString(Object o, String nullDefault)
Returns the result of calling toString on the first argument if the first argument is not null and returns the second argument otherwise.
Parameters:
o - an object
nullDefault - string to return if the first argument is null
Returns:
the result of calling toString on the first argument if it is not null and the second argument otherwise.
See Also:
toString(Object)
For java 8 you can use Optional approach:
Optional.ofNullable(gearBox).orElse("");
Optional.ofNullable(id).orElse("");
If you don't mind using Apache commons, they have a StringUtils.defaultString(String str) that does this.
Returns either the passed in String, or if the String is null, an empty String ("").
If you also want to get rid of "null", you can do:
StringUtils.defaultString(str).replaceAll("^null$", "")
or to ignore case:
StringUtils.defaultString(str).replaceAll("^(?i)null$", "")
If alternative way, Guava provides Strings.nullToEmpty(String).
Source code
String str = null;
str = Strings.nullToEmpty(str);
System.out.println("String length : " + str.length());
Result
0
Use an inline null check
gearBox == null ? "" : String.valueOf(gearBox);
StringUtils.defaultString(String str) Returns either the passed in String, or if the String is null, an empty String ("").
Example from java doc
StringUtils.defaultString(null) will return ""
StringUtils.defaultString("") will return ""
StringUtils.defaultString("bat") will return "bat"
Since you're using guava:
Objects.firstNonNull(gearBox, "").toString();
In Java 9+ use : Objects.requireNonNullElse (obj, defaultObj) https://docs.oracle.com/javase/9/docs/api/java/util/Objects.html#requireNonNullElse-T-T-
//-- returns empty string if obj is null
Objects.requireNonNullElse (obj, "")
I used to use the implicit call of toString when wanting some debug info about an object, because in case of the object is null it does not throw an Exception.
For instance:
System.out.println("obj: "+obj);
instead of:
System.out.println("obj: "+obj.toString());
Is there any difference apart from the null case?
Can the latter case work, when the former does not?
Edit:
What exactly is done, in case of the implicit call?
There's little difference. Use the one that's shorter and works more often.
If you actually want to get the string value of an object for other reasons, and want it to be null friendly, do this:
String s = String.valueOf(obj);
Edit: The question was extended, so I'll extend my answer.
In both cases, they compile to something like the following:
System.out.println(new StringBuilder().append("obj: ").append(obj).toString());
When your toString() is implicit, you'll see that in the second append.
If you look at the source code to java, you'll see that StringBuilder.append(Object) looks like this:
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
where String.valueOf looks like this:
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
Now, if you toString() yourself, you bypass a null check and a stack frame and go straight to this in StringBuilder:
public StringBuilder append(String str) {
super.append(str);
return this;
}
So...very similar things happens in both cases. One just does a little more work.
As others have said - use the "" + obj method.
According to The Java Language Spec:
If the term is null, use "null"
Primitive types are converted using the boxed-type constructor new Boolean(X) or whatever
toString() is invoked (or equivalent)
if the result of toString() is null, use "null"
Concatenate the strings.
No difference except, like you say, the null safety. Always prefer the former to the latter.
Actually, if your invariant says the object should never be null, it doesn't matter. So it depends on whether or not you accept obj to be null.
It is quite easy to write a generic reference type.
class ref
{
static public class Reference<T>
{
private T value;
public Reference(T value) { set(value); }
public Reference() { set(null); }
public void set (T value) { this.value = value; }
public T get () { return this.value; }
public String toString() { return String.valueOf(this.value); }
}
static void fillString (Reference<String> str)
{
str.set("foo");
}
public static void main (String[] args)
{
Reference<String> str = new Reference<String>("");
fillString(str);
System.out.println (str);
}
}
Running it gives the required output:
javac ref.java && java ref
foo