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.
Related
According to the String.split() documentation the method returns array, so how come the following code compiles?
The retval variable inside the for loop is a String and not an array but there is no error?
public class String_Splitting_Example
{
public static void main(String args[])
{
String Str = new String("Welcome-to-Tutorialspoint.com");
System.out.println("");
System.out.println("Return Value :" );
for (String retval: Str.split("-"))
{
System.out.println(retval);
}
}
}
String.split() returns an array. It isn't assigning the result of the call to retval (notice there's no = assignment operator). Instead, the : notation means it's using a for-each loop to iterate over the array, and assigning each element in turn to retval.
As #nobalG points out there are a number of good resources on StackOverflow as well. Check out some questions tagged java and foreach.
As Jared Burrows commented, by writing for (String retval: Str.split("-")) you are iterating through each part of the array where retval contains the current String in the array of Strings you got from doing Str.split
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.
How do String objects work in Java? How does term "immutable" exactly apply to string objects? Why don't we see modified string after passing through some method, though we operate on original string object value?
a String has a private final char[] . when a new String object is created, the array is also created and filled. it cannot be later accessed [from outside] or modified [actually it can be done with reflection, but we'll leave this aside].
it is "immutable" because once a string is created, its value cannot be changed, a "cow" string will always have the value "cow".
We don't see modified string because it is immutable, the same object will never be changed, no matter what you do with it [besides modifying it with reflection]. so "cow" + " horse" will create a new String object, and NOT modify the last object.
if you define:
void foo(String arg) {
arg= arg + " horse";
}
and you call:
String str = "cow";
foo(str);
the str where the call is is not modified [since it is the original reference to the same object!] when you changed arg, you simply changed it to reference another String object, and did NOT change the actual original object. so str, will be the same object, which was not changed, still containing "cow"
if you still want to change a String object, you can do it with reflection. However, it is unadvised and can have some serious side-affects:
String str = "cow";
try {
Field value = str.getClass().getDeclaredField("value");
Field count = str.getClass().getDeclaredField("count");
Field hash = str.getClass().getDeclaredField("hash");
Field offset = str.getClass().getDeclaredField("offset");
value.setAccessible(true);
count.setAccessible(true);
hash.setAccessible(true);
offset.setAccessible(true);
char[] newVal = { 'c','o','w',' ','h','o','r','s','e' };
value.set(str,newVal);
count.set(str,newVal.length);
hash.set(str,0);
offset.set(str,0);
} catch (NoSuchFieldException e) {
} catch (IllegalAccessException e) {}
System.out.println(str);
}
From the tutorial:
The String class is immutable, so that once it is created a String object cannot be changed. The String class has a number of methods, some of which will be discussed below, that appear to modify strings. Since strings are immutable, what these methods really do is create and return a new string that contains the result of the operation.
Strings in Java are immutable (state cannot be modified once created). This offers opportunities for optimization. One example is string interning, where string literals are maintained in a string pool and new String objects are only created if the particular string literal doesn't already exist in the pool. If the string literal already exists, a reference is returned. This can only be accomplished because strings are immutable, so you don't have to worry that some object holding a reference will change it.
Methods that appear to modify a string actually return a new instance. One example is string concatenation:
String s = "";
for( int i = 0; i < 5; i++ ){
s = s + "hi";
}
What actually happens internally (the compiler changes it):
String s = "";
for( int i = 0; i < 5; i++ ){
StringBuffer sb = new StringBuffer();
sb.append(s);
sb.append("hi");
s = sb.toString();
}
You can clearly see that new instances are created by the toString method (note that this can be made more efficient by directly using StringBuffers). StringBuffers are mutable, unlike Strings.
Every object has state. The state of a String object is the array of characters that make up the String, for example, the String "foo" contains the array ['f', 'o', 'o']. Because a String is immutable, this array can never be changed in any way, shape, or form.
Every method in every class that wants to change a String must instead return a new String that represents the altered state of the old String. That is, if you try to reverse "foo" you will get a new String object with internal state ['o', 'o', 'f'].
I think this link will help you to understand how Java String really works
Now consider the following code -
String s = "ABC";
s.toLowerCase();
The method toLowerCase() will not change the data "ABC" that s contains. Instead, a new String object is instantiated and given the data "abc" during its construction. A reference to this String object is returned by the toLowerCase() method. To make the String s contain the data "abc", a different approach is needed.
Again consider the following - s = s.toLowerCase();
Now the String s references a new String object that contains "abc". There is nothing in the syntax of the declaration of the class String that enforces it as immutable; rather, none of the String class's methods ever affect the data that a String object contains, thus making it immutable.
I don't really understood your third question. May be providing a chunk of code and telling your problem is a better option. Hope this helps.
You can also look into this blogpost for more understanding
[code samples are taken from the wiki. you can also look in there for more information]
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
I have a method which reads a file and returns the contents of the text file in a list of String array. Find the implementation of the method and how I read it below. Now I want to have the number of lines in the file as well. I can get it as shown below in the comment - Can you please let me know how can I pass the integer variable as well from the method and read the integer as well?
Below - i.e read file should return List consisting of string arrays and an int as well.
public List<String[]> readFile() {
final List<String[]> userList = new ArrayList<String[]>();
BufferedReader bufferedreader = null;
try {
final String FileName="abs.txt"
bufferedreader = new BufferedReader(new FileReader(FileName));
String line = null;
while ((line = bufferedreader.readLine()) != null) {
// Add Variable ++ to get number of lines
final String[] values = line.split(",");
userList.add(values);
}
}
catch (FileNotFoundException ex) {
logError(ex.getMessage());
}
catch (IOException ex) {
logError(ex.getMessage());
}
finally {
try {
if (bufferedreader != null){
bufferedreader.close();
}
}
catch (IOException ex) {
logError(ex.getMessage());
}
}
return userList;
}
This is how I read it:
List<String[]> usersArray1 = new ArrayList<String[]>();
usersArray1=complianceTracker.readFile();
In this instance, the number of lines in your file corresponds to the number of entries in usersArray1, you can get this as usersArray1.size().
Um, you can't. Java can only return 1 object.
You could make an encapsulating object to hold both the list and the int, or you can make the list you're using untyped and add in the int at the beginning or end, or just take the string value of the int and add it at the beginning or end and parse it later.
Edit: You know what? You're trying to get the int that holds the length of the list. You don't have to do this: lists already know how big they are, and you can retrieve it with size().
You can't return a list of String that also contains an integer. There are several things that can be done to work around this:
Redefine your method to take a List<String> argument; the method fills the list and returns an int.
In the calling code, just use the size() method of List to determine the number of entries after the method returns.
Define a class that contains an int and List<String> field, and return that instead of just the List<String>.
Pass an int[] array as an argument initialized to a single element. Store the integer return value in position 0 of the array. (Requires that the array be at least 1 long when the method is called.)
There are probably other techniques people can come up with.
The simplest answer for this particular case is the one from Mark Elliott, who seems to be the only one who read what readFile() is doing. The number of lines returned is usersArray1.size().
Another minor point. (Repeating your usage example here for reference)
List<String[]> usersArray1 = new ArrayList<String[]>();
usersArray1=complianceTracker.readFile();
The first line is needlessly creating an instance of ArrayList<String[]> which will be ready to be GC'ed after the second line executes. The usersArray1 reference will then refer to the object created on the first line of the readFile() method, leaving no reference referring to the object created when usersArray1 was declared and initialized.
Create a bean.
public class ResultBean
{
private List<String> userArray;
private Integer anotherResult;
//create get set here
}
later your readFile only need to return this resultBean class.
public ResultBean readFile()
{
ResultBean bean = new ResultBean();
//your existing logic here.
bean.setUserArray(new ArrayList<String>()); //please implement your own set here. This is just an example.
bean.setAnotherResult(Integer.valueOf(0));
return bean;
}
Whenever you need to return more than one piece of data, you have two choices, sometimes used together:
Use (write, if necessary) a class wrapping the data to be returned (in this case, a List and an integer).
Pass in as an argument that can hold some of the data, and can be modified by the method at hand.
There are basically two solutions to the problem of returning two things:
Create a class that keeps the two things together (makes a lot of sense if the integer and list of strings are passed around your code a lot).
Use various tricks for returning one (or both) through the parameters, including:
Passing a variable that is a new int[1] to the function, then changing the contents of that "array" in the function and reading from it after the function.
Passing in a class that encapsulates an integer in a mutable way (like an AtomicInteger).
Passing the List object to the function and modifying it (while maintaining the same List reference).
ints are passed by value and not reference by default in java. An easy way around this is to create a small class. Try something like
public class Data
{
public List<String[]> usersArray1;
public int value;
}
you could simply pass this to your method and store both the List of string[]s in there and the int could go in there too. Hope this helps!