Checking for duplicated data in Java array list [duplicate] - java

I want to check whether a List contains an object that has a field with a certain value. Now, I could use a loop to go through and check, but I was curious if there was anything more code efficient.
Something like;
if(list.contains(new Object().setName("John"))){
//Do some stuff
}
I know the above code doesn't do anything, it's just to demonstrate roughly what I am trying to achieve.
Also, just to clarify, the reason I don't want to use a simple loop is because this code will currently go inside a loop that is inside a loop which is inside a loop. For readability I don't want to keep adding loops to these loops. So I wondered if there were any simple(ish) alternatives.

Streams
If you are using Java 8, perhaps you could try something like this:
public boolean containsName(final List<MyObject> list, final String name){
return list.stream().filter(o -> o.getName().equals(name)).findFirst().isPresent();
}
Or alternatively, you could try something like this:
public boolean containsName(final List<MyObject> list, final String name){
return list.stream().map(MyObject::getName).filter(name::equals).findFirst().isPresent();
}
This method will return true if the List<MyObject> contains a MyObject with the name name. If you want to perform an operation on each of the MyObjects that getName().equals(name), then you could try something like this:
public void perform(final List<MyObject> list, final String name){
list.stream().filter(o -> o.getName().equals(name)).forEach(
o -> {
//...
}
);
}
Where o represents a MyObject instance.
Alternatively, as the comments suggest (Thanks MK10), you could use the Stream#anyMatch method:
public boolean containsName(final List<MyObject> list, final String name){
return list.stream().anyMatch(o -> name.equals(o.getName()));
}

You have two choices.
1. The first choice, which is preferable, is to override the `equals()` method in your Object class.
Let's say, for example, you have this Object class:
public class MyObject {
private String name;
private String location;
//getters and setters
}
Now let's say you only care about the MyObject's name, that it should be unique so if two `MyObject`s have the same name they should be considered equal. In that case, you would want to override the `equals()` method (and also the `hashcode()` method) so that it compares the names to determine equality.
Once you've done this, you can check to see if a Collection contains a MyObject with the name "foo" by like so:
MyObject object = new MyObject();
object.setName("foo");
collection.contains(object);
However, this might not be an option for you if:
You are using both the name and location to check for equality, but you only want to check if a Collection has any `MyObject`s with a certain location. In this case, you've already overridden `equals()`.
`MyObject` is part of an API that you don't have liberty to change.
If either of these are the case, you'll want option 2:
2. Write your own utility method:
public static boolean containsLocation(Collection<MyObject> c, String location) {
for(MyObject o : c) {
if(o != null && o.getLocation.equals(location)) {
return true;
}
}
return false;
}
Alternatively, you could extend ArrayList (or some other collection) and then add your own method to it:
public boolean containsLocation(String location) {
for(MyObject o : this) {
if(o != null && o.getLocation.equals(location)) {
return true;
}
}
return false;
}
Unfortunately there's not a better way around it.

