Java - passing null as an argument to print() - java

I want to know why the below code doesn't work :
System.out.print(null);
response.getWriter().print(null);
But the below ones work :
String s = null;
System.out.print(s);
response.getWriter().print(s);
Whats the difference between passing a null as compared to passing a reference as null ?
EDITED : Doesn't work fore mentioned indicates to compilation error .

This is because you can pass an Object or a String. Since null can fit in both, the compiler doesn't know which method to use, leading to compile error.
Methods definitions:
System.out.print(Object)
System.out.print(String)
Instead, if you provide an Object or a String variable (even if it has null value), the compiler would know which method to use.
EDIT: This is better explained in this answer. As to the internal link pointing to the Java specification, you can read it here, and this case would suit here:
The informal intuition is that one method is more specific than another **if any invocation handled by the first method could be passed on to the other one without a compile-time type error.
It is possible that no method is the most specific, because there are two or more methods that are maximally specific.

It's because System.out.println() expects something with a type. null doesn't have a type, and therefore it can't be output on it's own. This is shown by:
Doesn't work:
System.out.println(null);
Works:
System.out.println((String)null);
System.out.println((char[])null);
System.out.println((Object)null);
It's the compiler type-checking the parameters of the method call.

Thank you all for your answers . From your inputs , I compiled the answer myself . It seems the call System.out.print(null) is ambiguous to compiler because print(null) here will find the two best specific matches i.e. print(String) and print(char[]) . So compiler is unable to determine which method to call here .
Small example will be :
private void methodCall(String str) {
}
private void methodCall(char[] ch){
}
Now this code becomes ambigious : methodCall(null) .

Related

Java 8: method reference to a static method in a non-static way

I'm studying the new Stream API for the OCP exam and I found something that I don't really understand. Here's my code:
void methodOne() {
this.compare(1, 2); // This works fine.
Stream.of(1,2,3)
.sorted(this::compare); // Compilation error.
}
static Integer compare(Integer s1, Integer s2) {
return 0;
}
Here I have a static method called compare and a non-static one called compare. If I call the compare method from the non-static method I get a compiler warning:
The method compare(Integer, Integer) from the type TestStream should be accessed in a static way
If I instead use a method reference to that same method in my stream, that compiler warning becomes a compiler error with the same message.
I know why I get the warning but I don't get why this warning becomes a compilation error if I use a method reference. I didn't find anything online either. Can someone explain it to me?
Accessing a static method via a reference was seen as a design error to this day AFAIK. You can even do:
YourClass c = null;
c.compare (...)
And that would work just fine (with a warning though).
When java-8 features where designed this was corrected, so the only way to access a static method (for a method reference) is via the class itself:
YourClass::compare
I know why I get the warning but I don't get why this warning becomes
a compilation error if I a method reference. I didn't find anything
online either. Can someone explain it to me?
It should have been a compilation error in both cases, but the earlier versions of Java tolerated it because the designers of the language didn't know better, and now for continued compatibility it is too late to change it.
However, method references are a newly constructed language syntax. When you're using the construction <object instance>::<method name>, then by definition the method you're trying to reference cannot be a static method since you're accessing it by specifying what object instance you want it applied to, which a static method is incapable to do.
Doing it right this time and rejecting invalid constructs that try to access static stuff through an instance, doesn't break any existing syntax of the language that may have been used somewhere by someone, albeit unwisely. So they did it right this time. Don't do invalid things, the compiler ought to reject them, and in that case it will.
It would also complicate parameters inference in case of overloaded methods, some static and some non-static. But it wouldn't be the first inference hell they would have to make do with.

Passing null to the method preferring String, not Object

