Dealing with equality in an ArrayList in java - java

Say I have this section of code:
for(int i = 0; i < accounts.size(); i++) {
if(UserID.equals(accounts.get(i).getUserID())) {
if(accounts.contains(accounts.get(i))) {
if(UserPass.equals(accounts.get(i).getPassword())) {
System.out.println("True");
}
} else {
typePhrase("unrecognised userID: '" + UserID + "'");
}
} else {
typePhrase("unrecognised userID: '" + UserID + "'");
}
}
It goes through an arrayList filled with objects, that have an ID and a password. I get two inputs from the user, one is the userID, and the other is the password. What I want is for it to go through every possible object that is saved in that arrayList, and if it finds a match, print true into the console, the issue that I'm having is that if you type in something wrong, it prints an message that it is unrecognised for every object in the arrayList. It also prints the message for every object that there is in the arrayList -1 if you type one in right. What do you suggest I do?
User class:
public class User {
String userID;
String password;
public User(String ID, String Pass) {
userID = ID;
password = Pass;
}
public String getUserID() {
return userID;
}
public String getPassword() {
return password;
}
}
EDIT:
ArrayList<User> accounts = new ArrayList<User>();

You should implement equals method in the User class:
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
if (!getUserID().equals(user.getUserID())) return false;
return getPassword().equals(user.getPassword());
}
Then you can create a new User with the typed information and just check if the list contains this User:
User user = new User("typedUserId", "typedPassword");
System.out.println(accounts.contains(user));

This is a mistake I see newer programmers often make. You're searching through a list to see if any element meets some condition (e.g. ID and password match). If no element meets the condition, you do something that indicates an error.
But you can't tell if there's an error until you've gone through every element of the list. Therefore, any error message has to occur after the loop is completely done, right? Not in the middle of the loop. But you've put your "unrecognised" message in the middle of the loop. That can't work.
There are several common idioms to solve this, but here's a simple one:
boolean found = false;
for (whatever-your-loop-should-look-like) {
if (the-current-element-meets-the-condition) {
found = true;
break;
}
}
if (!found) {
whatever-action-you-take-when-it-isn't-found;
}

