List Iterator - Not working - java

I've below code:
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class IteratorExample {
public static void main(String[] args) {
List<String> listnames = new ArrayList<String>();
listnames.add("Tom");
listnames.add("Finn");
listnames.add("Harry");
ListIterator<String> iteratorNames = listnames.listIterator();
while (iteratorNames.hasNext()) {
System.out.println(iteratorNames);
}
}
}
When I execute, I am getting strange output like below(which differs everytime when I run the program):
java.util.ArrayList$ListItr#a200d0c
java.util.ArrayList$ListItr#a200d0c
java.util.ArrayList$ListItr#a200d0c
java.util.ArrayList$ListItr#a200d0c
java.util.ArrayList$ListItr#a200d0c
Also the program is running infinitely.
Why it is not printing the list values?

You're looking at the iterator itself.
use
iteratorNames.next()
to get the next item.

Change the below line:
System.out.println(iteratorNames);
To:
System.out.println(iteratorNames.next());

I am getting strange output like below
It's just printing the memory adress of the object using the toString() default implementation of the object class.
public String toString() {
return getClass().getName() + "#" + Integer.toHexString(hashCode());
}
Also the program is running infinitely.
As other answers stated, you have to use next()(i.e System.out.println(iteratorNames.next());) for two reasons :
It allows you to get the element in the list while iterating it
It advances the cursor position of the iterator
That's why your program runs indefinitely, because the cursor is still on the first position on your list, so hasNext() will always returns true.
Using next() the program looks like :
while (iteratorNames.hasNext()) {
String element = iteratorNames.next(); //now you can do what you want with this element
System.out.println(element);
}

Others have already mentioned how you use an Iterator--by querying it to see if it has a next value and then grabbing it via next() if it does.
However, you have the option of avoiding those low-level details altogether through a nice syntactic abstraction:
for (String name : listnames) {
System.out.println(name);
}
Give it a shot. In my opinion, it was one of the most helpful features of Java 5. Here is more information on it.

In your program System.out.println(iteratorNames); it will call toString() of Object class that will returns a string representation of the object (see implementation on toString())
public String toString() {
return getClass().getName() + "#" + Integer.toHexString(hashCode());
}
That is why you are getting output like java.util.ArrayList$ListItr#a200d0c.
call next() It will returns the next element in the list. as follows:
System.out.println(iteratorNames.next());

use,
System.out.println((String)iteratorNames.next());

Related

How to detect a string within an ArrayList with a for each loop?