I am facing an issue in my program and I made it clear with a small code snippet below. Can anyone explain why this is happening?
class ObjectnullTest {
public void printToOut(String string) {
System.out.println("I am null string");
}
public void printToOut(Object object)
System.out.println("I am null object");
}
class Test {
public static void main(String args[]) {
ObjectnullTest a = new ObjectnullTest();
a.printToOut(null);
}
}
This always prints I am null string .
I want to know the reason so that I can modify the code .
It's because In case of method Overloading
The most specific method is choosen at compile time.
As 'java.lang.String' is a more specific type than 'java.lang.Object'. In your case the method which takes 'String' as a parameter is choosen.
Its clearly documented in JLS:
The second step searches the type determined in the previous step for
member methods. This step uses the name of the method and the types of
the argument expressions to locate methods that are both accessible
and applicable, that is, declarations that can be correctly invoked
on the given arguments.
There may be more than one such method, in
which case the most specific one is chosen. The descriptor (signature
plus return type) of the most specific method is one used at run-time
to perform the method dispatch.
I agree with the existing comment about selection of the most specific method. You can force your null to be treated as an Object reference, eliminating use of the String argument method, by casting it:
a.printToOut((Object)null);
please see section 15.12.2.5 of jls that gives detail regarding how it is chosen
The most specific method is choosen at compile time
LINK TO THE JLS 15.12.2.5

toString: When is it used?

I have a class
class Configuration {
// various stuff
#Override
public String toString() {
// assemble outString
return outString;
}
}
I also have another class
class Log {
public static void d(String format, Object... d) {
// print the format using d
}
}
The Log class works perfectly fine, I use it all the time. Now when I do this:
Configuration config = getConfiguration();
Log.d(config);
I get the compiler error The method d(String, Object...) in the type Log is not applicable for the arguments (Configuration). I can solve this:
Log.d("" + config); // solution 1
Log.d(config.toString()); // solution 2
My problem: How is this different? In the first solution, the compiler notices that it has to concatenate two Strings, but the second one is a Configuration. So Configuration#toString() is called and everything is fine. In the compiler error case the compiler sees that a String is needed, but a Configuration is given. Basically the same problem.
Needed: String
Given: Configuration
How are these cases different and why is toString not called?
While designing the language, someone decided that when a programmer appends an arbitrary object to a string using the + operator, they definitely want a String, so implicitly calling toString() makes sense.
But if you call an arbitrary method that takes a String with something else, that is simply a type error, exactly what all that static typing is supposed to prevent.
The line
"" + config
gets translated to something like
StringBuilder sb = new StringBuilder("");
sb.append(config);
where the second line calls
StringBuilder.append(Object obj);
This method calls obj.toString() to get the String representation of the object.
On the other hand, the first parameter of Log.d must be a String, and Java doesn't automatically call toString() to cast everything to a String in that case.
One of the common use of toString(), is print() and println() methods of PrintStream, as in:
System.out.print(object);
System.out.println(object);
Basically, these two methods will call toString() on the passed object. This is one of the Polymorphism's benefits.
Nice Question...
But,
Compiler does not call a method to match formal parameters. it simply tries to cast the objects if possible.
But when you use the "+" operator the compiler executes the toString() method of its arguments (in case they are objects) by default.
In one case you are passing an object argument to an operator which expects objects.
In the earlier case you are passing an object argument to a function which expects string.
Basically function/operator signature is different.
It is almost incidental [in the context of this question] that .tostring called when + is applied. It takes an object and does something.
For all you know, you might be passing in object when string is required by mistake. So it can't blindly do .tostring()
You are passing Configuration class object argument in case 1 but in the case 2 , you are passing string argument . so no error occures.

is it possible to get the class of the interface <Set>

Am having some arguments say (String a, Treeset b, Set c)
and I try to get the class by arguments[i].getClass(); of the above arguments..
is Iit possible to get the class of the interface <Set>.
For example:
Class[] argumentTypes = new Class [arguments.length];
for (int i = 0 ; i < arguments.length ; i++)
{
argumentTypes[i] = arguments[i].getClass();
}
The code you've given will find the classes of the arguments (i.e. the values provided to the method) - but those can never be interfaces; they'll always be concrete implementations. (You can never pass "just a set" - always a reference to an object which is an instance of an implementation of the interface, or a null reference.)
It sounds like you want the types of the parameters - which you'd get via reflection if you absolutely had to, finding the Method and then getting the parameters from that with getParameterTypes. But given that you're within the method, you already know the parameter types, because they're at the top of the method... I'm not sure the best way of finding "the currently executing" method, if that's what you're after.
If you're just trying to get the class associated with Set, you can use Set.class of course. But again, it's not really clear what you're trying to do.
EDIT: Okay, judging from your comment, there are some logical problems with what you're trying to do. Going from the values of arguments to which method would be invoked is impossible in the general case, because you've lost information. Consider this, for example:
void foo(String x) {}
void foo(Object y) {}
foo("hello"); // Calls first method
foo((Object) "hello"); // Calls second method
Here the argument values are the same - but the expressions have a different type.
You can find all methods which would be valid for the argument values - modulo generic information lost by type erasure - using Class.isAssignableFrom. Does that help you enough?
Note that you'll also need to think carefully about how you handle null argument values, which would obviously be valid for any reference type parameter...
You can use http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Class.html#getInterfaces()
You will get the class what the caller provided.
I mean,in below class you will get HashSet.
Set set=new HashSet();
System.out.println(set.getClass());
You can do this in two ways given below
Set s = new //any class that implements it for example HashSet or TreeSet etc.;
s.getClass().getName(); //This will return the name of the subclass which is refered by s.
or if in other way can do it
Set s = null;
s.getClass();//This causes NullPointer Exception