Remove this check... It makes no sense while you loop over those objects to check if the current object is inside the list of objects it came from.
if(accounts.contains(accounts.get(i))) {
Without this, your code prints True (but continues to check the rest of the list) when the userID and password match. Otherwise, the other message is printed. If you want to stop the loop when you print True, put break there.
To address the problem, though, User.equals() is not implemented, so the default way to compare objects is used (via the hashcode method).
You should implement that to compare equality of userID and password.

Not sure if implementing equals() is a wise choice here. However, isn't that what you are trying to do as simple as:
boolean found = false;
for (User u : accounts) {
if (userId.equals(u.getUserId()) && userPass.equals(u.getPassword()) {
found = true;
break;
}
}
You may even use stream API if you are in Java 8+
accounts.stream().anyMatch(u -> userId.equals(u.getUserId())
&& userPass.equals(u.getPassword());

Instead of printing true or not found, you can keep a boolean variable with whether you have found a match or not.
boolean found = false
for each value in the array
if it's a match set found to true
if it's not a match do nothing, i.e. continue to next position
if (found) print "true" else print "not found"
You can also break out of loop if you found a match, no need to keep checking for more matches.
boolean found = true
for each value in the array
if it's a match set found to true and break out of loop
if it's not a match do nothing, i.e. continue to next position
if (found) print "true" else print "not found"
Even better, you can move the code to a method that returns boolean and get rid of the variable.
boolean isThereAMatch() {
for each value in the array
if it's a match set return true
if it's not a match do nothing, i.e. continue to next position
return false
}
And you can call it to check what to print.
if (isThereAMatch()) print "true" else print "not found"

You're struggling with whether to use contains() of List or to use a simple for loop. It can be done both ways, below is the code sample for both. For using the contains you'll have to add an equals() overridden method to User.
From the List.contains() documentation
Returns true if this list contains the specified element. More formally, returns true if and only if this list contains at least one element e such that (o==null ? e==null : o.equals(e)).
With For Loop
import java.util.*;
public class TestMain {
public static void main (String[] args) {
List<User> accounts = new ArrayList<User>();
User user1 = new User("test", "test");
User user2 = new User("test1", "test1");
accounts.add(user1);
accounts.add(user2);
String userId = "test";
String userPass = "test1";
boolean matchFound = false;
for(User account : accounts) {
if(userId.equals(account.getUserID()) && userPass.equals(account.getPassword())) {
System.out.println("True");
matchFound = true;
}
}
if(!matchFound) {
System.err.println("unrecognised userID: '" + userId + "'");
}
}
}
class User {
String userID;
String password;
public User(String ID, String Pass) {
userID = ID;
password = Pass;
}
public String getUserID() {
return userID;
}
public String getPassword() {
return password;
}
}
With contains() and equals()
import java.util.*;
public class TestMain2 {
public static void main (String[] args) {
List<User> accounts = new ArrayList<User>();
User user1 = new User("test", "test");
User user2 = new User("test1", "test1");
accounts.add(user1);
accounts.add(user2);
String userId = "test1";
String userPass = "test1";
boolean matchFound = accounts.contains(new User(userId, userPass));
if(!matchFound) {
System.err.println("unrecognised userID: '" + userId + "'");
} else {
System.out.println("True");
}
}
}
class User {
String userID;
String password;
public User(String ID, String Pass) {
userID = ID;
password = Pass;
}
public String getUserID() {
return userID;
}
public String getPassword() {
return password;
}
#Override
public boolean equals(Object user) {
boolean isEqual = false;
if(user != null && user instanceof User) {
User userType = (User)user;
boolean userIdMatched = (userID == null) ? userType.getUserID() == null : userID.equals(userType.getUserID());
boolean passwordMatched = (password == null) ? userType.getPassword() == null : password.equals(userType.getPassword());
isEqual = userIdMatched && passwordMatched;
}
return isEqual;
}
}

Related

For iterator is not being recognized in struts 2 execute method?

I have this execute method action for struts2 in my program, it validates a login form in my webpage, checking an ArrayList called listaUsuarios where my usuarioBean objects are being stored, to find if the username and the password are equal in those attributes
public String executeLogin() {
String go = ERROR;
for (Usuario u : s.getListaUsuarios()) {
if (usuarioBean.getNombreUsuario().equals(u.getNombreUsuario())) {
if (usuarioBean.getContrasenna().equals(u.getContrasenna())) {
if (u instanceof Administrador) {
go="admin";
break;
}
if (u instanceof Cliente) {
go="cliente";
break;
}
if (u instanceof Proveedor) {
go="proveedor";
break;
}
}
}
}
return go;
}
This doesn't work, it doesn't validate anything but if I put in my login form, this hardcoded method, it works, so I'm not sure what is happening:
public String executeLogin() {
String go = ERROR;
if (usuarioBean.getNombreUsuario().equals("jean182")) {
if (usuarioBean.getContrasenna().equals("123")) {
go = "admin";
}
}
return go;
}
Did you print the string you read from the form? The problem could be that those are not equals to the ones stored (spaces at the end, upper case / lower case)

Java "contains" not working properly

My class:
public class UserProgressModel {
private String email;
public UserProgressModel(String pEmail) {
super();
this.email = pEmail;
}
#Override
public boolean equals(Object x) {
if (x != null && x instanceof UserProgressModel
&& ((UserProgressModel) x).email.equals(this.email) == true) {
return true;
}
if (x != null && x instanceof String
&& x.equals(this.email) == true) {
return true;
}
return false;
}
#Override
public int hashCode() {
int hash = 7;
hash = 17 * hash + (this.email != null ? this.email.hashCode() : 0);
return hash;
}
}
And after putting some objects via gson:
UserProgressModel[] userProgressArray;
List<UserProgressModel> retUserProgress = new ArrayList<>();
userProgressArray = gs.fromJson(fileContents,
new TypeToken<UserProgressModel[]>() {
}.getType());
for (UserProgressModel ele : userProgressArray) {
if (ele != null) {
retUserProgress.add(ele);
}
}
I am unable to get true for the following code:
retUserProgress.contains("test#test.com");
I looped thru the array to verify that one object has the email.
Am I doing right? I think I have overridden the equals & hashcode.
Your equals implementation is incorrect. If you look at the contract for equals the implementation must be symmetric:
... for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.
In your case you have a list of UserProgressModel objects, but you are trying to compare against a String. While you've implemented UserProgressModel.equals(String) you would still need to have String.equals(UserProgressModel) return the correct result. Since you cannot do that this implementation will never work in all cases. What you should do is two things:
Remove the check in equals for String because it will never work.
Use a mock object to check in the collection:
retUserProgress.contains(new UserProgressModel("test#test.com"));
As long as your equals method is correct within your own type (UserProgressModel.equals(UserProgressModel)) this should fix your issue.
You cannot check if the retUserProgress contains e-mails because it does not. The ArrayList contains objects of Class: UserProgressModel, thus you can check if the ArrayList contains a 'UserProgressModel'.
What you would like to do is the following
private boolean containsEmail(List<UserProgressModel> retUserProgress, String email) {
boolean result = false;
for (UserProgressModel object : retUserProgress) {
if (object.equals(email))
result = true;
}
return result;
}
And the call the method like so:
containsEmail(retUserProgress, "test#test.com"); //This will return a true or false, depending if the ArrayList retUserProgress contains the email
i have tested your code in ideone
and it's working
true
UserProgressModel model=new UserProgressModel("test#test.com");
System.out.print(model.equals("test#test.com"));
false
UserProgressModel model=new UserProgressModel("test#test.com");
System.out.print(model.equals("test#test.co"));
try to compare with new object
retUserProgress.contains(new UserProgressModel("test#test.com"))
result
if you don't wanna compare with a new UserProgressModel you need to create your own list type that when it compare two object (UserProgressModel,string) it creates a new UserProgressModel and pass that email for it

Get the text from the field but if blank do this

I have a number of fields where data needs to be input. This is a Hotel Reservation system so if the fields arent filled it must display that they are empty and cannot proceed without filling them. What I want to do is get the text from the fields but if they are blank it must either set all the fields text to something like "*Please fill in all fields" or show up a message.
I have some code which is not working because it cant get the text if there's nothing in the fields. The code looks like this:
this.Firstname = NameF.getText();
this.Lastname = NameL.getText();
this.Country = Countr.getText();
this.IDtype = IDTy.getText();
this.PassportNo = PassNo.getText();
this.IDNo = IDNumber.getText();
this.Addr1 = Add1.getText();
this.Addr2 = Add2.getText();
this.AreaCode = Integer.parseInt(Area.getText());
this.TelNo = Tel.getText();
this.CellNo = Cell.getText();
this.Email = Em.getText();
}
if (this.Firstname.equals("") || this.Lastname.equals("") || this.Country.equals("") || this.IDtype.equals("") || this.IDNo.equals("") || this.Addr1.equals("") || this.Addr2.equals("") || this.AreaCode == 0 || this.TelNo.equals("") || this.CellNo.equals("") || this.Email.equals("")) {
JOptionPane.showMessageDialog(null, "Please fill in all fields");
}
Not sure if I should ask this in another question but is there an easier way to make the if without so many || operators? Just like if this.Firstname,this.Lastname,etc.equals("")
You could do something like this.
public void validateFields () {
for (String field : getNonBlankFields()) {
if (field.equals("")) {
JOptionPane.showMessageDialog(null, "Please fill in all fields");
return;
}
}
}
Collection<String> nonBlankFields;
public Collection<String> getNonBlankFields () {
if (this.nonBlankFields != null) {
return this.nonBlankFields;
}
this.nonBlankFields = new ArrayList<String> ();
this.nonBlankFields.add(this.lastName);
// add all of the other fields
this.nonBlankFields.add(this.email);
return this.nonBlankFields;
}
You could do this by creating a function to do the checks for you in a loop;
public boolean isAnyEmpty(String... strArr){
for(String s : strArr){
if(s.equals("")) return true;
}
return false;
}
Then call it with
if(isAnyEmpty(this.Firstname, this.lastName, this.Country, /* rest of your strings */)){
//your code
}
This method makes use of varargs to let you treat the parameters as an array, without having to add in the additional code to explicitly create one.
You can create a method that will validate your Strings in varargs flavor:
public boolean validateString(String ... stringsToValidate) {
for (String validString : stringsToValidate) {
if (...) { //logic to validate your String: not empty, not null, etc
return false;
}
}
return true;
}
Then just call it like this:
//add all the strings that must be validated with rules defined in validateString
if (!validateString(NameF.getText(), NameL.getText(), Countr.getText(), ...) {
JOptionPane.showMessageDialog(null, "Please fill in all fields");
}

finding element

I´ve got this method:
public User findById(String name)
{
for (User u : list)
{
if (u.getFirstName() == name)
{
return u;
}
}
return null; // or empty User
}
How can i program a method in my window class so that i can print out the user i´ve found?
This is what i got. (think im way off)
public void findCustomer()
{
String firstname = findCustomerField.getText();
if(!firstname.equals(""))
{
String result = list.findById(firstname);
outputText.setText(result);
}
}
Don't use == in your comparison
if (u.getFirstName() == name)
but equal
if (u.getFirstName().equal(name))
The operator == tests to see if two object reference variables refer to the exact same instance of an object.
The method .equals() tests to see if the two objects being compared to each other are equivalent
You need to change also your findCustomer method like this
public void findCustomer()
{
String firstname = findCustomerField.getText();
if(!"".equal(firstname))
{
User user = list.findById(firstname);
if(user != null)
{
outputText.setText(user.getFirstName());
}
}
}
Use String.equals() for value equality check.
Change this to:
if (u.getFirstName().equals(name)) {
The == basically does object reference equality check.
String result = list.findById(firstname);
Your findById returns a User so change it to:
User result = list.findById(firstname);
Consequently change your next line to:
outputText.setText(result.getFirstName());

i have a arraylist where i am verifying particular object is existing or not but even it exists it always returns false

hi i have class called userdata which returns the Userarraylist which is of type User. when ever i try to use contains method to check particular property is existing or not it always returns false why?
Actually i want the array list to be generic which should return the objects that are set in array list.
String className = data.getUserData().get(0).getClass().getSimpleName();
if(className.equalsIgnoreCase("User")) {
ArrayList<User> userdata=new ArrayList();
userdata = data.getUserData();
System.out.println(data.getUserData().contains(u.getUserId()));
if(userdata.contains(u.getUserName())) {
System.out.println(userdata.get(0).getEmailId());
}
}
The ArrayList is of Users while you are checking to see if it contains an ID or String.
userdata.contains(u);
The problem is, the ArrayList contains Objects, not the id's of those objects.
You are trying to compare the u.getUserId to the objects within the list, this is not a valid comparison (User != int)
UPDATE
boolean contains = false;
for (User user : userdata) {
// assuming userID is a number!!
if(user.getUserId() == u.getUserId()) {
contains = true;
break;
}
}
Just a side note, you should use either the instanceof operator or Class.equals method, instead of getting the simple name name checking for equality with some string.
You can't use contains in the list with User objects with its attributes i.e. user.userId or user.email.
Better to override equals method in User class which compare the attributes as below:
#Override
public boolean equals(Object obj) {
User other = (User) obj;
if (userId == null) {
if (other.userId != null)
return false;
} else if (!userId.equals(other.userId))
return false;
if (userName == null) {
if (other.userName != null)
return false;
} else if (!userName.equals(other.userName))
return false;
return true;
}
and then use contains as
userdata.contains(u)
It should be like
userdata.get(SOME_INDEX).getUserName.equals(u.getUserName());
or if you want to scan the whole ArrayList use this line inside a for loop
for (User user : userdata) {
if(user.getUserName().equals(u.getUserName())) {
return true;
}
}
Note that I have assumed there is a getter for the username attribute

Categories