How do I assert an Iterable contains elements with a certain property? - java

Assume I want to unit test a method with this signature:
List<MyItem> getMyItems();
Assume MyItem is a Pojo that has many properties, one of which is "name", accessed via getName().
All I care about verifying is that the List<MyItem>, or any Iterable, contains two MyItem instances, whose "name" properties have the values "foo" and "bar". If any other properties don't match, I don't really care for the purposes of this test. If the names match, it's a successful test.
I would like it to be one-liner if possible. Here is some "pseudo-syntax" of the kind of thing I would like to do.
assert(listEntriesMatchInAnyOrder(myClass.getMyItems(), property("name"), new String[]{"foo", "bar"});
Would Hamcrest be good for this type of thing? If so, what exactly would be the hamcrest version of my pseudo-syntax above?

Thank you #Razvan who pointed me in the right direction. I was able to get it in one line and I successfully hunted down the imports for Hamcrest 1.3.
the imports:
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.beans.HasPropertyWithValue.hasProperty;
the code:
assertThat( myClass.getMyItems(), contains(
hasProperty("name", is("foo")),
hasProperty("name", is("bar"))
));

AssertJ provides an excellent feature in extracting() : you can pass Functions to extract fields. It provides a check at compile time.
You could also assert the size first easily.
It would give :
import static org.assertj.core.api.Assertions;
Assertions.assertThat(myClass.getMyItems())
.hasSize(2)
.extracting(MyItem::getName)
.containsExactlyInAnyOrder("foo", "bar");
containsExactlyInAnyOrder() asserts that the list contains only these values whatever the order.
To assert that the list contains these values whatever the order but may also contain other values use contains() :
.contains("foo", "bar");
As a side note : to assert multiple fields from elements of a List , with AssertJ we do that by wrapping expected values for each element into a tuple() function :
import static org.assertj.core.api.Assertions;
import static org.assertj.core.groups.Tuple;
Assertions.assertThat(myClass.getMyItems())
.hasSize(2)
.extracting(MyItem::getName, MyItem::getOtherValue)
.containsExactlyInAnyOrder(
tuple("foo", "OtherValueFoo"),
tuple("bar", "OtherValueBar")
);

Its not especially Hamcrest, but I think it worth to mention here. What I use quite often in Java8 is something like:
assertTrue(myClass.getMyItems().stream().anyMatch(item -> "foo".equals(item.getName())));
(Edited to Rodrigo Manyari's slight improvement. It's a little less verbose. See comments.)
It may be a little bit harder to read, but I like the type and refactoring safety.
Its also cool for testing multiple bean properties in combination. e.g. with a java-like && expression in the filter lambda.

Try:
assertThat(myClass.getMyItems(),
hasItem(hasProperty("YourProperty", is("YourValue"))));

Assertj is good at this.
import static org.assertj.core.api.Assertions.assertThat;
assertThat(myClass.getMyItems()).extracting("name").contains("foo", "bar");
Big plus for assertj compared to hamcrest is easy use of code completion.

As long as your List is a concrete class, you can simply call the contains() method as long as you have implemented your equals() method on MyItem.
// given
// some input ... you to complete
// when
List<MyItems> results = service.getMyItems();
// then
assertTrue(results.contains(new MyItem("foo")));
assertTrue(results.contains(new MyItem("bar")));
Assumes you have implemented a constructor that accepts the values you want to assert on. I realise this isn't on a single line, but it's useful to know which value is missing rather than checking both at once.

AssertJ 3.9.1 supports direct predicate usage in anyMatch method.
assertThat(collection).anyMatch(element -> element.someProperty.satisfiesSomeCondition())
This is generally suitable use case for arbitrarily complex condition.
For simple conditions I prefer using extracting method (see above) because resulting iterable-under-test might support value verification with better readability.
Example: it can provide specialized API such as contains method in Frank Neblung's answer. Or you can call anyMatch on it later anyway and use method reference such as "searchedvalue"::equals. Also multiple extractors can be put into extracting method, result subsequently verified using tuple().

Alternatively to hasProperty you can try hamcrest-more-matchers where matcher with extracting function. In your case it will look like:
import static com.github.seregamorph.hamcrest.MoreMatchers.where;
assertThat(myClass.getMyItems(), contains(
where(MyItem::getName, is("foo")),
where(MyItem::getName, is("bar"))
));
The advantages of this approach are:
It is not always possible to verify by field if the value is computed in get-method
In case of mismatch there should be a failure message with diagnostics (pay attention to resolved method reference MyItem.getName:
Expected: iterable containing [Object that matches is "foo" after call
MyItem.getName, Object that matches is "bar" after call MyItem.getName]
but: item 0: was "wrong-name"
It works in Java 8, Java 11 and Java 14

With Stream you can also do:
List<String> actual = myList.stream().map(MyClass::getName).collect(toList());
assertThat(actual, hasItem("expectedString1"));
Because with anyMatch() or allMatch(), you know some values in your list are in the list, but there is possibility that your actual list only contains 5 values while in anyMatch() you have 6; you don't know if all values are present or not. With hasItem(), you indeed check every value you want.

Related

Hamcrest: test that an Iterable contains all elements of another Iterable [duplicate]

I'm trying to compare 2 lists:
assertThat(actual.getList(), is(Matchers.containsInAnyOrder(expectedList)));
But idea
java: no suitable method found for assertThat(java.util.List<Agent>,org.hamcrest.Matcher<java.lang.Iterable<? extends model.Agents>>)
method org.junit.Assert.<T>assertThat(T,org.hamcrest.Matcher<T>) is not applicable
(no instance(s) of type variable(s) T exist so that argument type org.hamcrest.Matcher<java.lang.Iterable<? extends model.Agents>> conforms to formal parameter type org.hamcrest.Matcher<T>)
method org.junit.Assert.<T>assertThat(java.lang.String,T,org.hamcrest.Matcher<T>) is not applicable
(cannot instantiate from arguments because actual and formal argument lists differ in length)
How should I write it?
If you want to assert that the two lists are identical, don't complicate things with Hamcrest:
assertEquals(expectedList, actual.getList());
If you really intend to perform an order-insensitive comparison, you can call the containsInAnyOrder varargs method and provide values directly:
assertThat(actual.getList(), containsInAnyOrder("item1", "item2"));
(Assuming that your list is of String, rather than Agent, for this example.)
If you really want to call that same method with the contents of a List:
assertThat(actual.getList(), containsInAnyOrder(expectedList.toArray(new String[expectedList.size()]));
Without this, you're calling the method with a single argument and creating a Matcher that expects to match an Iterable where each element is a List. This can't be used to match a List.
That is, you can't match a List<Agent> with a Matcher<Iterable<List<Agent>>, which is what your code is attempting.
List<Long> actual = Arrays.asList(1L, 2L);
List<Long> expected = Arrays.asList(2L, 1L);
assertThat(actual, containsInAnyOrder(expected.toArray()));
Shorter version of #Joe's answer without redundant parameters.
To complement #Joe's answer:
Hamcrest provides you with four main methods to match a list:
contains Checks for matching all the elements considering the order. If the list has more or fewer elements, it will fail
containsInAnyOrder Checks for matching all the elements, and it doesn't matter the order. If the list has more or fewer elements, will fail
hasItems Checks just for the specified objects it doesn't matter if the list has more
hasItem Checks just for one object it doesn't matter if the list has more
All of them can receive a list of objects and use the equals method for comparison or can be mixed with other matchers like #borjab mentioned:
assertThat(myList , contains(allOf(hasProperty("id", is(7L)),
hasProperty("name", is("testName1")),
hasProperty("description", is("testDesc1"))),
allOf(hasProperty("id", is(11L)),
hasProperty("name", is("testName2")),
hasProperty("description", is("testDesc2")))));
http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html#contains(E...)
http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html#containsInAnyOrder(java.util.Collection)
http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html#hasItems(T...)
With existing Hamcrest libraries (as of v.2.0.0.0) you are forced to use Collection.toArray() method on your Collection in order to use containsInAnyOrder Matcher.
Far nicer would be to add this as a separate method to org.hamcrest.Matchers:
public static <T> org.hamcrest.Matcher<java.lang.Iterable<? extends T>> containsInAnyOrder(Collection<T> items) {
return org.hamcrest.collection.IsIterableContainingInAnyOrder.<T>containsInAnyOrder((T[]) items.toArray());
}
Actually I ended up adding this method to my custom test library and use it to increase readability of my test cases (due to less verbosity).
For list of objects you may need something like this:
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.beans.HasPropertyWithValue.hasProperty;
import static org.hamcrest.Matchers.is;
#Test
#SuppressWarnings("unchecked")
public void test_returnsList(){
arrange();
List<MyBean> myList = act();
assertThat(myList , contains(allOf(hasProperty("id", is(7L)),
hasProperty("name", is("testName1")),
hasProperty("description", is("testDesc1"))),
allOf(hasProperty("id", is(11L)),
hasProperty("name", is("testName2")),
hasProperty("description", is("testDesc2")))));
}
Use containsInAnyOrder if you do not want to check the order of the objects.
P.S. Any help to avoid the warning that is suppresed will be really appreciated.
Make sure that the Objects in your list have equals() defined on them. Then
assertThat(generatedList, is(equalTo(expectedList)));
works.
To compare two lists with the order preserved (strict order) use.
assertThat(actualList, contains("item1","item2"));
If we want to compare without a specific order we can use below command
assertThat(collection, containsInAnyOrder("item1","item2"));

Using Java 8 Optional for List of String as output

I want to use Optional for a method which returns a List
Lets say the function is
public Output getListOfSomething() {
// In some cases there is nothing to return and hence it makes sense to have return
// type as Optional here
}
Hence the function looks like :
public Optional<List<String>> getListOfSomething() {
// return something only when there is some valid list
}
Now I want to do something if the list is present so something like :
Optional<List<String>> listOfSomething = getListOfSomething();
int size = 0;
listOfSomething.ifPresent(size = listOfSomething.get().size());
I am new to Optional and have gone through the articles about Optional and it seems like this should work however am getting syntax error in my IDE :
method ifPresent is not applicable for the arguments (void).
I wanted to get some help from developers who might be more fluent with lamdas in java 8.
It's important to think about the Semantics here.
Your method could return a List, or "no list".
If it returns a List, it could return an Empty list.
You should ask, "is there a semantic reason to distinguish between an Empty List, and No List?" Sometimes there is a good design reason to make the difference, but it is rare. Think long and hard before deciding that Empty and Null are different in your case. Part of the reason to avoid No List, is that it reduces "special cases" that the client code has to consider. For example, if they have to do something for every item returned, but you could also return null, they have to do a special check for null before going into a for each loop. A for each does nothing if the list is empty.
If a "No List" is distinct from an "Empty List" in your problem domain, then it is sometimes useful to return wrapper class that helps client code distinguish between those conditions, and handle them appropriately. Optional is one such generic class, but your domain may call for something more specific (even if it mimics the functionality of Optional, it might have better semantic definition).
The true functional-programming way is the following:
size = listOfSomething.map(List::size).orElse(0);
But it would be much better to return an empty List instead of Optional.
ifPresent requires a Consumer interface to work. You could do the following:
Optional<List<String>> listOfSomething = getListOfSomething();
Integer[] size = {0};
listOfSomething.ifPresent(list -> size[0]=list.size())
But as stated by Tagir Valeev it would be better to do:
size = listOfSomething.map(List::size).orElse(0);
And it would also be better to return an empty List or even a Stream maybe.

Hamcrest test that a map contains all entries from another map

I want to check that a map contains a certain set of entries. It is allowed to contain other entries that are not in expectedMap. I currently have the following assertion:
assertThat(expectedMap.entrySet(), everyItem(isIn(actualMap.entrySet())));
Although this does work, the failure message that it prints is confusing because the expected and received arguments have been reversed from normal usage. Is there a better way to write it?
hasItems does what you want, but in a non-obvious way. You have to jump through some hoops as Hamcrest has relatively limited support for matching Iterables. (Without going into detail, this is due to the vagaries of how Java generics work- I'll post some more links with detail later).
(I'm assuming you're using generics, e.g. Map<String, String> as opposed to simply Map).
In the meantime you have a couple of options...
If you are happy with test code that raises warnings / using #SuppressWarnings("unchecked") in your test:
assertThat(actualMap.entrySet(), (Matcher)hasItems(expectedMap.entrySet().toArray()));
Explanation: there is no overload of hasItems that takes a Set or Iterable, but it will take an array. Set.toArray() returns Object[], which won't match assertThat against your actualMap.entrySet() - but if you erase the declared type of the Matcher, it will happily proceed.
If you want an assertion that compiles without warnings, it gets uglier - you need to copy the Set into some kind of Iterable<Object> (you can't cast) in order to match on the Objects :
assertThat(new HashSet<Object>(actualMap.entrySet()), hasItems(expectedMap.entrySet().toArray()));
But to be perfectly honest, for clarity you are almost certainly best off asserting each entry individually:
for (Entry<String, String> entry : expectedMap.entrySet()) {
assertThat(actualMap, hasEntry(entry.getKey(), entry.getValue()));
}
...or you could write your own Matcher - there are plenty of resources on how to do this online and on SO.

How to JUnit test that two List<E> contain the same elements in the same order?

Context
I am writing a simple JUnit test for the MyObject class.
A MyObject can be created from a static factory method that takes a varargs of String.
MyObject.ofComponents("Uno", "Dos", "Tres");
At any time during the existence of MyObject, clients can inspect the parameters it was created by in the form of a List<E>, through the .getComponents() method.
myObject.ofComponents(); // -> List<String>: { "Uno", "Dos", "Tres" }
In other words, a MyObject both remembers and exposes the list of parameters that brought it into existence. More details about this contract:
The order of getComponents will be the same as the one chosen for object creation
Duplicate subsequent String components are allowed and retained in order
Behaviour on null is undefined (other code guarantees no null gets to the factory)
There are no ways to alter the list of components after object instantiation
I am writing a simple test that creates a MyObject from a list of String and checks that it can return the same list via .getComponents(). I do this immediately but this is supposed to happen at a distance in a realistic code path.
Code
Here my attempt:
List<String> argumentComponents = Lists.newArrayList("One", "Two", "Three");
List<String> returnedComponents =
MyObject.ofComponents(
argumentComponents.toArray(new String[argumentComponents.size()]))
.getComponents();
assertTrue(Iterables.elementsEqual(argumentComponents, returnedComponents));
Question
Is Google Guava Iterables.elementsEqual() the best way, provided I have the library in my build path, to compare those two lists? this is something I have been agonizing about; should I use this helper method which goes over an Iterable<E>.. check size and then iterate running .equals().. or any other of the methods that an Internet search suggests? what's the canonical way to compare lists for unit tests?
Optional insights I would love to get
Is the method test designed reasonably? I am not an expert in JUnit!
Is .toArray() the best way to convert a List<E> to a varargs of E?
Why not simply use List#equals?
assertEquals(argumentComponents, imapPathComponents);
Contract of List#equals:
two lists are defined to be equal if they contain the same elements in the same order.
I prefer using Hamcrest because it gives much better output in case of a failure
Assert.assertThat(listUnderTest,
IsIterableContainingInOrder.contains(expectedList.toArray()));
Instead of reporting
expected true, got false
it will report
expected List containing "1, 2, 3, ..." got list containing "4, 6, 2, ..."
IsIterableContainingInOrder.contain
Hamcrest
According to the Javadoc:
Creates a matcher for Iterables that matches when a single pass over the examined Iterable yields a series of items, each logically equal to the corresponding item in the specified items. For a positive match, the examined iterable must be of the same length as the number of specified items
So the listUnderTest must have the same number of elements and each element must match the expected values in order.
The equals() method on your List implementation should do elementwise comparison, so
assertEquals(argumentComponents, returnedComponents);
is a lot easier.
org.junit.Assert.assertEquals() and org.junit.Assert.assertArrayEquals() do the job.
To avoid next questions: If you want to ignore the order put all elements to set and then compare: Assert.assertEquals(new HashSet<String>(one), new HashSet<String>(two))
If however you just want to ignore duplicates but preserve the order wrap you list with LinkedHashSet.
Yet another tip. The trick Assert.assertEquals(new HashSet<String>(one), new HashSet<String>(two)) works fine until the comparison fails. In this case it shows you error message with to string representations of your sets that can be confusing because the order in set is almost not predictable (at least for complex objects). So, the trick I found is to wrap the collection with sorted set instead of HashSet. You can use TreeSet with custom comparator.
For excellent code-readability, Fest Assertions has nice support for asserting lists
So in this case, something like:
Assertions.assertThat(returnedComponents).containsExactly("One", "Two", "Three");
Or make the expected list to an array, but I prefer the above approach because it's more clear.
Assertions.assertThat(returnedComponents).containsExactly(argumentComponents.toArray());
assertTrue()/assertFalse() : to use only to assert boolean result returned
assertTrue(Iterables.elementsEqual(argumentComponents,
returnedComponents));
You want to use Assert.assertTrue() or Assert.assertFalse() as the method under test returns a boolean value.
As the method returns a specific thing such as a List that should contain some expected elements, asserting with assertTrue() in this way : Assert.assertTrue(myActualList.containsAll(myExpectedList)
is an anti pattern.
It makes the assertion easy to write but as the test fails, it also makes it hard to debug because the test runner will only say to you something like :
expected true but actual is false
Assert.assertEquals(Object, Object) in JUnit4 or Assertions.assertIterableEquals(Iterable, Iterable) in JUnit 5 : to use only as both equals() and toString() are overrided for the classes (and deeply) of the compared objects
It matters because the equality test in the assertion relies on equals() and the test failure message relies on toString() of the compared objects.
As String overrides both equals() and toString(), it is perfectly valid to assert the List<String> with assertEquals(Object,Object).
And about this matter : you have to override equals() in a class because it makes sense in terms of object equality, not only to make assertions easier in a test with JUnit.
To make assertions easier you have other ways (that you can see in the next points of the answer).
Is Guava a way to perform/build unit test assertions ?
Is Google Guava Iterables.elementsEqual() the best way, provided I have the library in my build path, to compare those two lists?
No it is not. Guava is not an library to write unit test assertions.
You don't need it to write most (all I think) of unit tests.
What's the canonical way to compare lists for unit tests?
As a good practice I favor assertion/matcher libraries.
I cannot encourage JUnit to perform specific assertions because this provides really too few and limited features : it performs only an assertion with a deep equals.
Sometimes you want to allow any order in the elements, sometimes you want to allow that any elements of the expected match with the actual, and so for...
So using a unit test assertion/matcher library such as Hamcrest or AssertJ is the correct way.
The actual answer provides a Hamcrest solution. Here is a AssertJ solution.
org.assertj.core.api.ListAssert.containsExactly() is what you need : it verifies that the actual group contains exactly the given values and nothing else, in order as stated :
Verifies that the actual group contains exactly the given values and
nothing else, in order.
Your test could look like :
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
#Test
void ofComponent_AssertJ() throws Exception {
MyObject myObject = MyObject.ofComponents("One", "Two", "Three");
Assertions.assertThat(myObject.getComponents())
.containsExactly("One", "Two", "Three");
}
A AssertJ good point is that declaring a List as expected is needless : it makes the assertion straighter and the code more readable :
Assertions.assertThat(myObject.getComponents())
.containsExactly("One", "Two", "Three");
And if the test fails :
// Fail : Three was not expected
Assertions.assertThat(myObject.getComponents())
.containsExactly("One", "Two");
you get a very clear message such as :
java.lang.AssertionError:
Expecting:
<["One", "Two", "Three"]>
to contain exactly (and in same order):
<["One", "Two"]>
but some elements were not expected:
<["Three"]>
Assertion/matcher libraries are a must because these will really further
Suppose that MyObject doesn't store Strings but Foos instances such as :
public class MyFooObject {
private List<Foo> values;
#SafeVarargs
public static MyFooObject ofComponents(Foo... values) {
// ...
}
public List<Foo> getComponents(){
return new ArrayList<>(values);
}
}
That is a very common need.
With AssertJ the assertion is still simple to write. Better you can assert that the list content are equal even if the class of the elements doesn't override equals()/hashCode() while JUnit ways require that :
import org.assertj.core.api.Assertions;
import static org.assertj.core.groups.Tuple.tuple;
import org.junit.jupiter.api.Test;
#Test
void ofComponent() throws Exception {
MyFooObject myObject = MyFooObject.ofComponents(new Foo(1, "One"), new Foo(2, "Two"), new Foo(3, "Three"));
Assertions.assertThat(myObject.getComponents())
.extracting(Foo::getId, Foo::getName)
.containsExactly(tuple(1, "One"),
tuple(2, "Two"),
tuple(3, "Three"));
}
My answer about whether Iterables.elementsEqual is best choice:
Iterables.elementsEqual is enough to compare 2 Lists.
Iterables.elementsEqual is used in more general scenarios, It accepts more general types: Iterable. That is, you could even compare a List with a Set. (by iterate order, it is important)
Sure ArrayList and LinkedList define equals pretty good, you could call equals directly. While when you use a not well defined List, Iterables.elementsEqual is the best choice. One thing should be noticed: Iterables.elementsEqual does not accept null
To convert List to array: Iterables.toArray is easer.
For unit test, I recommend add empty list to your test case.
Some of the solutions make sense and I agree with them. But for me, I would use assertEquals but I would sort the two lists.
assertEquals(sortedExpectedList, sortedActualList);
It is simple and the output still gives you the diff between the actual and the expected.

Always avoid in-out parameters in Java?

There's no doubt that in-out parameters leads to confused code since they may increase unexpected/unpredictabled side-effects.
So, many good programmers say :
Avoid in-out parameters for changing mutable method parameters. Prefer to keep parameters unchanged.
For a perfectionist programmer who expects his code to be the most clean and understandable, does this "rule" must be applied in all case ?
For instance, suppose a basic method for adding elements to a simple list, there's two ways :
First way (with in-out parameter):
private void addElementsToExistingList(List<String> myList){
myList.add("Foo");
myList.add("Bar");
}
and the caller being :
List<String> myList = new ArrayList<String>();
//.......Several Instructions (or not) .....
addElementsToExistingList(myList);
Second way without out parameter :
private List<String> addElementsToExistingList(List<String> originalList){
List<String> filledList = new ArrayList<String>(originalList); //add existing elements
filledList.add("Foo");
filledList.add("Bar");
return filledList;
}
and the caller being :
List<String> myList = new ArrayList<String>();
//.......Several Instructions (or not) .....
myList.addAll(addElementsToExistingList(myList));
Pros of second way :
Parameter are not modified => no risk of unexpected side-effects for a new code reader.
Cons of second way :
Very verbose and very less readable ...
Of course, you would tell me that for a code as simple as this one, first way is really more convenient.
But, if we don't consider the difficulty of any concept/code, I juge the second way more logical and obvious for any readers (beginners or not).
However, it violates the CQS principle that consider "command" methods having void return with potential (but allowed since it's the convention) side-effects and "query" methods having a return type and without side-effects.
So, what should a motivate programmer adopt ? Mix of two accorging to the code case ? Or keep the "law" expecting to always avoid in-out parameters...
(Of course, method for adding Element is named for expliciting the example, and would be a bad name choice in real code).
I think the law should be:
Use what is more straight-forward, but always, always document the behavior of your methods extensively.
Your second example is a very nice case where without documentation you would have a guaranteed bug: the name of the method is addElementsToExistingList, but the method does not add elements to the existing list - it creates a new one. A counter-intuitive and misleading name, to say the least...
There is a third way. Wrap List<String> into a class that knows how to add elements to itself:
class ElementList {
private List<String> = new ArrayList<String>();
public void addElements(Element... elements);
}
I like this approach because it keeps the List implementation private. You don't have to worry if someone passes an immutable list to your method or whether parameters are modified. The code is simpler. Long method names like addElementsToExistingList are code smells that an object is trying to do something another object should be doing.
You should always document when mutating an object that is a parameter because otherwise this can have unintended side effects for the caller. In the first case I agree with the others that have commented that the method name is sufficient documentation.
In your second example, the elements that are already present in myList seem to be added twice. In fact you could entirely remove the parameter of the addElementsToExistingList method and rewrite it as:
private List<String> getElements() {
List<String> filledList = new ArrayList<String>();
filledList.add("Foo");
filledList.add("Bar");
return filledList;
}
List<String> myList = new ArrayList<String>();
//.......Several Instructions (or not) .....
myList.addAll(getElements());
Note that this code is not equivalent to your second example because the elements are only added once, but I think this is actually what you intended. This is the style that I usually prefer. This code is easier to understand and more flexible than the first example without adding extra code (it may degrade performance very slightly but this usually isn't a concern). The client of getElements() can now also do other things with the element list besides adding it to an existing collection.
It's fine to change/mutate parameters as long as it's documented. And of course with a method name of "addElementsToExistingList", what else should someone expect? However, as someone previously pointed out, your second implementation returns a copy and doesn't modify the original, so the method name is now misleading. Your first way is a perfectly acceptable way of doing things. The only other additional improvements is to possibly add a true/false value to the return indicating true if only all the elements were added to the list.
In the case of your example the name makes it clear - "addElementsToExistingList" to me seems pretty clearly to hint that you're going to .. er.. you know. But your concern would be justified with a less obvious name.
For example, in ruby this is commonly handled with naming conventions
"a".upcase => gives you the uppercase of the variable, leaves the original unchanged
"a".upcase! => alters the original variable

Categories