In Java void method calling

In java is there a way to call a void method from a constructor.I try something like this but get an error message that the compiler can not find symbol method printThis(java.lang.String):
public class Date{
public Date(String inString){
String s = inString;
String b;
b.printThis(s);
}
public void printThis(getString)
{
System.out.printf(System.out.printf( new SimpleDateFormat("MM/dd").format(new SimpleDateFormat("MM/dd").parse(getString) ) );
}
You want printThis(s) - the complier is looking for a printThis method on the String instance, which does not exist.
There are LOTS of errors in the code as presented. These are the ones I spotted.
public class Date{
Problem: you are missing package declaration means this will be in the default package. That's a bad idea.
Problem: you are using a class name that is the same as commonly used classes in the standard class library. That's a bad idea.
public Date(String inString){
String s = inString;
String b;
b.printThis(s);
Error: The code attempts to invoke a method in the String API called printThis(...). No such method exists. You should probably get rid of b and just call printThis(s)
Error: The code attempts to use an uninitialized local (b) and this will give a compilation error (if you "fixed" the previous error by changing the type of b to something that did have a printThis method).
Problem: It is bad practice for a constructor to invoke a method on the object being constructed if there is any possibility that it might be overridden in a subclass. The problem is that the overriding method (from the subclass) might be called on the object before the superclass initialization has completed. It is safe to call static or private methods.
}
public void printThis(getString) {
Error: There is a syntax error in the declaration. Change getString to String getString.
Problem: The choice of parameter name is (IMO) nonsensical. What is a "get string"???
System.out.printf(System.out.printf(
new SimpleDateFormat("MM/dd").format(
new SimpleDateFormat("MM/dd").parse(getString) ) );
Error: Compilation error: the parentheses don't balance.
Error: Compilation error: the first argument to printf must be a String or a Locale. In your code, the first argument in the outer call is a PrintStream instance.
Error: System.out.printf(System.out.printf( is nonsensical. You almost certainly should use just System.out.println or System.out.print. If you do use a printf method you have to supply a format string in the syntax specified in the PrintStream javadocs. (This is NOT the same as the syntax used for date formats!!!)
}
Error: missing '}' to complete class.
Problem: Your code style needs a lot of work. If you can swear on a bible that nobody else is ever going to have to read your code (!), then I suppose its OK. Otherwise, this kind of stuff is unacceptable. If this was homework, I'd dock you 50% of your marks straight off for making no attempt to get the style correct.
You have used printThis() as a method of String. If you want to print the date you might want
printThis(s);
It's not generally a good idea to use the same class name (Date) as the JDK library class
The following lines are not going to work:
String b;
b.printThis(s);
What the above code is doing is attempting to call the printThis method on the String object called b.
Since a String.printThis method does not exist, the compiler returns the error message saying that it could not find the method.
What is probably intended is the following:
printThis(s);
The above will call the printThis method of the current instance.
You're getting that error because you're trying to call printThis() on object b, which is a String. You want:
public Date(String inString) {
printThis(inString);
}
Just FYI, it's generally inadvisable to name classes the same as JDK classes (like Date). Also the assignment you're doing of inString doesn't really achieve anything. Perhaps your code is a simplification of what you're doing but I thought I'd mention it anyway.

Categories