public String searchNumber(String name){
String result = "";
for(Person search: person){
if(search.getName().contains(name)){
result += search.getNumber();
}
else{
result = " number not known ";
}
}
return result;
}
Looking for some advice here on how to fix this problem I am having. This is a method which I expect to use my getName method to see if the local instance (name) is within the ArrayList. However, I am only getting the latter result to display only, saying "number not known." My step-by-step process goes like this: I create an instance of Person (search), access the getName method, access the contains method since it is originally a String method, and then check to see if the local instance is within the arrayList. If my logic is incorrect, please correct me. Also, does accessing the person array prevent me from using a String type in my for-each loop, since it is a Person object? I tried do this with a String type, but could not continue further since I could not convert to a String within the for-each loop.
Here's a breakdown of your current code:
You consider every object in the person list. If that person's name matches the parameter, you get the number from it. Otherwise, you set result to the error message. Note that the otherwise clause is applied for EACH person, instead of at the end if NOBODY was found to have the same name. That is, even if you find the right person and assign result to their number, if the next person isn't correct then you overwrite result to the error message again.
To make sure the error message is only assigned once and only if NOBODY is found, you need to check whether that is true after going through everyone (since you can't know if nobody is found before checking everyone!). The trick now is to find some clause which is always true when nobody was found. But that can just be if result was never modified. That is, you can set result to the default value at declaration, then only modify it to a number if the right person was found. Also, I am assuming that only one person should be found and you don't want to actually concatenate the numbers together (which is what you are doing by using +=). That said, try this:
public String searchNumber(String name){
for (Person search: person){
if (search.getName().contains(name)){
return search.getNumber();
}
}
return " number not known ";
}
Basically you can just return after finding your record
String notFound = " number not known ";
for(Person search: person){
if(search.getName().contains(name)){
return search.getNumber();
}
}
return notFound;
String result = null;
for(Person search: person){
if(search.getName().contains(name)){
result += search.getNumber();
}
}
if(result == null){
result = "number not known ";
}
return result;
Since there is no way to tell the last element in for-in loop, so the alternative is basing on result == null

Runtime problems in TestNG asserts

I have a TestNG assertion which may occasionally fail due to the state of the object asserted (ArrayList element), and when it does, I would like to display this state.
I created an example which will fail in runtime, to illustrate the concept
import static org.testng.Assert.assertEquals;
#Test
public void sandbox() {
ArrayList<Integer> arr = new ArrayList<>();
assertEquals(arr.size(), 0, "The problem is: " + arr.get(0).toString());
}
I expected the assertion to pass and it will, when I remove the third argument (message). I see it's not a TestNG issue as execution is not stepping in the statement, but rather fails directly at this step with
at java.util.ArrayList.rangeCheck(ArrayList.java:657)
at java.util.ArrayList.get(ArrayList.java:433)
What's the best approach here? I am thinking of a method which will take care of the exception, but perhaps there are better known ways.
Thanks
Below should work:
import static org.testng.Assert.assertEquals;
#Test
public void sandbox() {
ArrayList<Integer> arr = new ArrayList<>();
assertEquals(arr.size(), 0, "The problem is: " + arr);
}
This is more practical as well, because if list is not empty it will print all values from the list instead of the first.
There is no other pretty way of doing it since all your arguments are passed at once to the callee, i.e. your method, so that the arr.get(0) must have been evaluated.
You may simply call for the next() element only if there is one using the Iterator over your collection:
#Test
public void sandbox() {
ArrayList<Integer> arr = new ArrayList<>();
Iterator<Integer> it = arr.iterator();
assertEquals(arr.size(), 0, "The problem is: " + (it.hasNext() ? iterator.next() : ""));
}

Convert logger.debug("message: " + text) to logger.debug(message: {}", text)

I am trying to find the best way to address the issue of redundant string concatenation caused by using code of the following form:
logger.debug("Entering loop, arg is: " + arg) // #1
In most cases the logger.level is higher than debug and the arg.toString() and the string concatenation are a waste that user up cpu cycles and briefly use up memory.
Before the introduction of varargs the recommended approach was to test the logger level first:
if (logger.isDebugEnabled())
logger.debug("Entering loop, arg is: " + arg); // #2
But now the preferred form is
logger.debug("Entering loop, arg is: {}", arg); // #3
It is not very difficult to prefix each logger.debug with if (logger.isDebugEnabled()) (and its equivalent for the other methods) in a script, but I am trying to find the best way to convert the first form to the third.
Any suggestions? The challenge is to insert the correct number brace pairs {} in the format string. I wish logback would append the remaining arguments not covered by the placeholder at the end but I cannot find a reference that it does that.
As an alternative, I am thinking to write a class Concatenator as pasted at end and convert the first form to
logger.debug(new Concatenator("Entering loop, arg is: ", arg)); // #4
The Concatenator class delays the call to arg.toString() and string concatenation until the logger calls toString(), thereby avoiding both if the logger is at a higher filter level. It does add the overhead of creating an Object[] and a Concatenator but that should be cheaper than the alternative.
Questions:
I think this conversion (#1->#4 -- replace + with , and enclose in new Contatenator(...)) is much easier. Is there something I am missing?
Am I correct that #4 is much better than #1?
public class Concatenator {
final Object[] input;
String output;
public Concatenator(Object... input) {
this.input = input;
}
public String toString() {
if (output == null) {
StringBuffer b = new StringBuffer();
for (Object s : input) b.append(s.toString());
output = b.toString();
}
return output;
}
public static void main(String args[]) {
new Concatenator("a", "b", new X());
System.out.println(new Concatenator("c", "d", new X()));
}
}
class X {
public String toString() {
System.out.println("X.toString");
return super.toString();
}
}
Unfortunately your approach isn't going to change anything. In fact, it introduces an additional object instantiation/allocation (your Concatenator). You're also using StringBuffer which introduces synchronization overhead you don't need.
The problem is the method signature for SLF4J's Logger.debug() calls. The first argument is always a String. This means you're going to have to call:
logger.debug(new Concatenator("Entering loop, arg is: ", arg).toString());
which means ... you're doing exactly the same thing as Java is going to do, but with more overhead.
The Java compiler handles the String concatenation operator (+) by creating a StringBuilder and doing exactly what you're doing in your Concatenator class on toString().
logger.debug("Entering loop, arg is: " + arg);
becomes:
logger.debug(new StringBuilder()
.append("Entering loop, arg is: ")
.append(arg).toString());
(If you use javap to look at the generated bytecode, you'll see that's the case.)
So, your current approach is going to be more expensive than what you have now.
Edit: So, the way you could make this work is by doing ...
logger.debug("{}", new Concatenator("Entering loop, arg is: ", arg));
This way your Concatenator is passed as an Object and its toString() not called unless the logger needs to. Also, replace the StringBuffer in your class with StringBuilder.
And if I didn't answer your question directly ... is this better than the original? Probably; The string concatenation isn't occurring unless it needs to. You are, however, introducing an object instantiation/allocation. The only real way to see the differences would be to profile it / write a benchmark.

What to return when printing out Objects using the toString method and a for each loop?

I currently have a toString method, similar to the one below. Please ignore that the Objects are only temporarily named. I have done this so that there is no confusion between the types of each variable etc.:
#Override
public String toString() {
for(Object object : ArrayList) {
System.out.println("This object is a " + object.getVariableA() + " and a " + object.getVariableB() + ".");
}
return null;
}
However the toString method requires me to return a value. I would obviously just want to return the Strings that I'm printing, although if I place a return statement there, it will only print one Object and not all of the ones I am looping through. What would be the best way to print all these values and not simply return null as I don't want this printing out after all the Objects? I also want to ensure that each of these Objects are printed on separate lines like they currently are so please don't suggest solutions that include one long joined String without line breaks as this is not suitable in this situation.
Thanks in advance!
toString shouldn't output anything at all. Its job is to return an appropriate string representation of the relevant object, not to output that representation anywhere. That's outside its problem domain.
Instead, build and return a string (probably by using a StringBuilder).
E.g., something like:
#Override
public String toString() {
StringBuilder sb = new StringBuilder(some_appropriate_size);
for(Object object : ArrayList) {
sb.append("This object is a ")
.append(object.getVariableA())
.append(" and a ")
.append(object.getVariableB())
.append(".\n");
}
return sb.toString();
}
I also want to ensure that each of these Objects are printed on separate lines like they currently are so please don't suggest solutions that include one long joined String as this is not suitable in this situation.
The above puts the items from the array list on separate "lines" (via the \n). But "one long joined String" is the only appropriate thing for toString to do. If you want a different result, you must use a different method, rather than breaking the contract of toString.
You could create a String and add what you want each iteration:
#Override
public String toString() {
String result = "";
for(Object object : ArrayList) {
result += "This object is a " + object.getVariableA() + " and a " + object.getVariableB() + ".\n");
}
return result;
}
Don't forget to add the "\n" new-line character, so you print each "partial result" in one different line.
You state in your question that:
I also want to ensure that each of these Objects are printed on separate lines like they currently are so please don't suggest solutions that include one long joined String as this is not suitable in this situation.
Then you probably shouldn't be using toString(); that's not what's it's for. It is for returning a single string that is some representation of the object. It should never be outputting anything.
Add a getter to your class that returns the List of objects, output them as you would like. If you really wanted to make the class self-printing, add a print(OutputStream os) method that takes the supplied OutputStream (or maybe a PrintStream instead) and will do so.

values in queue Java

If I have a queue with strings as values How would I print all the values I was using:
System.out.println(queue.elements().toString().);
But it prints java objects...?
Do I have to use a loop to print values of queue?
Yes, you will need to use a loop however the loop can be simple like.
for(String s : queue) {
System.out.println(s.toString());
}
Actually, as long as it implements Iterable you should be able to do this type of foreach loop.
I don't understand your question. You say you want to print strings, and then after some code that doesn't compile, you say, "But it prints java objects...?" Strings are Java objects.
import java.util.*;
public class Foo {
public static void main(String[] args) {
Queue<String> queue = new LinkedList<String>(); // create queue
for (String name : args) queue.add(name); // add strings to queue
System.out.println(queue); // print entire queue at once
for (String s : queue) System.out.println(s); // print each separately
}
}
Run with e.g., java Foo apple banana pear. The output is:
[apple, banana, pear]
apple
banana
pear
If the problem is that you are getting output like this:
[MyObject#498b5a73, MyObject#5bdf59bd, MyObject#247cb66a]
MyObject#498b5a73
MyObject#5bdf59bd
MyObject#247cb66a
Then your Queue does not actually hold Strings, and you have forgotten to override the toString() method in your class:
#Override public String toString() {
return firstName + " " + lastName + ", " + quest + ", " + favoriteColor;
}
There is no need to use a loop, unless you don't [like, this, output, format].
The answer depends on the type of queue.
If it is a Queue or Deque, then your code won't compile, because these interfaces don't define an elements() method. This applies to most of the classes that implement Collection.
If it is a Vector, then the elements() returns an Enumeration, and you have to use a loop to pull the values from it.
My advice would be:
Stop using Vector ... unless you have no choice. Vector is a legacy class. Use one of the implementations of Queue or Deque instead.
Whether or not you use Vector, use queue.toString() rather than queue.elements().toString() to render the queue contents as a String. The toString() method is defined as rendering the elements of the collection for all of the standard collection classes.
Try this:
Enumeration e = queue.elements();
while ( e.hasMoreElements() )
System.out.println( e.nextElement() );
Look at Joiner in guava.
System.out.println(Joiner.on("\n").join(queue.elememts()));
try this
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
public class Main {
public static void main(String[] args) {
Queue myQueue = new LinkedList();
myQueue.add("A");
myQueue.add("B");
myQueue.add("C");
myQueue.add("D");
List<String> myList = new ArrayList<String>(myQueue);
for (Object theFruit : myList)
System.out.println(theFruit);
}
}
Java 1.8+ solution:
queue.forEach(System.out::println);

Categories