How to use hamcrest contains to compare 2 lists? - java

Why does this test fail? I know contains works when you pass in individual strings separated by commas but I wanted to see if it's possible to just pass in an entire list of strings instead. I just want to make sure that list 1 contains all of the contents of list 2.
#Test
public void testContains() {
String expected1 = "hello";
String expected2 = "goodbye";
List<String> expectedStrings = new ArrayList<>();
expectedStrings.add(expected1);
expectedStrings.add(expected2);
List<String> actualStrings = new ArrayList<>();
actualStrings.add(expected1);
actualStrings.add(expected2);
assertThat(actualStrings, contains(expectedStrings));
}
Is it considered acceptable to use this assertion instead?
assertThat(actualStrings, is(expectedStrings));

There is no overloaded contains method which takes a list of expected values.
In the statement assertThat(actualStrings, contains(expectedStrings))
the following method (in the Matchers class) is called:
<E> org.hamcrest.Matcher<java.lang.Iterable<? extends E>> contains(E... items)
Basically you are saying that you expect a list with one element and this element is expectedStrings but in fact it is expected1 (E is of type List<String> and not String). To verify add the following to the test which should then pass:
List<List<String>> listOfactualStrings = new ArrayList<>();
listOfactualStrings.add(actualStrings);
assertThat(listOfactualStrings, contains(expectedStrings));
To make the assertion work you have to convert the list to an array:
assertThat(actualStrings, contains(expectedStrings.toArray()));

If you want to apply a matcher for each item in a list you can use the everyItem matcher, like so:
everyItem(not(isEmptyOrNullString()))

Related

Using method reference to remove elements from a List

What's wrong with my code?
I want to remove all the elements starting with A from the List list:
public static void main(String[] args) {
Predicate<String> TTT = "A"::startsWith;
List<String> list = new ArrayList<>();
list.add("Magician");
list.add("Assistant");
System.out.println(list); // [Magician, Assistant]
list.removeIf(TTT);
System.out.println(list); // expected output: [Magician]
}
However, removeIf doesn't remove anything from the list.
"A"::startsWith is a method reference that can be assigned to a Predicate<String>, and when that Predicate<String> is tested against some other String, it would check whether the String "A" starts with that other String, not the other way around.
list.removeIf(TTT) won't remove anything from list, since "A" doesn't start with neither "Magician" nor "Assistant".
You can use a lambda expression instead:
Predicate<String> TTT = s -> s.startsWith("A");
The only way your original "A"::startsWith predicate would remove anything from the list is if the list would contain the String "A" or an empty String.
BiPredicate<String, String> b1 = String::startsWith;
BiPredicate<String, String> b2 = (string, prefix) -> string.startsWith(prefix);
System.out.println(b1.test("chicken", "chick"));
System.out.println(b2.test("chicken", "chick"));
The method reference combines two techniques. **startsWith()**
is an instance method. This means that the first parameter in the lambda is used
as the instance on which to call the method. The second parameter is passed to the
startsWith() method itself. This is example of how method references save a
good bit of typing.

Check if lists contain same objects

I have two filled lists.
The first list contains for example:
"Shoppinglist-fruit", "Shoppinglist-drinks", "Shoppinglist-dinner"
The second list contains:
"Shoppinglist-drinks"
Now i wanna print all items in the first list, except if there's a same object in the second list with the same name (Shoppinglist-drinks).
Looking like:
"Shoppinglist-fruit", "Shoppinglist-dinner"
So how can i check if the name of the object inside the second list is also in one of the objects of the first list.
Eventually i want to end up with a string containing all the names of the shoppinglists that are in the first list and not in the second one.
I started with some code below but i haven't been able to finish it.
I have the two lists, one called listShoppinglists, this is a list filled with different shopping lists.
And the second list filled with somebody's shoppinglists.
So i wanna check if the name of the shoppinglists are equal.
If done that by doing so.
public String getAllShoppingLists(List listShoppinglists, Customer customer, List shoppinglists) {
String namesOfTheShoppingListNames = ""
for (Shoppinglist shoppinglist : listShoppinglists) {
for (int i = 0; i < customer.shoppinglists.size(); i++) {
if (customer.shoppinglists.get(i).getName().equals(shoppinglist.getName())) {
// Some action here
}
}
}
return namesOfTheShoppingListNames;
}
You can try this:
List<ShoopingList> firstShoppingListNames = new ArrayList<>();
firstShoppingListNames.add(new ShoppingList("fruit"));
firstShoppingListNames.add(new ShoppingList("dinner"));
firstShoppingListNames.add(new ShoppingList("juice"));
List<ShoppingList> secondShoppingListNames = new ArrayList<>();
secondShoppingListNames.add(new ShoppingList("fruit"));
List<ShoppingList> distinct = firstShoppingListNames.stream().
filter( list -> secondShoppingListNames.stream().
noneMatch(o -> o.getName().equals(list.getName()))).
collect(Collectors.toList());
distinct.forEach(o -> System.out.print(o.getName()));
In this case you are using stream to achieve what you want. You filter first list to obtain those elements, which are not present in other list.
Additionaly if you want to obtain only names of those lists you can use map:
List<String> distinct = firstShoppingListNames.stream().
filter( list -> secondShoppingListNames.stream().
noneMatch(o -> o.getName().equals(list.getName()))).
map(ShoppingList::getName).collect(Collectors.toList());
Use Collections.removeAll() method to do this. Quoted from JavaDoc:-
Removes all of this collection's elements that are also contained in
the specified collection (optional operation). After this call
returns, this collection will contain no elements in common with the
specified collection
.List<String> list1=new ArrayList<String>();
list1.add("Shoppinglist-fruit");list1.add("Shoppinglist-drinks");list1.add("Shoppinglist-dinner");
List<String> list2=new ArrayList<String>();
list2.add("Shoppinglist-drinks");
list1.removeAll(list2);
System.out.println(list1);
//Output:- [Shoppinglist-fruit, Shoppinglist-dinner]
In case, lists contains a custom objects, override equals and hashcode methods in that custom object.