This is how to do it using Java 8+ :
boolean isJohnAlive = list.stream().anyMatch(o -> "John".equals(o.getName());

Google Guava
If you're using Guava, you can take a functional approach and do the following
FluentIterable.from(list).find(new Predicate<MyObject>() {
public boolean apply(MyObject input) {
return "John".equals(input.getName());
}
}).Any();
which looks a little verbose. However the predicate is an object and you can provide different variants for different searches. Note how the library itself separates the iteration of the collection and the function you wish to apply. You don't have to override equals() for a particular behaviour.
As noted below, the java.util.Stream framework built into Java 8 and later provides something similar.

Collection.contains() is implemented by calling equals() on each object until one returns true.
So one way to implement this is to override equals() but of course, you can only have one equals.
Frameworks like Guava therefore use predicates for this. With Iterables.find(list, predicate), you can search for arbitrary fields by putting the test into the predicate.
Other languages built on top of the VM have this built in. In Groovy, for example, you simply write:
def result = list.find{ it.name == 'John' }
Java 8 made all our lives easier, too:
List<Foo> result = list.stream()
.filter(it -> "John".equals(it.getName())
.collect(Collectors.toList());
If you care about things like this, I suggest the book "Beyond Java". It contains many examples for the numerous shortcomings of Java and how other languages do better.

Binary Search
You can use Collections.binarySearch to search an element in your list (assuming the list is sorted):
Collections.binarySearch(list, new YourObject("a1", "b",
"c"), new Comparator<YourObject>() {
#Override
public int compare(YourObject o1, YourObject o2) {
return o1.getName().compareTo(o2.getName());
}
});
which will return a negative number if the object is not present in the collection or else it will return the index of the object. With this you can search for objects with different searching strategies.

Map
You could create a Hashmap<String, Object> using one of the values as a key, and then seeing if yourHashMap.keySet().contains(yourValue) returns true.

Eclipse Collections
If you're using Eclipse Collections, you can use the anySatisfy() method. Either adapt your List in a ListAdapter or change your List into a ListIterable if possible.
ListIterable<MyObject> list = ...;
boolean result =
list.anySatisfy(myObject -> myObject.getName().equals("John"));
If you'll do operations like this frequently, it's better to extract a method which answers whether the type has the attribute.
public class MyObject
{
private final String name;
public MyObject(String name)
{
this.name = name;
}
public boolean named(String name)
{
return Objects.equals(this.name, name);
}
}
You can use the alternate form anySatisfyWith() together with a method reference.
boolean result = list.anySatisfyWith(MyObject::named, "John");
If you cannot change your List into a ListIterable, here's how you'd use ListAdapter.
boolean result =
ListAdapter.adapt(list).anySatisfyWith(MyObject::named, "John");
Note: I am a committer for Eclipse ollections.

Predicate
If you dont use Java 8, or library which gives you more functionality for dealing with collections, you could implement something which can be more reusable than your solution.
interface Predicate<T>{
boolean contains(T item);
}
static class CollectionUtil{
public static <T> T find(final Collection<T> collection,final Predicate<T> predicate){
for (T item : collection){
if (predicate.contains(item)){
return item;
}
}
return null;
}
// and many more methods to deal with collection
}
i'm using something like that, i have predicate interface, and i'm passing it implementation to my util class.
What is advantage of doing this in my way? you have one method which deals with searching in any type collection. and you dont have to create separate methods if you want to search by different field. alll what you need to do is provide different predicate which can be destroyed as soon as it no longer usefull/
if you want to use it, all what you need to do is call method and define tyour predicate
CollectionUtil.find(list, new Predicate<MyObject>{
public boolean contains(T item){
return "John".equals(item.getName());
}
});

Here is a solution using Guava
private boolean checkUserListContainName(List<User> userList, final String targetName){
return FluentIterable.from(userList).anyMatch(new Predicate<User>() {
#Override
public boolean apply(#Nullable User input) {
return input.getName().equals(targetName);
}
});
}

contains method uses equals internally. So you need to override the equals method for your class as per your need.
Btw this does not look syntatically correct:
new Object().setName("John")

If you need to perform this List.contains(Object with field value equal to x) repeatedly, a simple and efficient workaround would be:
List<field obj type> fieldOfInterestValues = new ArrayList<field obj type>;
for(Object obj : List) {
fieldOfInterestValues.add(obj.getFieldOfInterest());
}
Then the List.contains(Object with field value equal to x) would be have the same result as fieldOfInterestValues.contains(x);

Despite JAVA 8 SDK there is a lot of collection tools libraries can help you to work with, for instance:
http://commons.apache.org/proper/commons-collections/
Predicate condition = new Predicate() {
boolean evaluate(Object obj) {
return ((Sample)obj).myField.equals("myVal");
}
};
List result = CollectionUtils.select( list, condition );

Related

Accessing an element in a Set [duplicate]

Why doesn't Set provide an operation to get an element that equals another element?
Set<Foo> set = ...;
...
Foo foo = new Foo(1, 2, 3);
Foo bar = set.get(foo); // get the Foo element from the Set that equals foo
I can ask whether the Set contains an element equal to bar, so why can't I get that element? :(
To clarify, the equals method is overridden, but it only checks one of the fields, not all. So two Foo objects that are considered equal can actually have different values, that's why I can't just use foo.
To answer the precise question "Why doesn't Set provide an operation to get an element that equals another element?", the answer would be: because the designers of the collection framework were not very forward looking. They didn't anticipate your very legitimate use case, naively tried to "model the mathematical set abstraction" (from the javadoc) and simply forgot to add the useful get() method.
Now to the implied question "how do you get the element then": I think the best solution is to use a Map<E,E> instead of a Set<E>, to map the elements to themselves. In that way, you can efficiently retrieve an element from the "set", because the get() method of the Map will find the element using an efficient hash table or tree algorithm. If you wanted, you could write your own implementation of Set that offers the additional get() method, encapsulating the Map.
The following answers are in my opinion bad or wrong:
"You don't need to get the element, because you already have an equal object": the assertion is wrong, as you already showed in the question. Two objects that are equal still can have different state that is not relevant to the object equality. The goal is to get access to this state of the element contained in the Set, not the state of the object used as a "query".
"You have no other option but to use the iterator": that is a linear search over a collection which is totally inefficient for large sets (ironically, internally the Set is organized as hash map or tree that could be queried efficiently). Don't do it! I have seen severe performance problems in real-life systems by using that approach. In my opinion what is terrible about the missing get() method is not so much that it is a bit cumbersome to work around it, but that most programmers will use the linear search approach without thinking of the implications.
There would be no point of getting the element if it is equal. A Map is better suited for this usecase.
If you still want to find the element you have no other option but to use the iterator:
public static void main(String[] args) {
Set<Foo> set = new HashSet<Foo>();
set.add(new Foo("Hello"));
for (Iterator<Foo> it = set.iterator(); it.hasNext(); ) {
Foo f = it.next();
if (f.equals(new Foo("Hello")))
System.out.println("foo found");
}
}
static class Foo {
String string;
Foo(String string) {
this.string = string;
}
#Override
public int hashCode() {
return string.hashCode();
}
#Override
public boolean equals(Object obj) {
return string.equals(((Foo) obj).string);
}
}
If you have an equal object, why do you need the one from the set? If it is "equal" only by a key, an Map would be a better choice.
Anyway, the following will do it:
Foo getEqual(Foo sample, Set<Foo> all) {
for (Foo one : all) {
if (one.equals(sample)) {
return one;
}
}
return null;
}
With Java 8 this can become a one liner:
return all.stream().filter(sample::equals).findAny().orElse(null);
Default Set in Java is, unfortunately, not designed to provide a "get" operation, as jschreiner accurately explained.
The solutions of using an iterator to find the element of interest (suggested by dacwe) or to remove the element and re-add it with its values updated (suggested by KyleM), could work, but can be very inefficient.
Overriding the implementation of equals so that non-equal objects are "equal", as stated correctly by David Ogren, can easily cause maintenance problems.
And using a Map as an explicit replacement (as suggested by many), imho, makes the code less elegant.
If the goal is to get access to the original instance of the element contained in the set (hope I understood correctly your use case), here is another possible solution.
I personally had your same need while developing a client-server videogame with Java. In my case, each client had copies of the components stored in the server and the problem was whenever a client needed to modify an object of the server.
Passing an object through the internet meant that the client had different instances of that object anyway. In order to match this "copied" instance with the original one, I decided to use Java UUIDs.
So I created an abstract class UniqueItem, which automatically gives a random unique id to each instance of its subclasses.
This UUID is shared between the client and the server instance, so this way it could be easy to match them by simply using a Map.
However directly using a Map in a similar usecase was still inelegant. Someone might argue that using an Map might be more complicated to mantain and handle.
For these reasons I implemented a library called MagicSet, that makes the usage of an Map "transparent" to the developer.
https://github.com/ricpacca/magicset
Like the original Java HashSet, a MagicHashSet (which is one of the implementations of MagicSet provided in the library) uses a backing HashMap, but instead of having elements as keys and a dummy value as values, it uses the UUID of the element as key and the element itself as value. This does not cause overhead in the memory use compared to a normal HashSet.
Moreover, a MagicSet can be used exactly as a Set, but with some more methods providing additional functionalities, like getFromId(), popFromId(), removeFromId(), etc.
The only requirement to use it is that any element that you want to store in a MagicSet needs to extend the abstract class UniqueItem.
Here is a code example, imagining to retrieve the original instance of a city from a MagicSet, given another instance of that city with the same UUID (or even just its UUID).
class City extends UniqueItem {
// Somewhere in this class
public void doSomething() {
// Whatever
}
}
public class GameMap {
private MagicSet<City> cities;
public GameMap(Collection<City> cities) {
cities = new MagicHashSet<>(cities);
}
/*
* cityId is the UUID of the city you want to retrieve.
* If you have a copied instance of that city, you can simply
* call copiedCity.getId() and pass the return value to this method.
*/
public void doSomethingInCity(UUID cityId) {
City city = cities.getFromId(cityId);
city.doSomething();
}
// Other methods can be called on a MagicSet too
}
If your set is in fact a NavigableSet<Foo> (such as a TreeSet), and Foo implements Comparable<Foo>, you can use
Foo bar = set.floor(foo); // or .ceiling
if (foo.equals(bar)) {
// use bar…
}
(Thanks to #eliran-malka’s comment for the hint.)
With Java 8 you can do:
Foo foo = set.stream().filter(item->item.equals(theItemYouAreLookingFor)).findFirst().get();
But be careful, .get() throws a NoSuchElementException, or you can manipulate a Optional item.
Convert set to list, and then use get method of list
Set<Foo> set = ...;
List<Foo> list = new ArrayList<Foo>(set);
Foo obj = list.get(0);
Why:
It seems that Set plays a useful role in providing a means of comparison. It is designed not to store duplicate elements.
Because of this intention/design, if one were to get() a reference to the stored object, then mutate it, it is possible that the design intentions of Set could be thwarted and could cause unexpected behavior.
From the JavaDocs
Great care must be exercised if mutable objects are used as set elements. The behavior of a set is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is an element in the set.
How:
Now that Streams have been introduced one can do the following
mySet.stream()
.filter(object -> object.property.equals(myProperty))
.findFirst().get();
Object objectToGet = ...
Map<Object, Object> map = new HashMap<Object, Object>(set.size());
for (Object o : set) {
map.put(o, o);
}
Object objectFromSet = map.get(objectToGet);
If you only do one get this will not be very performing because you will loop over all your elements but when performing multiple retrieves on a big set you will notice the difference.
you can use Iterator class
import java.util.Iterator;
import java.util.HashSet;
public class MyClass {
public static void main(String[ ] args) {
HashSet<String> animals = new HashSet<String>();
animals.add("fox");
animals.add("cat");
animals.add("dog");
animals.add("rabbit");
Iterator<String> it = animals.iterator();
while(it.hasNext()) {
String value = it.next();
System.out.println(value);
}
}
}
it looks like the proper object to use is the Interner from guava :
Provides equivalent behavior to String.intern() for other immutable
types. Common implementations are available from the Interners
class.
It also has a few very interesting levers, like concurrencyLevel, or the type of references used (it might be worth noting that it doesn't offer a SoftInterner which I could see as more useful than a WeakInterner).
I know, this has been asked and answered long ago, however if anyone is interested, here is my solution - custom set class backed by HashMap:
http://pastebin.com/Qv6S91n9
You can easily implement all other Set methods.
Been there done that!! If you are using Guava a quick way to convert it to a map is:
Map<Integer,Foo> map = Maps.uniqueIndex(fooSet, Foo::getKey);
If you want nth Element from HashSet, you can go with below solution,
here i have added object of ModelClass in HashSet.
ModelClass m1 = null;
int nth=scanner.nextInt();
for(int index=0;index<hashset1.size();index++){
m1 = (ModelClass) itr.next();
if(nth == index) {
System.out.println(m1);
break;
}
}
If you look at the first few lines of the implementation of java.util.HashSet you will see:
public class HashSet<E>
....
private transient HashMap<E,Object> map;
So HashSet uses HashMap interally anyway, which means that if you just use a HashMap directly and use the same value as the key and the value you will get the effect you want and save yourself some memory.
Because any particular implementation of Set may or may not be random access.
You can always get an iterator and step through the Set, using the iterators' next() method to return the result you want once you find the equal element. This works regardless of the implementation. If the implementation is NOT random access (picture a linked-list backed Set), a get(E element) method in the interface would be deceptive, since it would have to iterate the collection to find the element to return, and a get(E element) would seem to imply this would be necessary, that the Set could jump directly to the element to get.
contains() may or may not have to do the same thing, of course, depending on the implementation, but the name doesn't seem to lend itself to the same sort of misunderstandings.
Yes, use HashMap ... but in a specialised way: the trap I foresee in trying to use a HashMap as a pseudo-Set is the possible confusion between "actual" elements of the Map/Set, and "candidate" elements, i.e. elements used to test whether an equal element is already present. This is far from foolproof, but nudges you away from the trap:
class SelfMappingHashMap<V> extends HashMap<V, V>{
#Override
public String toString(){
// otherwise you get lots of "... object1=object1, object2=object2..." stuff
return keySet().toString();
}
#Override
public V get( Object key ){
throw new UnsupportedOperationException( "use tryToGetRealFromCandidate()");
}
#Override
public V put( V key, V value ){
// thorny issue here: if you were indavertently to `put`
// a "candidate instance" with the element already in the `Map/Set`:
// these will obviously be considered equivalent
assert key.equals( value );
return super.put( key, value );
}
public V tryToGetRealFromCandidate( V key ){
return super.get(key);
}
}
Then do this:
SelfMappingHashMap<SomeClass> selfMap = new SelfMappingHashMap<SomeClass>();
...
SomeClass candidate = new SomeClass();
if( selfMap.contains( candidate ) ){
SomeClass realThing = selfMap.tryToGetRealFromCandidate( candidate );
...
realThing.useInSomeWay()...
}
But... you now want the candidate to self-destruct in some way unless the programmer actually immediately puts it in the Map/Set... you'd want contains to "taint" the candidate so that any use of it unless it joins the Map makes it "anathema". Perhaps you could make SomeClass implement a new Taintable interface.
A more satisfactory solution is a GettableSet, as below. However, for this to work you have either to be in charge of the design of SomeClass in order to make all constructors non-visible (or... able and willing to design and use a wrapper class for it):
public interface NoVisibleConstructor {
// again, this is a "nudge" technique, in the sense that there is no known method of
// making an interface enforce "no visible constructor" in its implementing classes
// - of course when Java finally implements full multiple inheritance some reflection
// technique might be used...
NoVisibleConstructor addOrGetExisting( GettableSet<? extends NoVisibleConstructor> gettableSet );
};
public interface GettableSet<V extends NoVisibleConstructor> extends Set<V> {
V getGenuineFromImpostor( V impostor ); // see below for naming
}
Implementation:
public class GettableHashSet<V extends NoVisibleConstructor> implements GettableSet<V> {
private Map<V, V> map = new HashMap<V, V>();
#Override
public V getGenuineFromImpostor(V impostor ) {
return map.get( impostor );
}
#Override
public int size() {
return map.size();
}
#Override
public boolean contains(Object o) {
return map.containsKey( o );
}
#Override
public boolean add(V e) {
assert e != null;
V result = map.put( e, e );
return result != null;
}
#Override
public boolean remove(Object o) {
V result = map.remove( o );
return result != null;
}
#Override
public boolean addAll(Collection<? extends V> c) {
// for example:
throw new UnsupportedOperationException();
}
#Override
public void clear() {
map.clear();
}
// implement the other methods from Set ...
}
Your NoVisibleConstructor classes then look like this:
class SomeClass implements NoVisibleConstructor {
private SomeClass( Object param1, Object param2 ){
// ...
}
static SomeClass getOrCreate( GettableSet<SomeClass> gettableSet, Object param1, Object param2 ) {
SomeClass candidate = new SomeClass( param1, param2 );
if (gettableSet.contains(candidate)) {
// obviously this then means that the candidate "fails" (or is revealed
// to be an "impostor" if you will). Return the existing element:
return gettableSet.getGenuineFromImpostor(candidate);
}
gettableSet.add( candidate );
return candidate;
}
#Override
public NoVisibleConstructor addOrGetExisting( GettableSet<? extends NoVisibleConstructor> gettableSet ){
// more elegant implementation-hiding: see below
}
}
PS one technical issue with such a NoVisibleConstructor class: it may be objected that such a class is inherently final, which may be undesirable. Actually you could always add a dummy parameterless protected constructor:
protected SomeClass(){
throw new UnsupportedOperationException();
}
... which would at least let a subclass compile. You'd then have to think about whether you need to include another getOrCreate() factory method in the subclass.
Final step is an abstract base class (NB "element" for a list, "member" for a set) like this for your set members (when possible - again, scope for using a wrapper class where the class is not under your control, or already has a base class, etc.), for maximum implementation-hiding:
public abstract class AbstractSetMember implements NoVisibleConstructor {
#Override
public NoVisibleConstructor
addOrGetExisting(GettableSet<? extends NoVisibleConstructor> gettableSet) {
AbstractSetMember member = this;
#SuppressWarnings("unchecked") // unavoidable!
GettableSet<AbstractSetMembers> set = (GettableSet<AbstractSetMember>) gettableSet;
if (gettableSet.contains( member )) {
member = set.getGenuineFromImpostor( member );
cleanUpAfterFindingGenuine( set );
} else {
addNewToSet( set );
}
return member;
}
abstract public void addNewToSet(GettableSet<? extends AbstractSetMember> gettableSet );
abstract public void cleanUpAfterFindingGenuine(GettableSet<? extends AbstractSetMember> gettableSet );
}
... usage is fairly obvious (inside your SomeClass's static factory method):
SomeClass setMember = new SomeClass( param1, param2 ).addOrGetExisting( set );
The contract of the hash code makes clear that:
"If two objects are equal according to the Object method, then calling the hashCode method on each of the two objects must produce the same integer result."
So your assumption:
"To clarify, the equals method is overridden, but it only checks one of
the fields, not all. So two Foo objects that are considered equal can
actually have different values, that's why I can't just use foo."
is wrong and you are breaking the contract. If we look at the "contains" method of Set interface, we have that:
boolean contains(Object o);
Returns true if this set contains the specified element. More
formally, returns true if and only if this set contains an element
"e" such that o==null ? e==null : o.equals(e)
To accomplish what you want, you can use a Map where you define the key and store your element with the key that defines how objects are different or equal to each other.
Here's what you can do if you have a NavigableSet (e.g. a TreeSet):
public static <E> E get(NavigableSet<E> set, E key) {
return set.tailSet(key, true).floor(key);
}
The things are slightly trickier for HashSet and its descendants like LinkedHashSet:
import java.util.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Test {
private static final Field mapField;
private static final Method hashMethod;
private static final Method getNodeMethod;
private static final Field keyField;
static {
try {
mapField = HashSet.class.getDeclaredField("map");
mapField.setAccessible(true);
hashMethod = HashMap.class.getDeclaredMethod("hash", Object.class);
hashMethod.setAccessible(true);
getNodeMethod = HashMap.class.getDeclaredMethod("getNode",
Integer.TYPE, Object.class);
getNodeMethod.setAccessible(true);
keyField = Class.forName("java.util.HashMap$Node").getDeclaredField("key");
keyField.setAccessible(true);
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
public static <E> E get(HashSet<E> set, E key) {
try {
Object map = mapField.get(set);
Object hash = hashMethod.invoke(null, key);
Object node = getNodeMethod.invoke(map, hash, key);
if (node == null)
return null;
#SuppressWarnings("unchecked")
E result = (E)keyField.get(node);
return result;
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
public static <E> E get(NavigableSet<E> set, E key) {
return set.tailSet(key, true).floor(key);
}
public static void main(String[] args) {
HashSet<Integer> s = new HashSet<>();
// HashSet<Integer> s = new LinkedHashSet<>();
// TreeSet<Integer> s = new TreeSet<>();
for (int i = 0; i < 100_000; i++)
s.add(i);
Integer key = java.awt.event.KeyEvent.VK_FIND;
Integer hidden = get(s, key);
System.out.println(key);
System.out.println(hidden);
System.out.println(key.equals(hidden));
System.out.println(key == hidden);
}
}
Quick helper method that might address this situation:
<T> T onlyItem(Collection<T> items) {
if (items.size() != 1)
throw new IllegalArgumentException("Collection must have single item; instead it has " + items.size());
return items.iterator().next();
}
Try using an array:
ObjectClass[] arrayName = SetOfObjects.toArray(new ObjectClass[setOfObjects.size()]);
Following can be an approach
SharedPreferences se_get = getSharedPreferences("points",MODE_PRIVATE);
Set<String> main = se_get.getStringSet("mydata",null);
for(int jk = 0 ; jk < main.size();jk++)
{
Log.i("data",String.valueOf(main.toArray()[jk]));
}

Mockito mock object with list argument's contents

I've faced this situation pretty often and don't know how to resolve it using Mockito's default methods such as (any, anyList, eq)
For example I have an object where I want to mock a method expecting a list which contains other mocked objects. Let me explain:
public class MyMapper {
public List<DataObjects> convertList(List<String> rawContents) {
rawContents.stream().map(r -> convertObject(r))
.collect(Collectors.toList());
}
public DataObject convertObject(String rawContent) {
return new DataObject(rawContent);
}
}
public class MyWorkerClass {
public boolean start(List<String> rawContents) {
List<DataObject> objects = new MyMapper().convertList(rawContents);
return publish(objects);
}
public boolean result publish(List<DataObject> objects) {
../// some logic
}
}
Now what I want to assert is something like. Note: Please assume the right mocks are returned when new() is called [Using some PowerMockito]
#Test
public void test() {
String content = "content";
DataObject mock1 = Mockito.mock(DataObject.class);
MyMapper mapperMock = Mockito.mock(MyMapper.class);
MyWorkerClass worker = new MyWorkerClass();
Mockito.when(mapperMock.convertObject(content)).thenReturn(mock1);
Mockito.when(worker.publish(eq(Arrays.asList(mock1)).thenReturn(true);
boolean result = worker.start(Arrays.asList(content));
Assert.assertTrue(result);
}
The problem with the code above is in the line
Mockito.when(worker.publish(eq(Arrays.asList(mock1)).thenReturn(true);
This will try to match the list object instead of the list contents, in other words, even when I have to lists A: [mock1] and B: [mock1], A is not equal to B and ultimately the stubbing fails.
What I need is some sort of matcher similar to hamcrest's contain matcher. Something like:
Mockito.when(worker.publish(contains(mock1)).thenReturn(true));
Is there anyway I can achieve this? Keep in mind the code above is just an example to grasp the problem, the real situation is a little bit more complex and I can only mock individual objects, not the list itself
Thanks
Nevermind, later I learned that Mockito's eq() method will call the equals() method on the argument. Now if that is an ArrayList it means it will return true if two list sizes are equal and if the equal's comparison for each one of the elements in the list also returns true. See https://docs.oracle.com/javase/6/docs/api/java/util/List.html#equals%28java.lang.Object%29
And for even more customization argThat() could be used What's the difference between Mockito Matchers isA, any, eq, and same?

Better way to convert an List<MyDataType> to List<String>

I am wondering if there isn't a better way to convert whole Lists or Collections as the way I show in the following code example:
public static List<String> getAllNames(List<Account> allAccounts) {
List<String> names = new ArrayList<String>(allAccounts.size());
for (Account account : allAccounts) {
names.add(account.getName());
}
return names;
}
Every time I produce a method like this, I start thinking, isn't there a better way? My first thought would be to create maybe a solution with some generics and reflections, but this seems maybe a bit over sized and maybe a bit to slow when it comes to performance?
Take a look at Google's Guava library
Something like this should do it
final List<String> names = Lists.transform(myObjs, new Function<MyObject, String>() {
public String apply(final MyObject input) {
return input.getName();
}
});
With Guava, there is a more functional approach:
return FluentIterable.from(allAccounts).transform(new Function<Account,String>(){
public String apply(Account account){return account.getName();}
}).toImmutableList()
But that essentially does the same thing, of course.
BTW: the difference between this answer and RNJ's is that in my case the list will be created once, while in the other answer it's a live view. Both versions are valid, but for different scenarios.
I actually have exactly this kind of method in my personal library.
public static <TSource,TTarget> List<TTarget> castList(List<TSource> sourceList)
{
List<TTarget> targetList = new ArrayList<TTarget>(sourceList.size());
for (TSource t : sourceList) {
//This will throw a ClassCastException if the types are not compatible
//Be carefull
targetList.add((TTarget)t);
}
return targetList;
}
Usage is very simple because the compiler infers the type for TTarget.
List<Object> objects = new ArrayList<Object>();
objects.add("One");
objects.add("Two");
List<String> strings = castList(objects);
Regarding the performance:
I think using generics is no problem here. But the need to copy the whole array is another story.
There is no better way. Casting is a difficult and dangerous thing. In your example, your are not able to cast a String to a MyDataType or vice versa, aren't you?
You might create an own List-Implementation with some kind of toStringList()-Method if you need these more often.
There's a simple way but it is not type safe
List<A> a = new ArrayList<A>();
List<B> b = (List)a;
but then you have to override the implementation of toString() method of your class to return the getName() value.
But there's no type checking,
And as mentioned you can of course do instead a loop and call getName on every object
You could try using the Iterables and Function classes from the Guava libraries. You can create a new type of an Iterable using,
Iterable<String> newTypeIterable = Iterables.transform(oldTypeIterable, new Function<MyDataType, String> () {
#Override
public String apply(MyDataType from)
{
return from.getName();
}
});
Turns out you can do this with the Lists class too!

Changing semantics of subclass methods in java

I've recently learned like 3 new languages and I'm starting to get them confused. I haven't worked Java in doing anything particularly complex (outside of android) in a couple years. I'm having trouble remembering if this is possible:
I'm subclassing ArrayList mainly so I can keep the arraylist ordered. I'm trying to override the add(object) method but I want it to return an int instead of a boolean (the location of the object that was added). But I'm getting errors on the return type of my method.
Is what I want even possible in the language? Can you have a method in a subclass return something different than the superclass' method?
Or am I trying to do something stupid? Is this breaking the is-a idea of inheritance? Should I just encapsulation an arraylist instead of extending it?
For reference, a portion of what I'm trying to do:
public class AuthorArray extends ArrayList \{
#Override
public int add(Author object) {
super.add(object);
Collections.sort(this, new SortByLastName());
return this.indexOf(object);
}
}
Can you have a method in a subclass return something different than the superclass' method?
In general, no. The only exception is covariant return types, when an overridden method returns a subclass of the return type in the base class/interface method. This became possible with Java5, and is good practice. But your case does not fall into this category.
Is this breaking the is-a idea of inheritance?
Yes. Users of ArrayList expect to get a boolean return value from add, and see the elements in the same order they added them, and you would break that expectation. Don't do that.
Should I just encapsulation an arraylist instead of extending it?
Yes. Then you can define your own interface, with whatever contract you prefer. But first, consider using a TreeSet instead.
Changing semantics is bad. In your case, changing method name from add to myadd would fix your problem, if you want a simple fix.
Personally i would recommend learning how to use Google guava-libraries immutable, sorted data structures with 'function', to get a refresher overview, browse youtube.
But here in standard Java, I made example, how to use TreeSet autosort - custom class, 2 value comparator, and efficient binary search equivalent.
public static class customC {
private String name;
private int value;
public customC(String name, int value) {super();this.name = name;this.value = value;}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public int getValue() {return value;}
public void setValue(int value) {this.value = value;}
#Override
public String toString() {
return new StringBuilder().append("[").append(this.name)
.append(":").append(this.value).append("]").toString();
}
}
public static void main(String[] args) {
TreeSet<customC> ts = new TreeSet<customC>(new Comparator<customC>(){
public int compare(customC a, customC b) {
int result = a.getName().compareToIgnoreCase(b.getName());
return (result != 0 ? result : a.getValue() - b.getValue());
}
});
ts.add(new customC("ab", 1988));
ts.add(new customC("ab", 1979));
ts.add(new customC("ba", 1988));
ts.add(new customC("ab", 1984));
ts.add(new customC("ab", 1980));
customC ce = new customC("ab", 1983);
ts.add(ce);
StringBuilder sb = new StringBuilder();
sb.append(ts.headSet(ce).last()).append(" comes before ")
.append(ce).append("\n").append(ts);
System.out.println(sb.toString());
}
This will output:
[ab:1980] comes before [ab:1983]
[[ab:1979], [ab:1980], [ab:1983], [ab:1984], [ab:1988], [ba:1988]]
The List interface guarantees that elements will be returned in the same order that they are added. Thus if you only have one thread manipulating the list you can easily perform an add and then request its size. size - 1 is the ordinal value of the element.
If the above order is not what you want then you have two choices - either sort the list using Collection.sort() methods, or use a SortedSet. Both methods can take on a comparator.
I've never found the need to extend the Java collections framework and do not recommend that you do so in this circumstance.

Most Concise Way to Determine List<Foo> Contains Element Where Foo.getBar() = "Baz"?

Given a starting List<Foo>, what is the most concise way to determine if a Foo element having a property bar (accessed by getBar()) has a value of "Baz"? The best answer I can come up with is a linear search:
List<Foo> listFoo;
for(Foo f:listFoo) {
if(f.getBar().equals("Baz")) {
// contains value
}
}
I looked into HashSet but there doesn't seem to be a way to use contains() without first instantiating a Foo to pass in (in my case, Foo is expensive to create). I also looked at HashMap, but there doesn't seem to be a way to populate without looping through the list and adding each Foo element one at a time. The list is small, so I'm not worried about performance as much as I am clarity of code.
Most of my development experience is with C# and Python, so I'm used to more concise statements like:
// C#
List<Foo> listFoo;
bool contains = listFoo.Count(f => f.getBar=="Baz")>0;
or
# Python
# list_foo = [Foo(), ...]
contains = "Baz" in (f.bar for f in list_foo)
Does Java have a way to pull this off?
Java does not support closures (yet), so your solution is one of the shortest. Another way would be to use, for example, google-collections Iterable's closure-like Predicate:
boolean contains = Iterables.any(iterableCollection, new Predicate<Foo>() {
#Override
public boolean apply(Foo foo) {
return foo != null && foo.getBar().equals("Baz");
}
}
In and of itself Java does not.
Also (just as an fyi) f.getBar == "Baz" won't work for string comparison, due to the fact that strings are objects. Then you use the == operator you are actually comparing objects (which are not equal because they are not at the same memory location and are individual objects). The equals method is the best way to do object comparisons. And specifically it is best to "Baz".equals(f.getBar()) as this also avoids nasty NullPointerExceptions.
Now to address your question. I can think of ways to do it, but it probably depends on the relationship of the parent object Foo to the child object Bar. Will it always be one to one or not? In other words could the Bar value of "Baz" be associated with more than one Foo object?
Where I'm going with this is the HashMap object that you talked about earlier. This is because there are the methods containsKey and containsValue. Since HashMap does allow duplicate values associated with different keys, you could put Bar as the value and Foo as the key. Then just use myHashMap.containsValue("Baz") to determine if it is in "the list". And since it is, then you can always retrieve the keys (the Foos) that are associate with it.
You can only emulate this in Java, e.g. using a "function object". But since this is a bit awkward and verbose in Java, it is only worth the trouble if you have several different predicates to select elements from a list:
interface Predicate<T> {
boolean isTrueFor(T item);
}
Foo getFirst(List<Foo> listFoo, Predicate<Foo> pred) {
for(Foo f:listFoo) {
if(pred.isTrueFor(f)) {
return f;
}
}
}
class FooPredicateBar implements Predicate<Foo> {
private final String expected;
FooPredicateBar(String expected) {
this.expected = expected;
}
public boolean isTrueFor(Foo item) {
return item != null && expected.equals(item.getBar());
}
}
...
List<Foo> listFoo;
Foo theItem = getFirst(listFoo, new FooPredicateBar("Baz"));
You can also use Apache Commons CollectionUtils:
boolean contains = CollectionUtils.exists(listFoo, new Predicate() {
public boolean evaluate(Object input) {
return "Baz".equals(((Foo)input).getBar());
}
});

Categories