Java Passing Variables and returning value - java

I am having trouble with passing some variables through a method and then having that method return a value. The checkValue method is supposed to look at each of the array items in the orderSplit array and if there is an error with them, return an error message, if not it will return an empty errorMessage. But as of right now the program doesn't seem to be executing the method at all. Any suggestions?
Here is an example of my code:
public class Foo {
public static void main(String args[]) {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String order = null;
try {
order = br.readLine();
} catch (IOException exc) {
System.out.println("ERROR: A Problem has occured");
}
String[] orderSplit = null;
orderSplit = order.split(" ");
String errorMessage = "";
checkValue(orderSplit, errorMessage);
if (errorMessage == "") {
System.out.println("SUCCESS");
}
}
public static String checkValue(String[] orderSplit, String errorMessage) {
// check the ordersplit values
return errorMessage;
}
}

You don't assign the result of the method to anything. Change your code to:
String errorMessage = checkValue(orderSplit);
And not that the checkValue method doesn't need any error message as argument. It will create one by itself and return it to the caller.
Also, assigning null to a variable you reassign immediately after, like this:
String[] orderSplit = null;
orderSplit = order.split(" ");
is unnecessary. You just need
String[] orderSplit = order.split(" ");
And you should never compare Strings with ==. == tests if two variables reference the same String object. You should use the equals() method, which tests if two Strings contain the exact same sequence of characters:
if (errorMessage.equals("")) {

You aren't assigning the return value of checkValue anywhere, only returning its parameter. Try changing
String errorMessage = "";
checkValue(orderSplit, errorMessage);
to
String errorMessage = "";
errorMessage = checkValue(orderSplit, errorMessage);
Good luck

java.lang.String is immutable. So whatever you do to errorMessage inside your method will not be visible outside the method, as essentially you are creating new String objects.
You should really check the return value from the method as other answers suggest.

The code above just assigns "" to the errorMessage variable and returns a reference to string "". This in and of itself does nothing.
I am assuming you have some code that assigns a different value to errorMessage in checkVlaue method. There are some caveats to this. Strings are immutable in java. In your message signature the value being passed is a value containing the reference to contents of errorMessage at the time of the call to checkValue. If you attempt to assign another value to this variable inside checkValue and return it you are actually returning a value that is the reference to a different string object. Once you return to the calling method printing errorMessage will print "" because this is the string object that errorMessage in the calling method still points to. If you changed your call to the following:
String errorMessage = checkValue(orderSplit);
You now are assigning the reference value that is returned from checkedValue toerrorMessagein the calling method. This will now print whatever the result ofcheckValue` was.
The net out is to remember that even though most things in java are object references(pointers) that all method signatures are actually pass by value. When you re-assign you are not changing what a pointer points to, but rather are assigning a new pointer to a variable all together.

Related

The thinking about String class's API

The following codes are based on Java.
Here, the famous method "toUpperCase()", can be invoked like this:
String s = new String("abc");
String ss = s.toUpperCase();
//result: ss = "ABC"
For this: s.toUpperCase() We didn't pass a value to the method, so this method cannot has a meaningful return value.
To explain what is called a not-meaningful return value, here is an example:
//not pass a value to the method
String toUpperCase(){
...
return ???;
}
As above, the return value has no relationship with that object called "s". (the invoking of a non-parameter method is often independent from the objects). If I invoke this non-parameter method: String ss = s.toUpperCase(); how can that return a value that has any relationship with the object "s"
And the following is called meaningful:
//pass a value to the method
static String toUpperCase(String str){
.... //to change the "str" into uppercase
return str;
}
Now I can invoke the method toUpperCase() like this:String ss = String. toUpperCase(s);
Since I pass the "s" (its address) to the method, I can do anything I wish to change the object and return a meaningful return value.
Based on the above, I have a reasonable doubt about this method s.toUpperCase(). since it cannot return a meaningful return value.
First, terminology. s is an instance.
how can that return a value that has any relationship with the object "s"
Do you understand this? For example, how does dog.getName() return a "meaningful value" of the name of that dog instance?
The char[] of the String object named s is stored within that instance, much like the String name of a Dog object.
class Dog {
String name;
public String getName() { return name; } // or 'return this.name;'
}
Bonus: Source code of toUpperCase() implementation, which does make a call to Character.toUpperCase(c) because char primitives to not have a toUpperCase method themselves.

How does String works as Object in Java

I am quite confused with how Object works in Java since I run into this problem.
Let's say I have a function called checkDateValue (code looks like this)
private boolean checkDateValue(Date d1, String msg) {
if (d1 == null) {
msg = "d1 is null!";
return false;
}
return true;
}
Here is the place I call this function:
String msg = null;
Date d1 = null;
if (!checkDateValue(d1, msg)) {
system.println(msg); //msg is still null.....
//what I need is the message generated in the function
}
As far as I know, if I put a customized Object
(e.g.
myObj { private String msg;}
)
into a function, and we change the value of msg inside the function, when we get out of the function, the change of msg is kept. However, I think String is also considered as an Object in java. Why the change is not kept?
Java doesn't have "out" function arguments; they are copies of references.
Even though you change msg in the function, it does not affect the caller's variable.
String is special, is immutable and is diffrent from normal Object.
Java's String is designed to be in between a primitive and a class.
String is passed by value, but unfortunately every change on String make new value, so your old reference has old value.
I think this is good explanation: https://stackoverflow.com/a/1270782/516167
In Java, you cannot pass back a value to calling code by assigning to a method parameter. You are right that you can alter the internal structure of any parameter and that change will be seen in the calling code. However, assigning to a parameter is not the same thing as altering the internal structure. Also, a String is immutable—once created, its internal structure cannot be altered.
A common trick to do what you what is to use an array argument:
private boolean checkDateValue(Date d1, String[] msg) {
if (d1 == null) {
msg[0] = "d1 is null!";
return false;
}
return true;
}
Then call it like this:
String[] msg = new String[1];
Date d1 = null;
if (!checkDateValue(d1, msg)) {
system.println(msg[0]);
}
This is related to the fact that
Java passes objects as references passed by value.
You can't change the reference argument to point to something else. You can change the object state.
You can read more here
msg = "d1 is null!"; and msg=null are two different String objects. Strings are immutable in Java.The reference is passed by value, i.e., a copy of the reference is passed. and since a String is immutable object , the assignment inside the method creates a new String object that the copy of the reference now points to. The original reference still points to the null String. Your method call is same as :
Object obj = null; // obj points to nowhere
foo(obj); // passed the reference values to method argument
void foo(Object o)
{
o = new Object( ); // o points to new Object, but obj still points to nowhere
}
if (!checkDateValue(d1, msg))
{
system.println(msg);
}
when you call checkDateValue method a reference String msg = null;
Date d1 = null; to the method
is passed which is pass by value. When method gets executed then
msg variable in checkDateValue will get referenced to "d1 is null!"
Here, msg variable in call remains same

Why is this string tokenizer making me cast to string?

I Think I broke this down to the most basic form. If not then I apologize and will try to edit it. Why in my while loop do I need to cast String for the FirstName if I already set the variable to be a String? Am I doing something wrong? I am try to set the FirstName variable to be equal to the first token which is supposed to be the first word of the text file etc.
try
{
BufferedReader infileCust =
new BufferedReader(new FileReader("C:\\custDat.txt"));
}
catch(FileNotFoundException fnfe)
{
System.out.println(fnfe.toString());
}
catch(IOException ioe)
{
System.out.println(ioe.toString());
}
}
public static void createCustomerList(BufferedReader infileCust,
CustomerList custList) throws IOException
{
String FirstName;
String LastName;
int CustId;
//take first line of strings before breaking them up to first last and cust ID
String StringToBreak = infileCust.readLine();
//split up the string with string tokenizer
StringTokenizer st = new StringTokenizer(StringToBreak);
while(st.hasMoreElements()){
FirstName = (String) st.nextElement();
LastName = (String) st.nextElement();
CustId = Integer.parseInt((String) st.nextElement());
}
Edit: Apprently I can use nextToken() instead. But how come my variables are being shown as not used? Are they not within the scope of the while loop?
This is because nextElement returns Object. If you call nextToken, you would not need to cast.
From the documentation:
public Object nextElement()
Returns the same value as the nextToken method, except that its declared return value is Object rather than String. It exists so that this class can implement the Enumeration interface.
EDIT Regarding the variables that are not used: the reason you get the warning is that the variables are assigned, but not printed, saved, or analyzed in some way. If you add a call to, say, writeln with first and last name, the warnings would go away.
Because StringTokenizer.nextElement returns a java.lang.Object. See the docs here: http://docs.oracle.com/javase/1.4.2/docs/api/java/util/StringTokenizer.html You can use nextToken() : String instead if you prefer.
Because StringTokenizer.nextElement() returns
The same value as the nextToken method, except that its
declared return value is Object rather than String.It exists so that this class can implement the Enumeration interface.

Replace a character at a specific index in a string?

I'm trying to replace a character at a specific index in a string.
What I'm doing is:
String myName = "domanokz";
myName.charAt(4) = 'x';
This gives an error. Is there any method to do this?
String are immutable in Java. You can't change them.
You need to create a new string with the character replaced.
String myName = "domanokz";
String newName = myName.substring(0,4)+'x'+myName.substring(5);
Or you can use a StringBuilder:
StringBuilder myName = new StringBuilder("domanokz");
myName.setCharAt(4, 'x');
System.out.println(myName);
Turn the String into a char[], replace the letter by index, then convert the array back into a String.
String myName = "domanokz";
char[] myNameChars = myName.toCharArray();
myNameChars[4] = 'x';
myName = String.valueOf(myNameChars);
String is an immutable class in java. Any method which seems to modify it always returns a new string object with modification.
If you want to manipulate a string, consider StringBuilder or StringBuffer in case you require thread safety.
I agree with Petar Ivanov but it is best if we implement in following way:
public String replace(String str, int index, char replace){
if(str==null){
return str;
}else if(index<0 || index>=str.length()){
return str;
}
char[] chars = str.toCharArray();
chars[index] = replace;
return String.valueOf(chars);
}
As previously answered here, String instances are immutable. StringBuffer and StringBuilder are mutable and suitable for such a purpose whether you need to be thread safe or not.
There is however a way to modify a String but I would never recommend it because it is unsafe, unreliable and it can can be considered as cheating : you can use reflection to modify the inner char array the String object contains. Reflection allows you to access fields and methods that are normally hidden in the current scope (private methods or fields from another class...).
public static void main(String[] args) {
String text = "This is a test";
try {
//String.value is the array of char (char[])
//that contains the text of the String
Field valueField = String.class.getDeclaredField("value");
//String.value is a private variable so it must be set as accessible
//to read and/or to modify its value
valueField.setAccessible(true);
//now we get the array the String instance is actually using
char[] value = (char[])valueField.get(text);
//The 13rd character is the "s" of the word "Test"
value[12]='x';
//We display the string which should be "This is a text"
System.out.println(text);
} catch (NoSuchFieldException | SecurityException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
You can overwrite a string, as follows:
String myName = "halftime";
myName = myName.substring(0,4)+'x'+myName.substring(5);
Note that the string myName occurs on both lines, and on both sides of the second line.
Therefore, even though strings may technically be immutable, in practice, you can treat them as editable by overwriting them.
First thing I should have noticed is that charAt is a method and assigning value to it using equal sign won't do anything. If a string is immutable, charAt method, to make change to the string object must receive an argument containing the new character. Unfortunately, string is immutable. To modify the string, I needed to use StringBuilder as suggested by Mr. Petar Ivanov.
You can overwrite on same string like this
String myName = "domanokz";
myName = myName.substring(0, index) + replacement + myName.substring(index+1);
where index = the index of char to replacement.
index+1 to add rest of your string
this will work
String myName="domanokz";
String p=myName.replace(myName.charAt(4),'x');
System.out.println(p);
Output : domaxokz

reflection type checking?

I'd like to find a way to dynamically check if string is parse-able into a given type.
in other words,
public boolean canBeParsed(String type, String val) {
// use reflect to check if val can be parsed into type
}
clearly, I'd like to be able check different types with different values..
types will be strings like : Java.lang.Integer
---------- addition -------------
so for example, if I call this function,
canBeParsed("Java.lang.Integer", "1"); //returns true
canBeParsed("Java.lang.Integer", "HelloWorld"); //returns false
canBeParsed("Java.lang.String", "HelloWorld"); //returns true
canBeParsed("Java.lang.Boolean", "false"); // returns true
canBeParsed("Java.lang.Boolean", "HelloWorld"); //returns false
This method works with classes which declare a static valueOf method. Any class without this will return false. Several exceptions have been omitted to keep the code short.
Class<?> cls = Class.forName(type);
//Get a converter method, String to type
//Requires static method valueOf
Method converter;
try{
converter = cls.getDeclaredMethod("valueOf",new Class[]{String.class});
}catch(NoSuchMethodError ex){
//No conversion method found
return false;
}
if(!Modifier.isStatic(converter.getModifiers()){
//the method has to be static in order to be called by us
return false;
}
if(!cls.isAssignableFrom(converter.getReturnType())
//The conversion method has the wrong return type
return false;
try{
//try to parse the value
Object o = converter.invoke(null,new Object[]{value};
if( o == null)return false;//false if method returned null
else return true;//success
}catch(Exception ex)
{
//could not parse value
return false;
}
The valueOf(String) method is present in the wrapper classes Short,Long,Integer,Float,Double,Boolean so it supports these and any other class which has this method.
A dynamic type check is something different from what you are asking. With a dynamic check you check if an obect is an instance of a specific type (basically sametype or narrower type will be allowed) and you can do it with the instanceof operator. But this involves the object hierarchy and not the "can be converted to" concept that you would like to have. You can try with string instanceof Integer but this will be ALWAYS false.
In your situation you want to check if a string rapresents an integer number and you should do it in a different way:
try {
int number = Integer.parseInt(string);
}
catch (NumberFormatException e) {
System.out.println("String is not an integer string!");
}
Otherwise you could define a regex for every type and check what the string contains through it:
if (string.matches("[1-9][0-9]*"))
...
In anycase, since a String is just a string type and nothing else, the RTTI won't help you here. The string itself is orthogonal with every other type (int, float, whatever) also if it rapresents the textual version of another type.
A solution can be found if you can modify the source string types, in this case you could define for example an
class IntString extends String {
IntString(int i) {
super(Integer.toString(i));
}
}
then you could check if string instanceof IntString but this would work only if the strings are built with their specific type eg String s = new IntString(20).
Your easiest solution is probably a switch statement, with one case for each type that you want to support.
public boolean canBeParsed(String type, String val)
{
switch(type) {
case "Java.lang.Integer" : return(tryParseInteger(val) != null);
case ...
}
public static Integer tryParseInteger(String text) {
try {
return new Integer(text);
} catch (NumberFormatException e) {
return null;
}
}
In C# this would be easier, as there is an actual TryParse() method for each numeric type, and it's not necessary to catch an exception to test it.

Categories

Resources