Getting individual entries of a Set in Java?

So I am currently having a problem understanding how to access a set, is that even allowed? So I understand my set of names contains a set of Character objects. I also understand that my toString() method call converts these Character objects into a String, but not a conventional string -- which is why I have [s,a] rather than [sa]. So my question is, is if there is a way to make me have a list of individual strings. So I want my list to be = [s, a] rather than [ [s,a] ]. Is this even possible? I apologize if this makes no sense; nevertheless, if you do understand my fumbled explanation thank you for your time and help. If you need for me to explain more, I will.
//this all works
Set<Character> names = find(prefix).getRollCall().keySet();
//[s,a]
String lists = names.toString();
//[s,a]
List<String> sloop = Arrays.asList(lists);
//[[s,a]]
If you want to convert a Set<Character> to a List<Character> you can do
List<Character> list = new ArrayList<Character>(set);
If you want to convert a Set<Character> to a List<String> you can do
List<String> list = new ArrayList<String>();
for (char c : set)
list.add("" + c);
Don't use toString() at all. Iterate over the elements of the Set and build up whatever string you like.
Set<Character> names = find(prefix).getRollCall().keySet();
for (Character c : names)
{
// whatever you like
}
Let me explain what's happening in your code, in case you aren't clear:
String lists = names.toString();
This calls the standard toString method for a collection which converts your set to an ordinary (conventional) string in a standard format (i.e. comma delimited, in brackets). There's nothing special about the string that is created: "[s, a]".
List<String> sloop = Arrays.asList(lists);
The asList method takes one or more arguments and converts them into a list. Because you've given it only a single argument lists it creates a list with a single string element: ("[s, a]")
Then, later, I suspect you are doing something like:
System.out.println(sloop);
This again calls the standard toString method for a collection (in this case the List sloop) and again creates a comma delimited, bracket enclosed standard string: "[[s, a]]"
So, most of that is probably not what you want. Your lists variable isn't a List, it's a String which I assume isn't what you want.
If you are just looking to convert your set of character to a list of strings, then this is pretty trivial in Java 8:
List<String> lists = names.stream().map(Character::toString).collect(Collectors.toList());

Comparing a string in a string object using java

