Compare object stored as value in hashmap [duplicate] - java

This question already has answers here:
How do I compare strings in Java?
(23 answers)
Closed 9 years ago.
I am having a hashMap which stores my values like that:
{10997=Event [Numb=0007449001, date=07.02.2008], 10998=Event [Numb=0007449001, date=08.04.2008], ...
As you can see the key is a integer and the value is an Event Object which has a numeric value and a date, which is saved as a String.
I want to compare the numeric value of the map to another value with an if statment.
I tried:
if(numericVal==eventMap.get(i).toString()) {
However that does not really work. How to get the value easily out of the HashMap and of the Object?
I appreciate your answer!
UPDATE
By easily I mean performance orientated, because I have to process a lot of values.

first off; do not compare Strings with == use equalsIgnoreCase() instead (or just equals() if the casing matters)
second; consider giving your Event a compareTo() and while you are at it an equals() and a hashCode().
Once you got the components in place and why they should be there, you'll realize what you want to do is possible in a much more elegant way.

If I understand correctly you are trying to compare the actual numeric value within your EventObject
Therefore your EventObject has to have an accesor to it.
Lets say your EventObject looks something like:
public class EventObject {
private String numericValue;
private String date;
public EventObject(String numericValue, String date) {
this.numericValue = numericValue;
this.date = date;
}
public String getNumericValue() {
return numericValue;
}
public void setNumericValue(String numericValue) {
this.numericValue = numericValue;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
}
From there now accessing the numericValue from a HashMap should be as easy as:
HashMap<Integer,EventObject> map = new HashMap<>();
map.put(10997,new EventObject("0007449001", "07.02.2008"));
int keyMap = 10997; //for sake of making obvious this is Key and not numericValue
String numValue = hashMap.get(keyMap).getNumericValue();
A comparison then can be done by:
if("0007449001".equals(map.get(10997).getNumericValue())) {
System.out.println("The Date I have is: " + map.get(10997).getDate());
}
Which will get you:
The Date I have is: 07.02.2008

Related

Java several enums as getter/setter

I wanted to use enum class to assign book formats to book object. Issue that I have encountered is that some books have 1 format and other have several.
public enum Format {
HARD_COVER, PAPERBACK, E_BOOK, AUDIOBOOK
}
Let's say that first book have only 1 format while second book have all formats. How can I solve it with getters/setters?
How can I solve it with getters/setters?
I wouldn't do this since in my experience, getters and setters are for setting single properties. If I have a class that requires a collection of property, then I'd have the class contain a List for this:
List<Format> formats = new ArrayList<>();
and then:
public void addFormat(Format format) {
formats.add(format); // add to the ArrayList of Format
}
and similarly a removeFormat(Format format) method for removing from the List.
Edit: as correctly stated by Dorian Gray in comments, it would be better that the collection of Formats be a Set<Format> initialized as an EnumSet` since this would prevent duplicate Formats being added to the collection.
Set<Format> formatSet = EnumSet.noneOf(Format.class);
You could work with Bitwise Operators to have one property with the possibility of having multiple values.
Have Enums with int values like this:
public enum Format {
HARD_COVER(1),
PAPERBACK(2),
E_BOOK(4),
AUDIOBOOK(8);
public final int value;
Format(int value) {
this.value = value;
}
}
In your Book class add an int property called format instead of a Format property. Also create a method called isFormat that returns a boolean value according to its Format parameter:
class Book {
private int format;
public Book(int format) {
this.format = format;
}
public boolean isFormat(Format format) {
return format.value == (this.format & format.value); // &: bitwise and
}
}
Finally create a book adding formats separated by | (bitwise or):
Book book = new Book(Format.E_BOOK.value | Format.HARD_COVER.value | Format.AUDIOBOOK.value);
And check its formats like this:
System.out.println("Is paperback?: " + book.isFormat(Format.PAPERBACK));
System.out.println("Is hard cover?: " + book.isFormat(Format.HARD_COVER));
System.out.println("Is audio book?: " + book.isFormat(Format.AUDIOBOOK));
System.out.println("Is E-book?: " + book.isFormat(Format.E_BOOK));
The result of this execution is this:
Is paperback?: false
Is hard cover?: true
Is audio book?: true
Is E-book?: true

What's the best way to change attributes of objects stored in an ArrayList or HashMap?

I have to do a little exercise (homework, like a friendlist) in Java, and i'm a little stuck on one of the tasks that i have to implement in my program.
The exercise is about storing some friend-objects with a variety of attributes in a container-class and implementing some methods in the container-class for various tasks on the friend-objects.
The overall exercise is not a problem at all, but i'm quite unconvinced that my solution is the way to go. I hope you can give me some tips here.
The method that is left over, should be something like a "updateFriend" method, with which you can set the value of a given attribute to a new value, straight from the container-class.
I've already set up my friend-class with a handfull of attributes (e.g. prename, lastname, date of birth, adress, and so on) an getters/setters for all of them. I've also implemented the container-class (as an ArrayList), but i can't seem to find an elegant way to implement this specific method. My updateFriend()-method right now takes three parameters.
1.The specific id of the friend-object
2.The name of the attribute that i want to change
3.The new value of the attribute
It uses an enum to check if the entered attribute is an existing attribute and if yes, the method searches the ArrayList for the object that contains that attribute and should overwrite the existing value. It gets a little bulky, as i have implemented a switch on the enum, that calls the fitting setter-method for each attribute of the friend, if the type in attribute exists at all.
So basically the friend-class looks like this:
public class Friend {
private static int friendCount = 1;
private String firstname;
private String lastname;
private LocalDate dateOfBirth;
private String phonenumber;
private String mobilenumber;
private String eMail;
private Adress home;
private int friendID;
//Getters & Setters
...
}
The method that gives me problems in the container-class looks something like this at the moment:
public void updateFriend(int id, String toChange, String newValue)
{
for(Attribute a : attribute.values())
{
if(String.valueOf(a).equalsIgnoreCase(toChange))
{
for(Friend f : friends)
{
int counter = 1;
if(f.getID() == id)
{
switch(a)
{
case FIRSTNAME:
{
f.setPreName(neuerWert);
break;
}
//a case for each attribute
}
I'm quite certain that my take on the given method is messy, slow, and cumbersome. What would be an elegant way of solving this?
Excuse my wording and thanks in advance, greets.
I would suggest 3 performance improvements.
Use HashMap instead of List with key as id. Since, id will be unique, it will take O(1) time to get the relevant object for modification instead of spending O(n) time on List iteration.
You can change the type of toChange parameter from String to enum. This will avoid enum to String conversion and then comparing it.
Since, you are already doing validation of the attribute to be modified and you must be following standard java convention while naming your getters and setters, you can use reflection to call the method on the Friend object by creating the method name from attribute name like set{Attributename}.
Okay, lets start using the enum Attribute to handle all the changes (Since you already holding the attribute values)
Attribute Enum
public enum Attribute {
FIRSTNAME("fname", (friend, name) -> friend.setFirstname(String.valueOf(name))),
LASTNAME("lname", (friend, lname) -> friend.setLastname(String.valueOf(lname))),
DATEOFBIRTH("dob", (friend, dob) -> friend.setDateOfBirth((LocalDate) dob)),
PHONENUMBER("pno", (friend, pno) -> friend.setFirstname(String.valueOf(pno))),
MOBILENUMBER("mno", (friend, mno) -> friend.setFirstname(String.valueOf(mno)));
private String attributeName;
private BiConsumer<Friend, Object> attributeSetter;
public static Attribute getAttributeSetterByName(String attributeName) {
return Arrays.stream(Attribute.values())
.filter(attribute -> attribute.getAttributeName().equalsIgnoreCase(attributeName))
.findFirst()
.orElseThrow(() -> new RuntimeException(String.format("Invalid Attribute name - %s", attributeName)));
//.orElse(null);
}
//Getter, Setter & Args Constructor (Use Lombok to reduce Boiler Plate code)
}
Update Logic
public void updateFriend(int id, String toChange, String newValue) {
Attribute attribute = Attribute.getAttributeSetterByName(toChange);
for (Friend friend : friends) {
if (friend.getId() == id) {
attribute.getAttributeSetter().accept(friend, newValue);
break;
}
}
}
You can use a java.util.function.Consumer<T> object to change an object inside your container where you have all the type safety you get. Instead of having magic strings and string arguments for values, which might not be even for string fields, you can work directly on the objects type:
public void updateFriend(int id, Consumer<Friend> c) {
// find the friend object
Friend found = null;
for (Friend f: this.friends) {
if (f.getId() == id) {
found = f;
break;
}
}
if (found == null) {
throw new IllegalArgumentException("There is no friend object with the given id");
}
// use the friend object.
c.accept(found);
}
You can use this method like this:
container.updateFriend(42, f -> f.setVorName("abc"));
container.updateFriend(9, f -> f.setAddress(some_address_object));

Should I initialize object values?

The question may sound a bit silly, but should an object class look something like this:
class Book {
String title;
int year;
///so on and so forward
}
or should it look like this?
class Book {
String title = "";
int year = 0;
///so on and so forward
}
i understand that actual values should be set by the constructor (or setValue methods), but should the initial values be null, or 0/"" ?
Edit: Im trying to work with the object values as strings (replacing certain characters, etc), which doesnt work if the value is null; i wasnt sure if i should add an "if" clause or simply initialize values to an empty string
It should look something like this:
public class Book {
private String title;
private int year;
}
public Book(String titleIn, int yearIn) {
title = titleIn;
year = yearIn;
}
And the way you should create the object is:
Book harryPotter = new Book("Harry Potter", 2014);

Find index of an object in a list

I have situation where I have a list(required items) that holds a table column result like:
NAME
ADDRESS
AGE
.
.
etc
In my method I get a User object that contains values for user.getName(), user.getAge() etc. I want to know the best way to ensure that every item in the list is present in the user object. The no of items in the list are variable.
public boolean isUserInfoComplete(User user, ArrayList list){
//so, if the list has AGE, the user.getAge() must have some value
}
One way I thought of is maintaining another list that holds values of every user info and checking that against my db list but that is not scalable.
It's not possible to dynamically match your method names with the list contents without reflection (which can be expensive and fragile). You may want to consider keeping your User values in a central Map cache. Here's one way to do that:
public class User {
private enum Field {
NAME,
AGE
//...
}
private Map<String, Object> values = new HashMap<>();
private void putValue(Field field, Object value) {
values.put(field.name(), value);
}
private Object getValue(Field field) {
return values.get(field.name());
}
public void setName(String name) {
putValue(Field.NAME, name);
}
public String getName() {
return (String)getValue(Field.NAME);
}
public void setAge(int age) {
putValue(Field.AGE, age);
}
public Integer getAge() {
return (Integer)getValue(Field.AGE);
}
//...
public boolean isUserInfoComplete(List<String> fields) {
return values.keySet().containsAll(fields);
}
}
You could use reflection to solve this problem if the items in the list match the getters in your User object.
For example, if AGE is in the list, you could use reflection to look for the getAge() method on the User class, call it on the object, and then check the result for null (or switch on the method return type to perform other types of checks).
Here's a starting point for you to experiment with (I haven't compiled or tested it):
public boolean isUserInfoComplete(User user, ArrayList list){
for(String attribute : list) {
String methodName = "get" + attribute.substring(0, 1).toUpperCase() + attribute.substring(1).toLowerCase();
Method method = User.class.getMethod(methodName, null);
if(method != null) {
Object result = method.invoke(user);
if(result == null) {
return false;
}
}
}
return true;
}
This seems like a case where you need reflection. This gives you the opportunity to inspect methods and field from your objects at runtime.
If you know your User-objects etc will follow a java bean standard then you will be able to use the getters for checking, though I see now problem in making your fields public final and checking directly on the fields themselves.
Take a look at https://docs.oracle.com/javase/tutorial/reflect/
You can check it using contains() while looping. This process will be very resource-consuming.
Maybe you can redesign something and simply compare two User objects? Will be faster. You can do it by providing your own implementation of equals and hashcode methods.

How do I use a comparator (for a binary search) to compare a DateTime to a DateTime field in an object?

I want to compare inputted dates to a sorted list of holidays objects using a binary search. The holiday objects consist of a string with the name and a jodatime Datetime. So I am comparing the same types but one is part of an object and the other is not.
I have:
public class DateTimeComparator implements Comparator<DateTime> {
public int compare(DateTime userDate, DateTime listHoliday) {
if (userDate.equals(Holidays.getAllHolidays().date)) {
return 1;
}
else {
return 0;
}
}
}
Eclipse's feedback is that date can't be resolved. How can I correctly point to the date field of my Holiday list?
Edit: So if I don't need a comparator (suggested to me in another question), how do I structure my binary search? So far I have:
public static boolean isHoliday(List<Holiday> holidayList, DateTime date) {
if(Collections.binarySearch(holidayList.date, date)) {
return true;
}
return false;
}
You don't need to write a Comparator for this, DateTimes are already inherently Comparable. Also, referencing the date field for a LIST is non-sensical; its the ELEMENTS of the list with have that field, not the list itself.
You want to use Collections.binarySearch instead, and handle the output yourself.
I solved this by creating a new holiday and comparing two holiday objects to each other with a comparator that looks at the DateTime field.

Categories

Resources