Jump to content

Problem with ArrayList

Merkey

Hi, so I have got a method in my java web application that is supposed to compare two ArrayLists(one from a database and the other one from a web page) and remove the same elements, so the second ArrayList should contain only new values:

public void updateWords(ArrayList<String> newArray, int idGroup){
        //get existing words in group
        ArrayList<String> oldArray = getWords(idGroup);
        //print words
        for (String s:newArray){
            System.out.println("New word:"+s);
        }
        for(String s:oldArray){
            System.out.println("Existing word:"+s);
        }
        //remove the same elements
        for (int i=(newArray.size()-1);i>=0;i--){
            String word=newArray.get(i).replace("\n","");
            if (oldArray.contains(word)){
                System.out.println("oldArray already contains:"+word);
                newArray.remove(i);
            }
        }
        for (String s:newArray){
            System.out.println("New word:"+s);
        }
    }

But this is the output:

New word:car
New word:lamp
New word:window
New word:cat
Existing word:car
Existing word:lamp
Existing word:window
New word:car
New word:lamp
New word:window
New word:cat

I tried to run this code in a standalone Java application with the same values and it worked.

Would anybody know why it doesn't work here?

Link to comment
Share on other sites

Link to post
Share on other sites

String equality in java is weird. Strings are objects. And if two strings are separate objects even if they have the same value they are not considered equal. So when you do oldArray.contains(word) If the object word does not exist in the array it will not be removed, regardless of what it's value is.  

Consider the following:

new String("test") == "test" // --> false 
new String("test").equals("test") // --> true 

You should be using the .equals() method on each element to determine if it's contained in the arraylist.

 

 

Link to comment
Share on other sites

Link to post
Share on other sites

Are you sure that the words are actually equal? Maybe the words from your list are coming with extra whitespace? Like "car  " or something like that. Alternatively try to write your own "oldArray.contains(word)" method. Equality in Java can be a pain in the butt. Have you tried debugging where it breaks?

I have also tried it with a standalone Java environment and it worked correct for me. What kind of environment are you using?

Link to comment
Share on other sites

Link to post
Share on other sites

23 minutes ago, geo3 said:

String equality in java is weird. Strings are objects. And if two strings are separate objects even if they have the same value they are not considered equal. So when you do newArray.remove(i); If the object i does not exist in the array it will not be removed, regardless of what it's value is.  

 

Consider the following:


new String("test") == "test" // --> false 
new String("test").equals("test") // --> true 

the bit about String comparison is correct when making strings on the heap (so using new), but remove does use .equals in its implementation (at least in the standard HotSpot JVM) so it shouldn't matter here. From oracle's docs: 

More formally, removes the element with the lowest index i such that (o==null ? get(i)==null : o.equals(get(i))) (if such an element exists)

 

@Merkey i can't see anything immediately wrong, and you said it worked for you locally. What web framework are you using? Is there something niche about the JVM that's being used on the web app that's different than what you are using locally?

EDIT: also, it's better to just use List<String> for your parameter type, not ArrayList<String>. You function should in theory be able to work with any List implementation, and you are restricting your consumers by using the implementation type instead of the interface.

Gaming build:

CPU: i7-7700k (5.0ghz, 1.312v)

GPU(s): Asus Strix 1080ti OC (~2063mhz)

Memory: 32GB (4x8) DDR4 G.Skill TridentZ RGB 3000mhz

Motherboard: Asus Prime z270-AR

PSU: Seasonic Prime Titanium 850W

Cooler: Custom water loop (420mm rad + 360mm rad)

Case: Be quiet! Dark base pro 900 (silver)
Primary storage: Samsung 960 evo m.2 SSD (500gb)

Secondary storage: Samsung 850 evo SSD (250gb)

 

Server build:

OS: Ubuntu server 16.04 LTS (though will probably upgrade to 17.04 for better ryzen support)

CPU: Ryzen R7 1700x

Memory: Ballistix Sport LT 16GB

Motherboard: Asrock B350 m4 pro

PSU: Corsair CX550M

Cooler: Cooler master hyper 212 evo

Storage: 2TB WD Red x1, 128gb OCZ SSD for OS