I'm having a config entry, from which I'm loading into an String array like
String s = "abc$#def$#ghi";
String[] scbHLNewArray = s.split("\\$\\#");
Here I'm comparing a string with the array values after splitting it like ,
for(String arrNewErrorInfo : scbHLNewArray) {
LOG.info("SCB HL New Error Value :"+arrNewErrorInfo+"\n");
if(errorInfo.equals(arrNewErrorInfo)) {
LOG.info("SCB HL Matched New value is :"+arrNewErrorInfo);
newState = ApplicationState.NEW;
addApplicationEvent(application.getId(),comment, ApplicationEventType.COMMENT,BBConstants.AUTOBOT);
scbHLNewStatus = "Matched";
break;
}
}
I want to use some util classes like List.. Any idea on append to list and compare the string with the list objecT?
Thanks,
Nizam
you can do this with List contains method.
ArrayList<Integer> arrlist = new ArrayList<Integer<(8);
// use add() method to add elements in the list
arrlist.add(20);
arrlist.add(25);
arrlist.add(10);
arrlist.add(15);
// list contains element 10
boolean retval = arrlist.contains(10); // It will return true.
Ok, let's try... First of all, you can create a List Object, wrapping your array very easily:
List<String> myList = Arrays.asList( scbHLNewArray );
Be carefull, because you can NOT add to this list, as it only wraps your array. If you want a list you can add to, you would have to create a new one, for example:
List<String> myModifiableList = new ArrayList<String>( myList );
This will create a new List that contains all the Strings from the first one but is also modifiable (you can add Strings, if you want).
In any case, you can use "contains", as Pratik has already shown, to test if a String is inside your list:
if (myList.contains("someString")) { ... }
This works because the String class already has well implemented equals(...) and hashCode() methods. If you want to put other Object than Strings into your list, you would have to make sure that these methods are implemented well, otherwise contains might not work as expected.
Yes you can use a list of course, you need to :
1. Take the result of split as an array.
2. Then convert this array to a list.
String s = "abc$#def$#ghi";
String[] scbHLNewArray = s.split("\\$\\#");
List<String> list=Arrays.asList(scbHLNewArray); //convert the array to a list
Take a look at Arrays.asList(Array a) and this Tutorial for further information about it.
And then to search the wanted String object you can use indexOf(Object o) or contains(Object o) List methods

How to check if collection contains items in given order using Hamcrest

How to check using Hamcrest if given collection is containing given items in given order? I tried hasItems but it simply ignores the order.
List<String> list = Arrays.asList("foo", "bar", "boo");
assertThat(list, hasItems("foo", "boo"));
//I want this to fail, because the order is different than in "list"
assertThat(list, hasItems("boo", "foo"));
You can use contains matcher instead, but you probably need to use latest version of Hamcrest. That method checks the order.
assertThat(list, contains("foo", "boo"));
You can also try using containsInAnyOrder if order does not matter to you.
That's the code for contains matcher:
public static <E> Matcher<Iterable<? extends E>> contains(List<Matcher<? super E>> itemMatchers)
{
return IsIterableContainingInOrder.contains(itemMatchers);
}
To check tha collection contains items in expected (given) order you can use Hamcrest's containsInRelativeOrder method.
From javadoc:
Creates a matcher for Iterable's that matches when a single pass over
the examined Iterable yields a series of items, that contains items
logically equal to the corresponding item in the specified items, in
the same relative order For example: assertThat(Arrays.asList("a",
"b", "c", "d", "e"), containsInRelativeOrder("b", "d")).
Actual for Java Hamcrest 2.0.0.0.
Hope this helps.
You need to implement a custom Matcher, something like this
class ListMatcher extends BaseMatcher {
String[] items;
ListMatcher(String... items) {
this.items = items;
}
#Override
public boolean matches(Object item) {
List list = (List) (item);
int l = -1;
for (String s : items) {
int i = list.indexOf(s);
if (i == -1 || i < l) {
return false;
}
l = i;
}
return true;
}
#Override
public void describeTo(Description description) {
// not implemented
}
}
#Test
public void test1() {
List<String> list = Arrays.asList("foo", "bar", "boo");
Assert.assertThat(list, new ListMatcher("foo", "boo"));
Assert.assertThat(list, new ListMatcher("boo", "foo"));
}
The accepted answer is not working for me. It still fails, saying
Expected: iterable containing ["foo", "boo"] but: Not matched: "bar"
So I wrote my own IsIterableContainingInRelativeOrder, and submitted it as a patch.
I found a solution at http://www.baeldung.com/hamcrest-collections-arrays
Look for the section that has an example with strict order.
List<String> collection = Lists.newArrayList("ab", "cd", "ef");
assertThat(collection, contains("ab", "cd", "ef"));
Basically you need to use the contains Matcher (org.hamcrest.Matchers.contains)
You can combine is and equalTo of matchers library. The assert statement looks longer but the error message is better. Since contains is fail first it breaks when it finds the first mismatch and wouldn't find failures further down the list. Where as is and equalTo will print the entire list from which you see all the mismatches.
Example using contains
List<String> list = Arrays.asList("foo", "bar", "boo");
assertThat(list, contains("foo", "boo", "bar"));
Gives the following error message:
Expected: iterable containing ["foo", "boo", "bar"]
but: item 1: was "bar"
Example using is and equalTo
List<String> list = Arrays.asList("foo", "bar", "boo");
assertThat(list, is(equalTo(Lists.newArrayList("foo", "boo", "bar"))));
Gives the following error message:
Expected: is <[foo, boo, bar]>
but: was <[foo, bar, boo]>
The second method doesn't tell you the index where the mismatch is but to me this is still better as you can fix the test by looking at the failure message just once. Whereas in method one, you'll first fix index 1, run the test, detect mismatch at index 2 and do the final fix.

Categories