• Post Reply Bookmark Topic Watch Topic
  • New Topic

Evaluating class objects by multiple criteria  RSS feed

 
Josh Herron
Ranch Hand
Posts: 39
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Good evening everyone.   I'm continuing my journey with Java and I've hit another hurdle.   I'm wondering how to handle the creation of class objects when an object with the instance variables already exist.

For example below, In my main method I create 3 people.   In my addPerson method I want to import some data from a text file and append the variables to String arrays and then index through and create a new person if a person with the name AND email address do not already exist.   I can't figure out how to do this check.
  
I want to add duplicate person records but only if the email address is different.   So below in addPerson I would expect the first variable set for John Smith to be skipped and the remaining 2 to be added.   Can anyone give me some hints on what would work to accomplish this? 

 
Pete Letkeman
Ranch Foreman
Posts: 914
26
Android Chrome IntelliJ IDE Java MySQL Database
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You may want to look into using ArrayList, or any other object which implements the List interface here are a couple of links to help you out:
  • https://docs.oracle.com/javase/tutorial/collections/intro/
  • https://docs.oracle.com/javase/tutorial/collections/implementations/list.html
  • https://docs.oracle.com/javase/8/docs/api/java/util/ArrayList.html

  • Some (all?) of the classes  which implement the List interface have built in methods like:
  • contains
  • add
  • remove
  • toArray

  • I know ArrayList implements these methods.
    You could create an ArrayList of your Person class and check to see if the ArrayList already contains, using the contains method, the Person object using the contains method.
     
    Josh Herron
    Ranch Hand
    Posts: 39
    1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    I considered the ArrayList route, in fact I had it in my code and then removed it because I don't know how to check multiple criteria.  If I create an ArrayList of Person objects it will just be storing the hash value correct, not the literal values for each variable?

    So if I did made an ArrayList name personArray and created a for loop to index through like below.   (the code might be wrong... just firing something off real quick)



    That wouldn't work because the newName and newEmailAddress would just be getting compared to a has value right?
     
    Pete Letkeman
    Ranch Foreman
    Posts: 914
    26
    Android Chrome IntelliJ IDE Java MySQL Database
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    I think that you may have to override the either the equals, hashcode or comparable methods in your object:
    https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html
    https://docs.oracle.com/javase/8/docs/api/java/lang/Comparable.html

    I think that once you do this then you could use the ArrayList contains method by doing something like:

    Please notice the !, which means not. So if the personList does not contain the new person with an name of "Jim" and an email address of "jimmy@domain.com" then add it to the list.
    Or, this is a bit more confusing and a bit more advanced, but you could use Lambda's with a custom interface maybe the Predicate interface.
     
    Pete Letkeman
    Ranch Foreman
    Posts: 914
    26
    Android Chrome IntelliJ IDE Java MySQL Database
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    After looking to the documentation
    Java Documentation wrote:public boolean contains(Object o)
    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)).
    Specified by:
    contains in interface Collection<E>
    Specified by:
    contains in interface List<E>
    Overrides:
    contains in class AbstractCollection<E>
    Parameters:
    o - element whose presence in this list is to be tested
    Returns:
    true if this list contains the specified element

    So you would just have to override the equals method for your person object.
     
    Josh Herron
    Ranch Hand
    Posts: 39
    1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    I appreciate your guidance here, but it doesn't seem to be working.  When I debug I can see the personList has objects created from the main method but in the addPerson method when it checks the objects for John Smith and his email address it finds no match and adds a duplicate Person for John Smith.  Did I do something wrong with the equals override?

     
    Pete Letkeman
    Ranch Foreman
    Posts: 914
    26
    Android Chrome IntelliJ IDE Java MySQL Database
    • Likes 1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Made a few changes, from what I can see the key to the problem was equals and the code below works:


    I just took the equals method from a Google search and changed it slightly to match your object's properties.
     
    Pete Letkeman
    Ranch Foreman
    Posts: 914
    26
    Android Chrome IntelliJ IDE Java MySQL Database
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Okay, there are plenty of different rules for when to use static and I'm not going to go into them right now.
    However I did take the static array list out of the person object, however you can add it back in.
    Heck you can do whatever you want, nothing says that you can't.

    I'm not too sure why you were adding the objects to the list the way that you were adding them to the list.
    So I just put the few line of code in the main method. Once again, you can do whatever you want, as long as it works for you.

    If you remove the toString method, then you get something else when you do a print of the object, which is not too helpful for most humans.
     
    Josh Herron
    Ranch Hand
    Posts: 39
    1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    This is great, thank you so much.


    For my SSCE I was just trying to get some data in a list but in my real App my Person class is serialized and each time the app runs it will import all of the known Persons that have been previously created.   So I guess step one will be to re-populate my personList and then index through all of the potential new Persons adding the ones that meet the criteria.

    I really do appreciate all of the help and support here at the ranch.     It makes this new adventure into Java far less overwhelming.

     
    Pete Letkeman
    Ranch Foreman
    Posts: 914
    26
    Android Chrome IntelliJ IDE Java MySQL Database
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Hey, I'm glad that you are happy. All that I ask if that you pay if forward when the opportunity presents it's self.

    Now if you want to get a little more advance then you may want to look into reading and writing data to and from an external source(s).
    There is are many ways that this can be done, so I'll leave that up to you.
     
    Josh Herron
    Ranch Hand
    Posts: 39
    1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Yep, I've been doing a little reading and writing to text files with bufferedreader and writer, and I've managed to get serialization to save and load data.   So that's pretty neat.

    I really need to start digging into reading and parsing XML because we use a lot of XML over HTTP at work, and I'm hoping to learn enough to get involved with out app dev teams in some capacity there.
     
    Knute Snortum
    Sheriff
    Posts: 4287
    127
    Chrome Eclipse IDE Java Postgres Database VI Editor
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    When you override the equals() method, you need to override the hashCode() method too.
     
    Pete Letkeman
    Ranch Foreman
    Posts: 914
    26
    Android Chrome IntelliJ IDE Java MySQL Database
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Thanks @Knute Snortum I did not know about that.
     
    Josh Herron
    Ranch Hand
    Posts: 39
    1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Knute can you elaborate on how the hashCode works?   I guess I'm not certain how to override that.
     
    Pete Letkeman
    Ranch Foreman
    Posts: 914
    26
    Android Chrome IntelliJ IDE Java MySQL Database
    • Likes 1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    As shown in this post
    https://coderanch.com/t/683598/java/override-equals-override-hashCode#3208012
    If you choose you have use the String hashCode function to create your own hashCode on from the string members of your object.

    There are also libraries and other methods that you can use to create your own hashCode for your object.

    You can read about the String hashCode function here:
    https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#hashCode
     
    Josh Herron
    Ranch Hand
    Posts: 39
    1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Thanks again!   I have a book that I'm using to learn Java but it seems like there are many topics that aren't covered.
     
    Pete Letkeman
    Ranch Foreman
    Posts: 914
    26
    Android Chrome IntelliJ IDE Java MySQL Database
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    No problem at all, at least for me. I understand, there is a lot that one can learn and I know that any single book or tutorial is going to cover it all.

    I suggest that if this link
    https://coderanch.com/t/683598/java/override-equals-override-hashCode#3208012
    Does not help you out enough with hashCode that you Google for something like
    Java hashcode override
    And then after doing some research if you are still experiencing problems with hashCode that you start a new thread/post.
     
    Knute Snortum
    Sheriff
    Posts: 4287
    127
    Chrome Eclipse IDE Java Postgres Database VI Editor
    • Likes 1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    In Java 8, there is a new utility class, Objects, that will create a hash code for you.  Below is a demonstration of a class where two addresses can be different but the object can still be equal.  The hashCode() method is one line.
     
    Josh Herron
    Ranch Hand
    Posts: 39
    1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Thanks!  I also found that in Eclipse if I hit source it will override equals and hashcode for me.   But I obviously want to understand how to do it manually before relying on an IDE to create it for me.

     
    Campbell Ritchie
    Marshal
    Posts: 56587
    172
    • Likes 1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Search for Effective Java™ by Joshua Bloch, and search for a sample chapter. Or find a copy and look at pages 33‑51, which used to be available free of charge in a sample chapter. Remember that book was written before the Objects class, but you will find suggests for the Object#equals method in the form of Bloch's (I think) canEqual method.
    Go through that chapter. Also look at the three links in this post, as well as the general contract for equals(), which you will find if you scroll down from the same link.
    You also need to know that a double or a float is stored in memory as 64 or 32 bits, and those bits can be expressed as a long or an int, which is why you can find these two methods in the Double (capital D) class: 1 2. There are corresponding methods in the Float class. In the case of a Float, it is possible to get a hash code simply by returning those 32 bits, but it is more complicated for a Double. What Bloch shows is the left half of those 64 bits undergoing an exclusive or operation with the right half, and then the left half being discarded simply by casting the result to an int. You use a similar technique for a long, but the 64 bits are already available so no strange transformations are required.
    Another problem is that some fields might point to null, so you have to take that into consideration when calculating hash codes:-
    ... + (myField == null ? 0 : myField.hashCode()) ...
    Now, the Objects#hash method takes all that into consideration for you. A null is given a default “hash code”, possibly 0. A double is boxed to a Double and that object's hashCode method is called, which uses the same technique as Bloch describes.

    Once you have worked out how to calculate hash codes, you will probably default to using Objects#hash. Much simpler. It can be implemented on the following basis:-The reason for multiplying by a prime number is to bring any variability in the hash code to the right. In the older edition of Bloch, he used * 13, * 17, * 19, * 23 etc. for prime multiplication. Nowadays it is usual to use the same prime number throughout. Maybe in future somebody will discover that using a larger Mersenne prime is more efficient and they can change the multiplicand to 8191, but that might make serialised hashMaps inconsistent with newer implementations.
     
    Stephan van Hulst
    Saloon Keeper
    Posts: 7993
    143
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Knute Snortum wrote:In Java 8, there is a new utility class, Objects

    It's been around since Java 7 :)
     
    • Post Reply Bookmark Topic Watch Topic
    • New Topic
    Boost this thread!