Case: HAF 932 adv

 

Link to comment
Share on other sites

Link to post
Share on other sites

9 minutes ago, MrMG said:

Have you tried debugging where it breaks?

I haven't, but I have checked the values inside the loop multiple times simply with println() methods. Each time the values were exactly the same, but the contains() method always returned false. I think I have to declare my own method for comparing strings

Link to comment
Share on other sites

Link to post
Share on other sites

4 minutes ago, Merkey said:

I think I have to declare my own method for comparing strings

You really shouldn't have to as long as you aren't using an esoteric JVM. I would try to use a breakpoint and compare in debug mode before giving up on a cleaner design that should be working, instead of just writing a workaround that probably isn't necessary.

 

also, you are removing newlines from the newArray strings, but not the old ones. Are you 100% sure you have no newline chars in the old strings?

Gaming build:

CPU: i7-7700k (5.0ghz, 1.312v)

GPU(s): Asus Strix 1080ti OC (~2063mhz)

Memory: 32GB (4x8) DDR4 G.Skill TridentZ RGB 3000mhz

Motherboard: Asus Prime z270-AR

PSU: Seasonic Prime Titanium 850W

Cooler: Custom water loop (420mm rad + 360mm rad)

Case: Be quiet! Dark base pro 900 (silver)
Primary storage: Samsung 960 evo m.2 SSD (500gb)

Secondary storage: Samsung 850 evo SSD (250gb)

 

Server build:

OS: Ubuntu server 16.04 LTS (though will probably upgrade to 17.04 for better ryzen support)

CPU: Ryzen R7 1700x

Memory: Ballistix Sport LT 16GB

Motherboard: Asrock B350 m4 pro

PSU: Corsair CX550M

Cooler: Cooler master hyper 212 evo

Storage: 2TB WD Red x1, 128gb OCZ SSD for OS

Case: HAF 932 adv

 

Link to comment
Share on other sites

Link to post
Share on other sites

3 minutes ago, reniat said:

also, you are removing newlines from the newArray strings, but not the old ones. Are you 100% sure you have no newline chars in the old strings?

 

If the strings had newlines, the output would look like this, wouldn't it?

Existing word:car

Existing word:lamp

Existing word:window

 

Link to comment
Share on other sites

Link to post
Share on other sites

1 minute ago, Merkey said:

If the strings had newlines, the output would look like this, wouldn't it?

fair. Either way, breakpoints and debugging should help here. 

Gaming build:

CPU: i7-7700k (5.0ghz, 1.312v)

GPU(s): Asus Strix 1080ti OC (~2063mhz)

Memory: 32GB (4x8) DDR4 G.Skill TridentZ RGB 3000mhz

Motherboard: Asus Prime z270-AR

PSU: Seasonic Prime Titanium 850W

Cooler: Custom water loop (420mm rad + 360mm rad)

Case: Be quiet! Dark base pro 900 (silver)
Primary storage: Samsung 960 evo m.2 SSD (500gb)

Secondary storage: Samsung 850 evo SSD (250gb)

 

Server build:

OS: Ubuntu server 16.04 LTS (though will probably upgrade to 17.04 for better ryzen support)

CPU: Ryzen R7 1700x

Memory: Ballistix Sport LT 16GB

Motherboard: Asrock B350 m4 pro

PSU: Corsair CX550M

Cooler: Cooler master hyper 212 evo

Storage: 2TB WD Red x1, 128gb OCZ SSD for OS

Case: HAF 932 adv

 

Link to comment
Share on other sites

Link to post
Share on other sites

When I run your code, I get the expected result

jshell> updateWords(new ArrayList<>(List.of("car", "lamp", "window", "cat")), 1);
New word:car
New word:lamp
New word:window
New word:cat
Existing word:car
Existing word:lamp
Existing word:window
oldArray already contains:window
oldArray already contains:lamp
oldArray already contains:car
New word:cat

That suggests to me that your newArray or getWords are returning results taht aren't quite equal, possibly because they have extra whitespace. If you add a check for word.equals("car"), and use that as a debug check, you can see whether it is actually car; you could also do the same thing with the existing words.

HTTP/2 203

Link to comment
Share on other sites

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×