I'm moving into Java from a C++ background and I'm currently getting to grips with the notion of not overloading operators, as is the Java way. I'm currently trying to figure out how to handle a situation where, if I were writing in C++, I would overload operator<< for my class and call it a day.
How should this situation be handled in Java? Is there a specific procedure with specific syntax, or it is as simple as writing something like
public void PrintMyStuff( final MyClass myClass ){
System.out.print( /*MyClass member1*/ );
System.out.print( /*MyClass member2*/ );
}
I think you've answered your own question. To put a little more "ritual" and "the right way to do things" into things - the convention is for this "printing method" to be called toString(), and it should return a String - that String is then printed explicitly.
(...though I won't tattle on you if you just print in the method like you want to... especially if it's only for your own purposes...)
Here is the salient link about this convention: http://www.javapractices.com/topic/TopicAction.do?Id=55
Do you want to get a string representation of an object? If so, just override the toString() method. For example:
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(member1);
...
sb.append(member2);
return sb.toString();
}
A StringBuilder would be the closest equivalent to a std::stringstream i guess.
hth
Related
Suppose I have an application that needs to apply several custom transformation on strings. The needs will grow by time. The following two approaches do exactly the same thing, but I am wondering which one is more beneficial in the long run. Are they the same? Or, does one offer more benefits than the other as the number of transforms increase and vary?
Suppose we have these:
public static final String PL = "(";
public static final String PR = ")";
public static final String Q1 = "'";
Here is each approach's setup and usage.
Approach 1:
#FunctionalInterface
public interface StringFunction {
String applyFunction(String s);
}
public class StrUtils {
public static String transform(String s, StringFunction f) {
return f.applyFunction(s);
}
public static String putInQ1(String s) {
return Q1.concat(s).concat(Q1);
}
public static String putInParens(String s) {
return PL.concat(s).concat(PR);
}
// and so on...
}
Which I would use like this:
System.out.println(StrUtils.transform("anSqlStr", StrUtils::putInQ1));
System.out.println(StrUtils.transform("sqlParams", StrUtils::putInParens));
Approach 2:
Here, I use straightforward Function:
Function<String, String> putInQ1 = n -> Q1.concat(n).concat(Q1);
Function<String, String> putInParens = n -> PL.concat(n).concat(PR);
// and so on...
Which I would use like this:
System.out.println(putInQ1.apply("anSqlStr");
System.out.println(putInParens.apply("sqlParams");
You sketched two ways of offering a certain functionality
The first one is to explicitly offer it as a method
public static String putInQ1(String s) {
return Q1.concat(s).concat(Q1);
}
which is supposed to be used via a method reference.
The second one is to offer it as a Function object:
Function<String, String> putInQ1 = n -> Q1.concat(n).concat(Q1);
(Here, you did not say where these instances should be located. I assume that you would also create a class that contained all these Function instances as (possibly public static final fields)
JBNizet mentioned a third option: You could use the methods directly, and not via method references. Indeed, the purpose of the transform function is not entirely clear. The only justification for this would be that you want to pass in arbitrary method references there, but these method references would just be Function objects - like in the second approach...
However, in a technical sense, the difference is not so large. Just to illustrate the point: Both approaches can trivially be converted into each other! The method can be implemented based on the function object
public static String putInQ1(String s) {
return putInQ1.apply(s);
}
And a function object can be created from the method reference:
Function<String, String> putInQ1 = StringUtils::putInQ1;
So the main question may be: How do you want to offer this functionality to the user of your library?
For this, consider the use case the you have an input string, and want to put it into ( parentheses ), and the result into ' single quotes ':
String doItWithMethodReferences(String input) {
String result = input;
result = StrUtils.transform(result, StrUtils::putInParens);
result = StrUtils.transform(result, StrUtils::putInQ1);
return result;
}
String doItWithFunctionObjects(String input) {
String result = input;
result = StringFunctions.putInParens.apply(result);
result = StringFunctions.putInQ1.apply(result)
return result;
}
String doItWithMethods(String input) {
String result = input;
result = StrUtils.putInParens(result);
result = StrUtils.putInQ1(result);
return result;
}
You can see that there is hardly a difference between the approaches that would qualify one of them as "better" or "worse" than the other in terms of readability, except for the obvious fact that the last one is simpler than the first one by avoiding the unnecessary transform calls.
Of course, each of these methods could be written "more compactly", in a single line. But depending on the number and the structure of the operations, this could severely reduce the readability, and in fact, this leads to another point: I could imagine that extensibility may something to consider. Imagine you wanted to create a single operation that placed a string into '( single quotes and parentheses )' at once.
With methods:
public static String putInPandQ1(String s) {
return putInQ1(putInParens(s));
}
With functions:
Function<String, String> putInPandQ1 = putInParens.andThen(putInQ1);
I think that the andThen function would be a nice feature that helps to compose more complex string manipulations.
(But taking that arbitrarily far, one has to ask whether you are not actually attempting to implement a template engine or a new domain-specific programming language...)
A short note: All this seems fairly unrelated to performance. Whether you do return s0 + s1; or return s0.concat(s1) will often not matter, and in the few cases where it does matter, you can change the implementation later - because, given the functionality that is sketched in the question, the decision about using + or concat or some StringBuilder trickery is exactly that: An implementation detail.
And another note, as pointed out in the comments: Instead of defining your own StringFunction interface, you could use UnaryOperator<String>. Both are "structurally equal", but the first one is part of the standard API. Imagine that there are already many libraries out there, with methods that expect the standard UnaryOperator<String> as an argument. When you only have instances of your own StringFunction, then you may have to convert these instances so that your code can cooperate with other code. This is trivial, of course, but the interfaces in the functional package are carefully chosen to cover a large range of application cases, and I think that the interoperability between libraries can be greatly increased when programmers don't needlessly create new interfaces that already exist in the standard API. One could argue that the introduction of the StringFunction makes code easier, because it does not need the <String> generic parameter. But if you want this, then you should simply declare the iterface as interface StringFunction extends UnaryOperator<String> { }, which simply is a further specialization, and will keep the compatibility with other code. Additionally, you'll then conveniently inherit all the default methods from Function, like the andThen that I mentined above.
Why not simply define the method 'putInWhatever(String s, String left, String right) {
return left + s + right;
}
with overloaded variants in case left and right are equal. No complicated functional interfaces and lambda's needed
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?
I am trying to call a method defined in android activity in c++ qt using QAndroidJniObject.
here is my call in c++ class
QAndroidJniObject data = QAndroidJniObject::callStaticObjectMethod("com/android/app/appActivity",
"appData",
"(I)Ljava/lang/String;");
QString dataValue = data.toString();
qDebug() <<"Data is " << dataValue;
this appData is defined in appActiviy android class and it returns a String
this is defined method I want to call and get the returned string value
static String appData(){
Log.d("App Data is ", "Working");
return data;
}
but I am getting null is dataValue and it is not throwing any error too.
You may need to manually check exceptions to get your Java errors.
From Qt documentation:
Handling Java Exception
When calling Java functions that might throw an exception, it is important that you check, handle and clear out the exception before continuing.
Note: It is unsafe to make a JNI call when there are exceptions pending.
void functionException()
{
QAndroidJniObject myString = QAndroidJniObject::fromString("Hello");
jchar c = myString.callMethod<jchar>("charAt", "(I)C", 1000);
QAndroidJniEnvironment env;
if (env->ExceptionCheck()) {
// Handle exception here.
env->ExceptionClear();
}
}
Are you sure you want to be calling com/android/app/appActivity and not com/android/app/Activity?
Here are some thoughts:
Have you used Log.d() to print the string before return making sure it is not null?
Not sure it matters, but you are specifying an integer as argument, but the Java method does not have that in its signature. You should then provide this integer as a parameter in callStaticObjectMethod().
As mentioned by Alex P, exceptions have to be handled or they will give you a headache as they might happen quite often and crash the entire application.
I can not find any class at com/android/app/appActivity in the Android documentation. Did you mean com/android/app/Activity? If so, I can't find a method named "appData" here.
Thanks guys for your answer, finally I figured it out. It was way simple then I was trying
QAndroidJniObject data = QAndroidJniObject::callStaticObjectMethod("com/android/app/appActivity",
"appData",
"(I)Ljava/lang/String;");
In this code I was not aware that this(I)Ljava/lang/String; means type of parameter your Java method is accepting but in my case there were none. So the correct answer is
QAndroidJniObject data = QAndroidJniObject::callStaticObjectMethod<jstring>("com/android/app/appActivity",
"appData")`
denotes return type of my defined java method.
I guess it was silly mistake from my end...thanks again
I have the same problem today. Although it is different from your code, but the return value is also NULL.here is my code:
package org.test.project.test;
public class TestJava {
public static String notify(int iNumber )
{
String strNum = iNumber+"";
return strNum;
}
}
and then the c++ code:
QAndroidJniObject str = QAndroidJniObject::callStaticObjectMethod("org/test/project/test/TestJava",
"notify",
"(I)Ljava/lang/String;",
m_iNumber);
//the str always been NULL
Right now I'm trying to implement this interface with an int which represents a binary number.
I know I shouldn't implementto string(); , but Let's assume that I need to.
This is what I wrote so far:
public class IPAddressInt implements IPAddress {
private int ipAdress;
public IPAddressInt(int num1,int num2, int num3, int num4){
String n1=Integer.toBinaryString(num1);
String n2=Integer.toBinaryString(num2);
String n3=Integer.toBinaryString(num3);
String n4=Integer.toBinaryString(num4);
String finalString=n1+n2+n3+n4;
this.ipAdress=Integer.parseInt(finalString);
}
public String toString() {
return this.toString();
}
when I'm tring to return this.ipAdress.toString(); or even ipAdress.toString()
the compiler says that it Cannot invoke toString() on the primitive type int,
and when I write only this.toString(); it works. why? I know that an int can be converted to a string, and how come the this works and the whole statement is not? shouldn't it be the same? will I get what I want anyway?
Thank you.
Calling this.toString() is just going to blow up - it's calling the same method recursively, with no exit.
The reason you can't call toString directly on ipAddress is that int is a primitive type, and you can't call methods on primitive types.
To convert anything to a string, use String.valueOf(ipAddress). For int in particular, you could use Integer.toString(ipAddress).
It's not really clear why you're doing the conversion to a binary string in the first place though... that doesn't look like a good idea to me. Any reason why you're not using
ipAddress = (num1 << 24) | (num2 << 16) | (num3 << 8) | num4;
(assuming each value is really in the range 0-255).
I highly doubt that the binary representation is really want you want, particularly given the lack of padding, and that you're then trying to parse it as a decimal number.
When you say "it works" I suspect you mean "it compiles". If you actually call that toString method you'll get a stack overflow, or maybe just an infinite loop if your compiler/JVM is very clever.
To convert an int to a string, call Integer.toString(this.ipAdress). (But preferably spell address correctly :-).)
[EDITED to add: after writing this I see that in another answer Jon Skeet prefers String.valueOf rather than Integer.toString for this purpose. He's a very smart chap and probably has a good reason. It'll mean less has to change if you change the type of ipAddress -- er, I mean ipAdress, for instance.]
What you want is probably to implement the toString method like this:
public String toString()
{
return Integer.toString(ipAdress);
}
What the compiler says is true because you cannot invoke ANY methods on primitive types. You have to wrap the primitive int into an Integer which has the method toString implemented. The code snippet above is just a more effective way of calling:
return Integer.valueOf(ipAdress).toString();
Your toString method is recursively calling itself and will end up in a stack overflow exception.
Try converting ipAdress to a String like this:
public String toString() {
return Integer.toString(ipAdress);
}
FYI, your variable ipAdress has a typo, should be ipAddress.
I want to ask you about the print vector array , the following one:
Vector[] routingTable = new Vector[connectivity.length];
I tried this method , but it doesn't work with me and it gives me protocol.Route#c17164
when I printed in the main, here is the code, so can you tell me why it doesn't print the correct value ?
public String printRT(int hop)
{
String s = "";
for (int i = 0; i < conf.routingTable[hop].size(); i++)
{
s= " ROUTING TABLE " + conf.routingTable[hop].get(i);
}
return s;
}
it looks like you need to implement the toString() method in protocol.Route.
class Route {
public String toString() {
return "some string that makes sense";
}
}
Either override the toString() method on the protocol.Route class, or get the desired properties from the Route object and append them to the String s inside your printRT method.
Many helpful suggestions, but I think everyone is overlooking something very simple- in each loop iteration you are overwriting the value of s. I think you mean to say something like the following instead:
s += " ROUTING TABLE " + conf.routingTable[hop].get(i);
Note the "+=" rather than simple assignment. Or use a StringBuilder, or whatever.
When you ask java to print an object for which no toString method is defined, then it will fall back on the default toString implementation in the Object class. From the javadocs:
The toString method for class Object
returns a string consisting of the
name of the class of which the object
is an instance, the at-sign character
`#', and the unsigned hexadecimal
representation of the hash code of the
object. In other words, this method
returns a string equal to the value
of:
getClass().getName() + '#' + Integer.toHexString(hashCode())
In your example 'protocol.Route' would be the class name and 'c17164' is whatever the hashcode method returns as a hexString, which, unless hashCode has been overwritten, is probably the address of the object, although this is implementation dependent.
So, there are a few ways to fix your problem.
Write your own implementation of the toString method for the Route class that prints out the data you want. This is probably the most "correct" way to fix your problem. It keeps things nicely encapsulated within the class, meaning only the toString method inside of the class needs to know about the exact member variables that are to be printed.
If the situation is such that you cannot change the Route class, you could subclass your own version of the Route class that you could add a toString method to. However, depending on the design of the class, this may be difficult.
Have the current printRT method look inside each Route object and get the specific information that you want to append to the current string.
Also, note that with the current code, you have written the following in the inner loop:
s= " ROUTING TABLE " + conf.routingTable[hop].get(i);
This means that printRT will only return a string for the very last iteration of the loop. So most of the time in the for loop is spent creating strings, assigning them to a variable and then overwriting them the next time through the loop.
If you want to return a string representation for every iteration, you will need to change the above to something like the following:
s += " ROUTING TABLE " + conf.routingTable[hop].get(i);
Now the new information is being appended to s every time through the loop. However, depending on the number of string concatenations being performed, the StringBuilder class may be a better alternative (see a short summary and tutorial on it here).
Two options.
Either override the toString() method on the protocol.Route class.
public String toString() {
return someMethodorPropertyThatreturnsString;
}
or get the desired properties/methods from the Route object and append them to the String s inside your printRT method.
public String printRT(int hop)
{
String s = "";
for (int i = 0; i < conf.routingTable[hop].size(); i++)
{
s= " ROUTING TABLE " + conf.routingTable[hop].get(i).someMethodorPropertyThatreturnsString;
}
return s;
}
There are a number of issues here.
You should be specifying a type to put in your List with Generics. That way, you will make it more obvious to yourself and others what you are putting into and taking out of your List.
As mentioned by others, your List is a list of protocol.Route objects, not Strings. When you try to add a Route to s, Java doesn't know how to convert it into a String, so it uses the default Object#toString(). Override it in Route to do what you want.
It looks like you'll potentially be doing a lot of appending here. Use a StringBuilder.
It looks to me like printRT(int) should be a method inside of whatever conf is.
You should probably be using a different implementation of List; Vector is not really recommended to use anymore, so take a look at other options like ArrayList.