i'm curently developing app which has lots of ArraYlists and it needs to compare them with nonlist data. When i try this method fdata.contains(data2) it always returns false. ArayLists contains class named 'favdat' which looks like this:`
public class favdat {
public String product,term,note,link;
}
And Data2 is defined like this: favdat Data2=new favdat();
I have also tryed retain all method and it returns list in the size of 0.
I know that some data are equal.
So the question is how could i tell if fdata contains data2?
The default implementation to compare objects is to compare if they are the same object, so two objects with the exactly same attributes would still not be equals. What you need to do is override the hashCode and equals methods. As an example:
public int hashCode() {
return product.hashCode() * 31 + term.hashCode();
}
public boolean equals(Object o) {
if (o instanceof favdata) {
favdata other = (favdata) o;
return product.equals(other.product)
&& term.equals(other.term)
&& note.equals(other.note)
&& link.equals(other.link);
} else {
return false;
}
}
In java classnames are usually started with capitals, so it would be Favdat, and your code usually gets easier to read to keep the field declarations separate.
You need to define a method called equals(Object obj) inside favdat that will enable object comparison.
Here's a more detailed howto:
Comparing Objects in Java
Also related thread in SO, talk about how ArrayList.contains() work.
Related
I have a two kotlin object which are very identical data without any change, but getting return false. which has to be return true if two object are identical, only if change then it should be return false.
Doing checking objects are:
private var emp1: Employee? = null
var emp2: Employee? = null
fun dataChanged(): Boolean {
return if (emp1 != null && emp2 != null) {
emp1 != emp2
} else {
false
}
}
I checked the data in log, which is not changing anyhing not even space.
Employee defiend as follows,
data class Employee(
//...
): Parcelable {
//...
}
No equals and hashcode.
here using for changing data change on edittext -> TextInputEditText, TextWatcher. Any suggestion, where, i'm doing wrong.
Thanks in advance.
When you define a data class compiler automatically derives the following members from all properties declared in the primary constructor:
equals()/hashCode() pair;
...
Therefore equals method execution depends on parameters of primary constructor.
If you use some other objects in primary constructor make sure they are also data classes or have overriden equals method.
I suggest to put logs before comparison of two objects and check whether they contain equal data.
EDIT:
I have a two kotlin object which are very identical data without any change, but getting return false.
Your function dataChanged() returns false for two identical objects because of condition emp1 != emp2. The name of the function says that it will return true if objects are not identical, false - if they are identical, i.e. data not changed. So the function dataChanged() works as expected.
I have a use case that is as simple as this: Look for a Book in the Remote source, if it doesn't exist, create it.
So this is my approach that used to work with rxJava1:
public void handleBook(int id) {
getBookById(id)
.flatMap(new Func1<Book, Observable<Book>> {
#Override
public Observable<Book> call(Book book) {
if(book != null) // it exists
...
else // it's null - it doesn't exist ...
}
}
}
public Observable<Book> getBookById(int id) {
Book book = remoteSource.book(id)
return Observable.just(book)
}
In this case if the object book is null, the Observable.just call throws an exception. It's explicitly checking against null values.
Back for rxJava 1 I could pass a null as value to Observable.just (or other accesoars), then in the map or flatMap operators I'd check if the value I get is null (meaning result does not exist) or not (meaning I got some result).
With this limitation it seems that I cannot do this check anymore. I tried returning Observable.empty() in case the book object is null but then the whole thread would complete and finish when the returned value is Observable.empty().
How can I check in a rx-chain of execution if something I need is there and branch the chain of execution afterwards?
Instead of using Observable<Book> as a return type use Single<Book>. Single type emits either an object or an error
NOTE: Right now I don't have an IDE so the code will probably have some compiler fails. I assume you'll fix it easily
public Single<Book> getBookById(int id) {
return Single.create((e) => {
Book book = remoteSource.book(id)
if (book != null)
e.emit(book);
else
e.fail();
}
}
public void handleBook(int id) {
getBookById(id)
.onErrorResume(e => createBook(...))
...
}
Like a said earlier I'm not sure about the exact code but you can read it as if it was pseudo-code
I'm implementing the MVP design pattern. My presenter receives the new values from the view. I want to manage the state of a next button by automatically check if everything is valid when values are updated on the view.
In my form I have an optional part which is displayed only if the user select the correct option.
In this optional part I have a binary question. If the part is not displayed I need to set the value of the question to null on the Presenter side.
For example, the user select the option and the optional part is displayed. The user select the answer. Then the user change the option and the optional part is hidden. In that case I need to set the answer to the optional question to null, for the answer to not be already selected if the user display the optional part again.
To do so, I call a method on the Presenter with a null value instead of true/false.
Here is the code:
private final PublishSubject<Boolean> mObsOptionalAnswer = PublishSubject.create();
public MyPresenter(){
// Combine all the values together to enable/disable the next button
Observable.combineLatest(
// ... other fields
// I need this to return false if the optional part is
// displayed but nothing is selected
mObsOptionalAnswer.map(this::isValid),
(...) -> ...
).subscrible(enable ->{
mView.enableBtn(enable);
});
}
public void myFunction(Boolean isSomething){
// ... some code
mObsOptionalAnswer.onNext(isSomething);
}
private boolean isValid(Boolean value){
return value != null;
}
The problem is, since RxJava 2, null values are not allowed in the onNext() method.
So, how am I supposed to manage that?
If you want to be able to send a null value, you can use a wrapper. In this configuration, you send the wrapper, which isn't null even if the value itself is.
public class BooleanWrapper {
public final Boolean value;
public BooleanWrapper(Boolean value) {
this.value = value;
}
}
Your PublishSubject<Boolean> becomes a PublishSubject<BooleanWrapper> and you just have to create the wrapper and de-reference your Boolean when needed :
mObsOptionalAnswer.onNext(new BooleanWrapper(isSomething));
and
mObsOptionalAnswer.map(wrapper -> this.isValid(wrapper.value))
If you need to do that more than once in your code, you can create a generic wrapper (as described by this tutorial) :
public class Optional<M> {
private final M optional;
public Optional(#Nullable M optional) {
this.optional = optional;
}
public boolean isEmpty() {
return this.optional == null;
}
public M get() {
return optional;
}
}
you could use a constante Boolean object
public static final Boolean RESET_VALUE = new Boolean(false);
and you can emit this instead of emitting null. The receiver would have to check against this instance and behaving accordingly. Eg.
.subscrible(enable ->{
if (enable != RESET_VALUE) {
mView.enableBtn(enable);
}
});
regarding my code example down, what shold I do if one Locable's variables is null? In example, now if l.getZoom() returns null, I got NullPointerException.
#Override
public void writeToParcel(Parcel parcel, int arg1) {
parcel.writeInt(count);
for(Locable l:locableArr){
parcel.writeInt(l.getOriginId());
parcel.writeInt(l.getLocableType());
parcel.writeInt(l.getZoom());
parcel.writeDouble(l.getLatituda());
parcel.writeDouble(l.getLongituda());
parcel.writeString(l.getTitle());
parcel.writeString(l.getSnipet());
}
}
Thanks!
You can use Parcel.writeValue for marshalling generic object with null value.
I'm using a Parcelable class that has Integer and Boolean fields as well, and those fields can be null.
I had trouble using the generic Parcel.writeValue method, particularly when I was trying to read it back out via Parcel.readValue. I kept getting a runtime exception that said it couldn't figure out the type of the parceled object.
Ultimately, I was able to solve the problem by using Parcel.writeSerializable and Parcel.readSerializable with a type cast, as both Integer and Boolean implement the Serializable interface. The read and write methods handle null values for you.
This is the solution I came up with to write strings safely:
private void writeStringToParcel(Parcel p, String s) {
p.writeByte((byte)(s != null ? 1 : 0));
p.writeString(s);
}
private String readStringFromParcel(Parcel p) {
boolean isPresent = p.readByte() == 1;
return isPresent ? p.readString() : null;
}
Most serialization code that I've seen uses either flags to indicate the presence/absence of a value OR precedes the value with a count field (for example, when writing arrays) where the count field is just set to zero if the value doesn't exist at all.
Examining the source code of Android core classes reveals code like this (from Message class):
if (obj != null) {
try {
Parcelable p = (Parcelable)obj;
dest.writeInt(1);
dest.writeParcelable(p, flags);
} catch (ClassCastException e) {
throw new RuntimeException(
"Can't marshal non-Parcelable objects across processes.");
}
} else {
dest.writeInt(0);
}
or this (from Intent class):
if (mCategories != null) {
out.writeInt(mCategories.size());
for (String category : mCategories) {
out.writeString(category);
}
} else {
out.writeInt(0);
}
My suggestion: In your code, if there is no functional difference between "zoom == null" and "zoom == 0", then I would just declare zoom as a primitive (int instead of Integer) OR initialize it to zero in the constructor and ensure that you never set it to null (then you can be guaranteed that it will never be null and you won't have to add special code to deal with that in your serialization/deserialization methods).
I'm working on an app in android studio. The part of the app I'm having issues with is where the user can favourite and remove their favourite item. I do this by adding and removing the item from a list.
The thing is the add functionality works which is:
public void addFavorite(Context context, NewSubject subject) {
List<NewSubject> favorites = getFavorites(context);
if (favorites == null)
favorites = new ArrayList<NewSubject>();
favorites.add(subject);
saveFavorites(context, favorites);
}
I am passing in an object of type "NewSubject" which is just a class of getters and setters for name and id.
The problem arises when I try to remove an item from this list. Code below:
public void removeFavorite(Context context, NewSubject subject) {
ArrayList<NewSubject> favorites = getFavorites(context);
if (favorites != null) {
favorites.remove(subject);
saveFavorites(context, favorites);
}
}
I've even tried something like:
for(int i = 0; i < favorites.size(); i++){
if(favorites.get(i).getSubject_name() == subject.getSubject_name())
favorites.remove(i);
}
Even though both subject names match, the if statement never triggers as true. By changing it to ID it does remove the item but I was wondering why it doesn't work the other way. MeetTitan suggested to use "equals" operator to compare Strings and this has fixed that issue. But I'm still wondering as to why removing the item by "subject" without the FOR loop and IF statement doesn't work.
I have cleared the app's data multiple times whilst trying to debug the source of the problem.
Thank you for your time and help, it is much appreciated.
This applies if you are re-creating NewSubject twice... If you are trying to remove the exact same instance of NewSubject that you got from the collection, then I guessed wrong and this isn't the answer you are looking for.
Is it possible you haven't defined equals and hashCode in your Favorites object? Without those remove will only work with the EXACT same object instance in the collection. If you haven't, try defining them and see if remove() works the way you expect.
Without those methods defined, collections will respond this way:
Obj x=new Obj("data")
Obj y=new Obj("data")
collection.put(x)
collection.remove(y)
assert( collection.size() == 1) // was not removed because .equals didn't exist--remove reverted to == instead which failed, x != y
collection.remove(x)
assert( collection.size() == 0) // NOW it worked because you used the same instance.
if you define .equals and hashCode to compare the strings inside obj, then this will work:
collection.put(x)
collection.remove(y)
assert( collection.size() == 0) // worked because x.equals(y)!
Try
String.equalsIgnoreCase(value1,value2)
This might do your work.
From your example, it's evident that name is a String object. In java, you have to use ".equals()" or comparing two strings.
You can do this:
if(favorites.get(i).getSubject_name().equals(subject.getSubject_name())){
...
}
Or, you can override the equals() method in your NewSubject class to make this work:
favorites.remove(subject);
You can use something like this as your equals() method in the NewSubject class (considering you are only matching two NewSubject objects based on their names):
#Override
public boolean equals(Object other){
if (other == null) return false;
if (other == this) return true;
NewSubject otherSubject = (NewSubject) other;
if(this.getSubject_name().equals(otherSubject.getSubject_name()))
return true;
else
return false;
}
Update:
You may want to override hashcode() as well. If your NewSubject class ever gets used in a hash-based collection such as HashMap, overriding only equals() method will not be sufficient. For reference, this is from Effective Java by Joshua Bloch:
You must override hashCode() in every class that overrides equals().
Failure to do so will result in a violation of the general contract
for Object.hashCode(), which will prevent your class from functioning
properly in conjunction with all hash-based collections, including
HashMap, HashSet, and Hashtable.