I need to know the "best" and safest way to get a value held within a Set if there is only one entry. methodToGetValues() is used extensively to read config files and return a list of values given a specific key, in this case "enabled". For the enabled key, there should only be one entry returned in the Set, obviously "true" or "false" but, mistakes happen. I have the following which seems a little convoluted:
Set<String> enabled = methodToGetValues("enabled");
if (!enabled.isEmpty() && enabled.size() < 2 && "true".equals(enabled.iterator().next())) {
...
}
Can anyone suggest a simpler yet still robust way of checking this?
Your question asks to get something from the Set. But your example just needs a check.
If you know what to expect in the Set, this works fine.
if (enabled != null && enabled.size() == 1 && enabled.contains("true")) {
...
}
Otherwise, if you just want to get the element but don't know what it is, the iterator you suggested works fine.
String getOnlyElement(Set<String> enabled, String default) {
return (enabled == null || enabled.size() != 1) ? default : enabled.iterator().next();
}
I like having null checks but it depends on what methodToGetValues returns.
Unsure of what the use case is that would drive using a Set<String> for this data but here is an option:
// check size = 1 over two checks, use contains rather than grabbing an iterator
if (set.size() == 1 && set.contains("true")) {
...
}
public Set<String> getValues(final String key){
.....
}
public String getValue(final String key) {
final Set<String> values = getValues(key);
if (values == null || values.size() != 1) {
throw new IllegalStateException("Invalid configuration for give key :" + key);
}
return values.iterator().next();
}
public Boolean getValueAsBoolean(final String key) {
return Boolean.valueOf(getValue(key));
}
You can modify method to have accept argument to return default value when keys are not found. You can add different methods to return specific type object like inte, boolean, this way code looks cleaner
Related
I have to Array lists with 1000 objects in each of them. I need to remove all elements in Array list 1 which are there in Array list 2. Currently I am running 2 loops which is resulting in 1000 x 1000 operations in worst case.
List<DataClass> dbRows = object1.get("dbData");
List<DataClass> modifiedData = object1.get("dbData");
List<DataClass> dbRowsForLog = object2.get("dbData");
for (DataClass newDbRows : dbRows) {
boolean found=false;
for (DataClass oldDbRows : dbRowsForLog) {
if (newDbRows.equals(oldDbRows)) {
found=true;
modifiedData.remove(oldDbRows);
break;
}
}
}
public class DataClass{
private int categoryPosition;
private int subCategoryPosition;
private Timestamp lastUpdateTime;
private String lastModifiedUser;
// + so many other variables
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
DataClass dataClassRow = (DataClass) o;
return categoryPosition == dataClassRow.categoryPosition
&& subCategoryPosition == dataClassRow.subCategoryPosition && (lastUpdateTime.compareTo(dataClassRow.lastUpdateTime)==0?true:false)
&& stringComparator(lastModifiedUser,dataClassRow.lastModifiedUser);
}
public String toString(){
return "DataClass[categoryPosition="+categoryPosition+",subCategoryPosition="+subCategoryPosition
+",lastUpdateTime="+lastUpdateTime+",lastModifiedUser="+lastModifiedUser+"]";
}
public static boolean stringComparator(String str1, String str2){
return (str1 == null ? str2 == null : str1.equals(str2));
}
public int hashCode() {
int hash = 7;
hash = 31 * hash + (int) categoryPosition;
hash = 31 * hash + (int) subCategoryPosition
hash = 31 * hash + (lastModifiedUser == null ? 0 : lastModifiedUser.hashCode());
return hash;
}
}
The best work around i could think of is create 2 sets of strings by calling tostring() method of DataClass and compare string. It will result in 1000 (for making set1) + 1000 (for making set 2) + 1000 (searching in set ) = 3000 operations. I am stuck in Java 7. Is there any better way to do this? Thanks.
Let Java's builtin collections classes handle most of the optimization for you by taking advantage of a HashSet. The complexity of its contains method is O(1). I would highly recommend looking up how it achieves this because it's very interesting.
List<DataClass> a = object1.get("dbData");
HashSet<DataClass> b = new HashSet<>(object2.get("dbData"));
a.removeAll(b);
return a;
And it's all done for you.
EDIT: caveat
In order for this to work, DataClass needs to implement Object::hashCode. Otherwise, you can't use any of the hash-based collection algorithms.
EDIT 2: implementing hashCode
An object's hash code does not need to change every time an instance variable changes. The hash code only needs to reflect the instance variables that determine equality.
For example, imagine each object had a unique field private final UUID id. In this case, you could determine if two objects were the same by simply testing the id value. Fields like lastUpdateTime and lastModifiedUser would provide information about the object, but two instances with the same id would refer to the same object, even if the lastUpdateTime and lastModifiedUser of each were different.
The point is that if you really want to want to optimize this, include as few fields as possible in the hash computation. From your example, it seems like categoryPosition and subCategoryPosition might be enough.
Whatever fields you choose to include, the simplest way to compute a hash code from them is to use Objects::hash rather than running the numbers yourself.
It is a Set A-B operation(only retain elements in Set A that are not in Set B = A-B)
If using Set is fine then we can do like below. We can use ArrayList as well in place of Set but in AL case for each element to remove/retain check it needs to go through an entire other list scan.
Set<DataClass> a = new HashSet<>(object1.get("dbData"));
Set<DataClass> b = new HashSet<>(object2.get("dbData"));
a.removeAll(b);
If ordering is needed, use TreeSet.
Try to return a set from object1.get("dbData") and object2.get("dbData") that skips one more intermediate collection creation.
I'm trying to make a bit of code that returns a boolean value depending on whether an item was successfully removed from a HashMap or not.
My understanding is that map.remove(Key) should return the Key if it worked and null if not. My approach was to check if the return value is null and print false if it is, true if anything else.
The problem I'm having comes from that I don't know how to check what the return value was inside my method.
Here is my attempt so far.
public boolean deleteMapEntry(String entry)
{
testMap.remove(entry);
if(null)
{
return false;
}
else
{
return true;
}
}
Obviously saying if (null) doesn't work, but I can't find what would.
You need to assign the value of testMap.remove(entry) to a variable to test it to see if it is null...
String value = testMap.remove(entry);
return value != null;
you can also just test what you remove directly and not use a variable:
return testMap.remove(entry) != null;
private Map<Group, List<Contact>> groupedContactList =
new HashMap<Group, List<Contact>>();
I'm trying to implement a getGroup(int position) method but I'm having trouble.
I've tried (Group)groupedContactList.keySet().toArray()[position]; but its not working.
EDIT: the getGroup() method must be overriden because I am extending an adapter so I cant change the method signature unfortunately.
A Map object lends itself well to using a key rather than a position value to get what you're looking for.
Map objects store information in key/value pairs. In your example, the key is a Group and the value is a List of Contacts. In order for it all to work, your key object must implement the equals(Object object) method.
public class Group {
//lots of really great code that defines a Group
public boolean equals(Object obj) {
if( Object == null ) return false;
if( !(Object instanceof Group) ) return false;
if( this == obj ) return true;
Group compareMe = (Group)obj;
if( this.getId() != null && compareMe.getId() != null && this.getId().equals(compareMe.getId()) ) return true;
return false;
}
}
Then the map.get(Group key) can be used to get what you are looking for.
The real issue is that Maps are not sorted collections. There is no guaranteed order to the way the information is stored there, so you can't really be guaranteed that getting something based on position value 1 will be the same every time.
If you use a LinkedHashMap, which preserves the order in whick the key/value pairs were added, I think your code should work. Give it a try.
is it possible to do something like
criteria.add(Expression.eq("product", " * "))
for it to match everything ?
It would be handy in case that you get a variable that can have many values and a special value "all" that matches against everything. So you can call a method like this and if the variable had a value of "all", then the expression would match everything.
public void someFunction(String variable) {
criteria.add(Expression.eq("product", variable))
}
EDITED: If I had 2 select fields with Source Language & Destination Language and a table listing entries based on which language combination it contains, with IF STATEMENTS it would look like this: (DynamicQuery is an abstraction for Criteria)
private DynamicQuery addCriteria(DynamicQuery dq, String languageFrom, String languageTo){
if (null != languageFrom && !languageFrom.isEmpty() && null != languageTo && !languageTo.isEmpty()){
if(languageFrom.equals("All") && languageTo.equals("All")) {
return dq;
} else if (!languageFrom.equals("All") && !languageTo.equals("All")) {
dq.add(PropertyFactoryUtil.forName("languageFrom").eq(languageFrom));
dq.add(PropertyFactoryUtil.forName("languageTo").eq(languageTo));
return dq;
} else if (languageFrom.equals("All") && !languageTo.equals("All")) {
dq.add(PropertyFactoryUtil.forName("languageTo").eq(languageTo));
return dq;
} else if (!languageFrom.equals("All") && languageTo.equals("All")) {
dq.add(PropertyFactoryUtil.forName("languageFrom").eq(languageFrom));
return dq;
}
}
}
It's disgusting, consider there would be one more field, it would be even more disgusting...One simply must cover all the combinations that might occur ... That's why I would like to have something like REGEX, because I would assign variable the reqex "*" value and I would add two lines like this
dq.add(PropertyFactoryUtil.forName("languageFrom").eq(languageFromVariable));
dq.add(PropertyFactoryUtil.forName("languageTo").eq(languageToVariable));
if (null != variable && !variable.isEmpty()){
criteria.add(Expression.eq("product", variable)) ;
}
If you only need it when it is selected. You may wanna add an if statement so criteria is added only when needed.
Edit 1:
You can define a method if you are gonna use it for more than fields. Even you can define different criterias inside here. Easy maintance (as is used by all and centrilized), code reuse (change at one point at it will be effective to all)
addCriteria(Criteria criteria, String name, String value){
//you wanna handle special cases like null == name as well accordingly
if (null != value && !value.isEmpty() && null != name && !name.isEmpty()){
criteria.add(Expression.eq(name, value)) ;
}
}
I have written this function which will set
val=max or min (if val comes null)
or val=val (val comes as an Integer or "max" or "min")
while calling i am probably sending checkValue(val,"min") or checkValue(val,"max")
public String checkValue(String val,String valType)
{
System.out.println("outside if val="+val);
if(!val.equals("min") && !val.equals("max"))
{
System.out.println("Inside if val="+val);
try{
System.out.println("*Inside try val="+val);
Integer.parseInt(val);
}
catch(NumberFormatException nFE)
{
System.out.println("***In catch val="+val);
val=valType;
}
return val;
}
else
{
return val;
}
}
But the problem is if val comes null then
outside if******val=null
is shown.
Can any1 tell me is this a logical mistake?
And why will I correct?
If val is null, then the expression val.equals("min") will throw an exception.
You could correct this by using:
if (!"min".equals(val) && !"max".equals(val))
to let it go inside the if block... but I would personally handle it at the start of the method:
if (val == null) {
// Do whatever you want
}
Btw, for the sake of readability you might want to consider allowing a little more whitespace in your code... at the moment it's very dense, which makes it harder to read.
...the problem is if val comes null then outside if****val=null is shown. Can any1 tell me is this a logical mistake?
The output is correct; whether you want it to come out that way is up to you.
Your next line
if(!val.equals("min") && !val.equals("max")){
...will throw a NullPointerException because you're trying to dereference val, which is null. You'll want to add an explicit check for whether val is null:
if (val == null) {
// Do what you want to do when val == null
}
you should use valType instead of val to check either minimum or maximum is necessary to check.
My advice to you in such cases to use boolean value or enum instead of strings. Consider something like that:
/**
* check the value for minimum if min is true and for maximum otherwise
*/
public String checkValue(String val, boolean min){
if (min) {
// ...
} else {
// ...
}
}
If you need to compare strings against constants you should write it the other way around to make it null-safe:
if (! "min".equals(val))
And while this is mostly a style issue, I would make all method arguments final and not re-assign them (because that is confusing), and you can also return from within the method, not just at the end. Or if you want to return at the end, do it at the very end, not have the same return statement in both the if and the else branch.