This question already has answers here:
Using Java 8 Optional for List of String as output
(3 answers)
Closed 1 year ago.
I keep seeing some users saying that using a collection with an optional is not recommended / is bad practice. I couldn't find much information on why it would be bad practice, so here I am.
In case it matters, in my particular case I have a JpaRepository with 2 methods. One Optional<List> getValues() and a second List getDefaultValues(), as such:
public interface someRepository extends JpaRepository<x, y> {
Optional<List> getValues();
List getDefaultValues();
}
The idea is that the values might not be present so I want to force the method caller to do .orElse(getDefaultValues()) so there is no chance getting returned an empty List. I also figured it would be tidier than just doing something like this:
List list = getValues();
if (list.isEmpty()) {
list = getDefaultValues();
}
Any feedback is appreciated.
Edit: I realise my example is not the most well suited to the question, as pointed out in the answers below. However, I would still like to understand why Optional<List> is considered bad practice by some.
This question does not really answer my question.
I think the point is moot. There are two possible cases:
1. The caller needs to be aware that default values have been returned
In this case, the caller will not be able to use the orElse()/orElseGet() construct, and will have to check with isPresent(). This is no better than checking whether the list is empty.
2. The caller does not need to be aware that default values have been returned
In which case you might as well hide the implementation details behind a single List getValues() method that returns the default values in case no values were found.
As to the general applicability of using Optional<List>, I think the Brian Goetz quote from this answer says it best:
Our intention was to provide a limited mechanism for library method
return types where there needed to be a clear way to represent "no
result", and using null for such was overwhelmingly likely to cause
errors.
When it comes to lists (and collections in general), there is already a clear way to represent "no result", and that is an empty collection.
Lets first consider this example:
public class <X> Example {
public List<X> getValues() {
if (...) {
return null;
} else {
return /* a non-empty list */
}
}
public List<X> getValuesAgain() {
if (...) {
return Collections.emptyList();
} else {
return /* a non-empty list */
}
}
}
Which of those ways of returning no values is better?
I would argue that the better way is (nearly always) the way that getValuesAgain does it; i.e. by returning an empty list. Consider the following.
With the first version, I need to test for a null before using the result:
List<String> l = example.getValues();
if (l != null) {
for (s String: l) {
/* do something */
}
}
With the second version, I can use the result directly:
List<String> l = example.getValuesAgain();
for (s String: l) {
/* do something */
}
In short, returning null makes life more complicated for the caller compared with returning an empty list. In theory, you may have saved the creation of an empty list object ... except that the javadoc for emptyList() states that it doesn't need to return a distinct list object each time. (And it typically won't!)
Now consider what Optional<List<String>> means: either a List<String> or no value. But as we have already seen, returning an empty list is simpler for the caller that returning a null. And the same logic applies here too.
So if getValues returns an Optional<List<X>>, we would need to use it like this:
Optional<List<String>> l = example.getValues();
if (l.isPresent()) {
for (s String: l.get()) {
/* do something */
}
}
Compare with the original getValuesAgain:
List<String> l = example.getValuesAgain();
for (s String: l) {
/* do something */
}
In short, using Optional to return a list or null is not an improvement.
The only scenario where I think you should contemplate using Optional<List<?>> as a return type is if the API needs to make a semantic distinction between an empty list versus no list.
The same applies for other collection types, and also for arrays, strings and other examples.
Another way of thinking about this is that the designers' intention for Optional is to provide a way to indicate there is "no result"; see Brian Goetz's answer to this question. But we don't need to indicate there is "no result" here since we can return an empty collection.
Related
how to rewrite this function to be more Java 8 with Optionals? Or should I just leave it as it is?
public void setMemory(ArrayList<Integer> memory) {
if (memory == null)
throw new IllegalArgumentException("ERROR: memory object can't be null.");
if (memory.contains(null))
throw new IllegalArgumentException("ERROR: memory object can't contain null value.");
this.memory = memory;
}
You've got a pattern condition -> throw an exception which can be moved to a method:
private void checkOrElseThrow(boolean condition, Supplier<? extends RuntimeException> exceptionSupplier) {
if (condition) {
throw exceptionSupplier.get();
}
}
public void setMemory(List<Integer> memory) {
checkOrElseThrow(memory == null, () -> new IllegalArgumentException("message #1"));
checkOrElseThrow(memory.contains(null), () -> new IllegalArgumentException("message #2"));
this.memory = memory;
}
If the type of the exception is not going to be changed, it's reasonable to pass only the message of the exception (thank #tobias_k for pointing it out):
private void checkOrElseThrow(boolean condition, String exceptionMessage) {
if (condition) {
throw new IllegalArgumentException(exceptionMessage);
}
}
public void setMemory(List<Integer> memory) {
checkOrElseThrow(memory == null, "message #1");
checkOrElseThrow(memory.contains(null), "message #2");
this.memory = memory;
}
If you want to stick to IllegalArgumentException and you have guava on the class path, you could use this:
Preconditions.checkArgument(memory != null,
"ERROR: memory object can't be null.");
Preconditions.checkArgument(!memory.contains(null),
"ERROR: memory object can't contain null value.");
You can't really use Optional here since you want different error messages for different conditions.
If you are OK having a single error message on the other hand, you could do:
this.memory = Optional.ofNullable(memory)
.filter(x -> !x.contains(null))
.orElseThrow(() -> new IllegalArgumentException(
"memory object is null or contains null values"));
For the first case I would use:
Objects.requireNonNull().
I don't think Optional is a way to go here as null is an illegal value.
I usually avoid Optional for such cases as it tends to obscure what's going on.
But first I'd like to mention that the original code lets the caller retain a reference to what is now an internal field memory of the containing class. Maybe you trust your callers not to be malicious, but the caller might accidentally reuse the list passed as an argument. If it does, despite the meticulous argument checking, the memory list might end up containing nulls after all. Or, it could change unexpectedly, leading to other malfunctions.
The solution is to make a defensive copy of the argument list. The straightforward way to do this is as follows:
public void setMemory(ArrayList<Integer> memory) {
if (memory == null)
throw new IllegalArgumentException("memory is null");
List<Integer> temp = new ArrayList<>(memory);
if (temp.contains(null))
throw new IllegalArgumentException("memory contains null");
this.memory = temp;
}
Note that the copy is made and stored in a local variable temp prior to being checked. Obviously, you don't want to store into the field before the list is checked for containing nulls. But the check for containing nulls should be done on the copy, not on the argument list, otherwise, the caller could modify the list after the check but before the copy. (Yes, this is being paranoid.)
If you don't care about the exact exception message, this could be shortened as follows:
public void setMemory(ArrayList<Integer> memory) {
List<Integer> temp;
if (memory == null || ((temp = new ArrayList<>(memory)).contains(null)))
throw new IllegalArgumentException("memory is or contains null");
this.memory = temp;
}
Now this could be rewritten to use Optional:
public void setMemory(ArrayList<Integer> memory) {
this.memory = Optional.ofNullable(memory)
.map(ArrayList::new)
.filter(list -> ! list.contains(null))
.orElseThrow(() -> new IllegalArgumentException("memory is or contains null"));
}
Compared to the usual abuses :-) of Optional I see frequently, this one isn't too bad. The chaining here serves to avoid creation of a local variable, which is a bit of a win. The logic is fairly straightforward, especially if one has Optional on the forebrain. However, I'd be somewhat concerned about revisiting this code in, say, a month. You'd probably have to squint at it a while before convincing yourself it does what you intended it to do.
Finally, a couple general style comments.
The usual preference (at least in the JDK) is to use NullPointerException for these cases. I've stuck with IllegalArgumentException for these examples because that's what the OP is using.
I'd recommend using List<Integer> instead of ArrayList<Integer> for the argument type and possibly the field type. This will enable the use of unmodifiable lists in situations where it's appropriate (e.g., using JDK 9's List.of).
First, it may be a good idea to use the more general list type as input parameter, so change your implementation to:
public void setMemory(List<Integer> memory) {
//stuff
}
and then as others mentioned, checking for null values for every "set" operation is a bit of an overkill.
If this "memory list" comes from some of your code and you can use guava, then maybe use guavas immutable list. This list throws an exception when someone tries to add "null" to your list.
ImmutableList.of( //your Integers)
If you cannot use guava but stillt want to use that approach you could always write your own list implementation that does this null checking for you.
And last, if all of this is not possible for you, just leave your code as is. It is very easy to read and everyone knows what you're doing. Using Optionals can be quite confusing as you can see in other answers here.
One liner with Optionals:
public void setMemory(ArrayList<Integer> memory) {
this.memory = Optional.ofNullable(memory).map((a) -> Optional.ofNullable(a.contains(null) ? null : a).orElseThrow(() -> new IllegalArgumentException("ERROR: memory object can't contain null value."))).orElseThrow(() -> new IllegalArgumentException("ERROR: memory object can't be null."));
}
Sorry for adding yet another answer, but based on reading comments to the question, there might be even better way to change signature of the method: replace ArrayList<Integer> with IntStream:
public void setMemory(#NonNull IntStream input) {
Objects.requireNonNull(input);
this.memory = ...; // collect the stream into the storage
}
Primitive streams do not incur cost of (un)boxing.
This way you don't have to worry about the caller changing List contents under your feet, and will be able to chose the suitable storage for integers as explained in my other answer (or even resolve the stream contents lazily!).
Do not use Optionals, they won't benefit you here.
Instead use a more suitable type in place of ArrayList. Storing Integers in collection incurs (un)boxing costs and does not make sense when nulls are not allowed.
Few possible collection libraries, that may suite your needs better:
HPPC collections (my favorite, but API is incompatible with Java Collection framework)
Koloboke
Fastutil
All of those libraries provide specialized implementations of Lists, Maps and other containers for primitives. Those implementations are generally significantly faster than anything that involves ArrayList<Integer> (unless all integers in your ArrayList are small enough to fit into global Integer instance cache).
As a nice side-effect, using specialized Lists of primitive integers won't allow caller to store nulls by default.
My solution may be used only if you need two different exceptions and more functional style. But it looks complicated and even longer.
.map(e -> false) maps element of list (integer in this case) to boolean which is required for filter().
this.memory = Optional.ofNullable(memory)
.orElseThrow(() -> new IllegalArgumentException("ERROR: memory object can't be null."))
.stream()
.filter(element ->
Optional.ofNullable(element)
.map(e -> true)
.orElseThrow(
() -> new IllegalArgumentException("ERROR: memory object can't contain null value.")))
.collect(Collectors.toList());
Can someone explain how Optional helps us avoid NullPointerException?
Optional<String> op = someFunc()
if(op.isPresent()) {
op.get();
}
String possibleNull = op.get();
Isn't this code prone to NullPointerException too? If so, then why is this code preferred over
String op = someFunc()
if(op != null) {
op.get();
}
String possibleNull = op;
What possible benefit does Optional provide other than the fact that it helps us in knowing whether a function actually had a return value or not
Let's say you want to get a string returned by a function, convert it to upper case, and then print it out. If you have:
String someFunc() { ... }
You might be tempted to write:
System.out.println(someFunc().toUpperCase());
Of course, this throws NullPointerException if someFunc returns null. Instead, suppose we have this:
Optional<String> someFunc() { ... }
Then
System.out.println(someFunc().toUpperCase());
won't work, since Optional doesn't have a toUpperCase method. At this point -- hopefully -- you'll be confronted with an Optional, which should make you think about the case of the Optional being empty. This helps avoid NPEs, but probably only somewhat.
Now you might be focusing on how to get the value out of the Optional, and you might forget about the empty case. Ah, there's a get method:
System.out.println(someFunc().get().toUpperCase());
This brings back the same problem as NPE, except that the exception is NoSuchElementException instead. So if you blindly call get on an Optional, it really is pretty much the same thing as calling a method on a reference without checking whether it's null.
(For this reason, Brian Goetz considers Optional.get to be the biggest mistake in Java 8. See his interview with Angelika Langer JAX 2015 Fragen und Antworten zu Java 8 at about 16 minutes in. I'm not sure it's the biggest, but it is a mistake. People just don't expect get to throw an exception.)
If you're diligent about checking for null references or empty optionals, then
Optional<String> os = someFunc();
if (os.isPresent()) {
System.out.println(os.get().toUpperCase());
}
is hardly any better than the old
String s = someFunc();
if (s != null) {
System.out.println(s.toUpperCase());
}
The real advantage of Optional is that it's a library class that has a fairly rich API for dealing with the empty case in a safe way. It's often possible to process the value that might be contained within an Optional by chaining a couple method calls to the method that returned the Optional in the first place. For example, we could rewrite the sample above as follows:
someFunc().map(String::toUpperCase)
.ifPresent(System.out::println);
String op = someFunc()
if(op != null) {
op.trim();
}
When the interface someFunc() is invoked above, it doesn't explicitly say that a null value could be returned, so the caller is left to his/her own assumption.
By explicitly returning an Optional, the caller of someFunc() is made aware that the interface could potentially return null. From an interface creator's perspective, it lets him/her be specific about the return value rather than having to document it separately.
Optional<String> op = someFunc()
if(op.isPresent()) {
op.get().trim();
}
One scenario where Optional is helpful in avoiding NullPointerException is method chaining.
class A {
private B b;
}
class B {
private C c;
}
class C {
private D d;
}
Let's say I have the above classes, and I want to make sure that an instance of class A has a non-null instance of D, but without causing a null pointer exception.
If I were to directly call a.getB().getC().getD() != null, then it might throw NullPointerException - say if a.getB() was null.
Of course, I can do
try {
a.getB().getC().getD();
// do something
}
catch(NullPointerException e) {
// handle exception
};
But that doesn't look nice. An elegant solution would be to wrap our objects in optional.
Optional.ofNullable(a).map(A::getB).map(B::getC).map(C::getD).isPresent()
Check this for more.
Example code:
modifyMyList(myList);
public void modifyMyList(List someList){
someList.add(someObject);
}
or:
List myList = modifyMyList(myList);
public List modifyMyList(List someList){
someList.add(someObject)
return someList;
}
There is also a 3rd option I believe: You can create a new List in modifyMyList method and return this new List...
( 3rd option is here, I was too lazy but someone already added it in the answers: )
List myList = modifyMyList(myList);
public List modifyMyList(List someList){
List returnList = new ArrayList();
returnList.addAll(someList);
returnList.add(someObject);
return Collections.unmodifiableList(returnList);
}
Is there any reason why I should choose one over another? What should be considered in such case?
I have a (self imposed) rule which is "Never mutate a method parameter in a public method". So, in a private method, it's ok to mutate a parameter (I even try to avoid this case too). But when calling a public method, the parameters should never be mutated and should be considered immutable.
I think that mutating method arguments is a bit hacky and can lead to bugs that are harder to see.
I have been known to make exceptions to this rule but I need a really good reason.
Actually there is no functional difference.
You'll come to know the difference when you want the returned list
List someNewList = someInstnace.modifyMyList(list);
The second is probably confusing as it implies a new value is being created and returned - and it isn't.
An exception would be if the method was part of a 'fluent' API, where the method was an instance method and was modifying its instance, and then returning the instance to allow method chaining: the Java StringBuilder class is an example of this.
In general, however, I wouldn't use either.
I'd go for your third option: I write a method that creates and returns a new list with the appropriate change. This is a bit artificial in the case of your example, as the example is really just reproducing List.add(), but...
/** Creates a copy of the list, with val appended. */
public static <T> List<T> modifyMyList(List<T> list, T val) {
List<T> xs = new ArrayList<T>(list);
xs.add(val);
return xs;
}
Aside: I wouldn't, as suggested by Saket return an immutable list. His argument for immutability and parallelism is valid. But most of the time Java programmers expect to be able to modify a collection, except in special circumstances. By making you method return an immutable collection, you limit it's reusability to such circumstances. (The caller can always make the list immutable if they want to: they know the returned value is a copy and won't be touched by anything else.) Put another way: Java is not Clojure. Also, if parallelism is a concern, look at Java 8 and streams (the new kind - not I/O streams).
Here's a different example:
/** Returns a copy of a list sans-nulls. */
public static <T> List<T> compact(Iterable<T> it) {
List<T> xs = new ArrayList<T>();
for(T x : it)
if(x!=null) xs.add(x);
return xs;
}
Note that I've genercized the method and made it more widely applicable to taking an Iterable instead of a list. In real code, I'd have two overloaded versions, one taking an Iterable and one an Iterator. (The first would be implemented by calling the second, with the iterable's iterator.) Also, I've made it static as there was no reason for your method to be an instance method (it does not depend on state from the instance).
Sometimes, though, if I'm writing library code, and if it is not clear whether a mutating or non-mutating implementation is more generally useful, I create both. Here's a fuller example:
/** Returns a copy of the elements from an Iterable, as a List, sans-nulls. */
public static <T> List<T> compact(Iterable<T> it) {
return compact(it.iterator());
}
public static <T> List<T> compact(Iterator<T> iter) {
List<T> xs = new ArrayList<T>();
while(iter.hasNext()) {
T x = iter.next();
if(x!=null) xs.add(x);
}
return xs;
}
/** In-place, mutating version of compact(). */
public static <T> void compactIn(Iterable<T> it) {
// Note: for a 'fluent' version of this API, have this return 'it'.
compactIn(it.iterator());
}
public static <T> void compactIn(Iterator<T> iter) {
while(iter.hasNext()) {
T x = iter.next();
if(x==null) iter.remove();
}
}
If this was in a real API I'd check the arguments for null and throw IllegalArgumentException. (NOT NullPointerException - though it is often used for this purpose. NullPointerException happens for other reasons as well, e.g. buggy code. IllegalArgumentException is better for invalid parameters.)
(There'd also be more Javadoc than actual code too!)
The first and second solution are very similar, The advantage of the second is to permit chaining. The question of "is it a good practise" is subjected to debate as we can see here:
Method Chaining in Java
So the real question is between the first solution with mutable list and the third with a unmutable list, and again, there is not a unique response, it is the same debate between returning String, which are immutable and using Stringbuffer, which are mutable but permits better performance.
If you need reliablility of your API , and if you don't have performance issues use immutable (the third solution). Use it if your lists are always small.
If you need only performance use a mutable list (the first solution)
I will recommend creating a new list in the method and returning an immutable list. That way your code will work even when you are passed in an Immutable list. It is generally a good practice to create immutable objects as we generally move towards functional programming and try to scale across multiple processor architectures.
List myList = modifyMyList(myList);
public List modifyMyList(List someList){
List returnList = new ArrayList();
returnList.addAll(someList);
returnList.add(someObject);
return Collections.unmodifiableList(returnList);
}
As I said in my other answer, I don't think you should mutate the list parameter. But there are times where you also don't want to take a copy of the original list and mutate the copy.
The original list might be large so the copy is expensive
You want the copy to be kept up-to-date with any updates to the original list.
In these scenarios, you could create a MergedList which is a view over two (or perhaps more) lists
import java.util.*;
public class MergedList<T> extends AbstractList<T> {
private final List<T> list1;
private final List<T> list2;
public MergedList(List<T> list1, List<T> list2) {
this.list1 = list1;
this.list2 = list2;
}
#Override
public Iterator<T> iterator() {
return new Iterator<T>() {
Iterator<T> it1 = list1.iterator();
Iterator<T> it2 = list1.iterator();
#Override
public boolean hasNext() {
return it1.hasNext() || it2.hasNext();
}
#Override
public T next() {
return it1.hasNext() ? it1.next() : it2.next();
}
};
}
#Override
public T get(int index) {
int size1 = list1.size();
return index < size1 ? list1.get(index) : list2.get(index - size1);
}
#Override
public int size() {
return list1.size() + list2.size();
}
}
The you could do
public List<String> modifyMyList(List<String> someList){
return new MergedList(someList, List.of("foo", "bar", "baz"));
}
Both ways will work because in this case java works with the reference of the List but i prefer the secound way because this solution works for pass by value too, not only for pass by reference.
Functionally both are same.
However when you expose your method as an API, second method may give an impression that it returns a new modified list other than the original passed list.
While the first method would make it clear (of-course based on method naming convention) that it will modify the original list (Same object).
Also, the second method returns a list, so ideally the caller should check for a null return value even if the passed list is non null (The method can potentially return a null instead of modified list).
Considering this I generally prefer to use method one over second.
How do I write a static method in Java that will take a List, perform an action on each element, and return the result (without affecting the original of course)?
For example, if I want to add 2 to each element what goes in the ... here? The concrete return type must be the same, e.g. if my List is a LinkedList with values 1,2,3 I should get back a LinkedList with values 3,4,5. Similarly for ArrayList, Vector, Stack etc, which are all Lists.
I can see how to do this using multiple if (lst instanceof LinkedList) ... etc... any better way?
import java.util.List;
public class ListAdd {
static List<Integer> add2 (List<Integer> lst) {
...
return result;
}
}
There are already many answers, but I'd like to show you a different way to think of this problem.
The operation you want to perform is known as map in the world of functional programming. It is something we do really all the time in functional languages.
Let M<A> be some kind of container (in your case, M would be List, and A would be Integer; however, the container can be lots of other things). Suppose you have a function that transforms As into Bs, that is, f: A -> B. Let's write this function as of type F<A, B>, to use a notation closer to Java. Note that you can have A = B, as in the example you give (in which A = B = Integer).
Then, the operation map is defined as follows:
M<B> map(M<A>, F<A, B>)
That is, the operation will return a M<B>, presumably by applying F<A, B> to each A in M<A>.
In practice...
There's a brilliant library developed by Google, called Guava, which brings lot's of functional idioms to Java.
In Guava, the map operation is called transform, and it can operate on any Iterable. It has also more specific implementations that work directly on lists, sets, etc.
Using Guava, the code you want to write would look like this:
static List<Integer> add2(List<Integer> ns) {
return Lists.transform(ns, new Function<Integer, Integer>() {
#Override Integer apply(Integer n) { return n + 2; }
}
}
Simple as that.
This code won't touch the original list, it will simply provide a new list that calculates its values as needed (that is, the values of the newly created list won't be calculated unless needed -- it's called a lazy operation).
As a final consideration, it is not possible for you to be absolutely sure that you will be able to return exactly the same implementation of List. And as many others pointed out, unless there's a very specific reason for this, you shouldn't really care. That's why List is an interface, you don't care about the implementation.
Fundamentally, the List interface doesn't make any guarantees that you'll have a way to duplicate it.
You may have some luck with various techniques:
Using clone() on the passed in List, although it may throw, or (since it is protected in Object) simply not be accessible
Use reflection to look for a public no-argument constructor on the passed-in List
Try to serialize and deserialize it in order to perform a "deep clone"
Create some sort of factory and build in knowledge of how to duplicate each different kind of List your code may encounter (What if it's a wrapper created by unmodifiableList(), or some oddball custom implementation backed by a RandomAccessFile?)
If all else fails, either throw, or return an ArrayList or a Vector for lack of better options
You could use reflection to look for a public zero-arg constructor on the result of lst.getClass() and then invoke() it to obtain the List into which you'll place your results. The Java Collections Framework recommends that any derivative of Collection offer a zero-arg constructor. That way, your results we be of the same runtime class as the argument.
Here is a variant which does neither copies nor modifies the original list. Instead, it wraps the original list by another object.
public List<Integer> add2(final List<Integer> lst) {
return new AbstractList<Integer>() {
public int size() {
return lst.size();
}
public Integer get(int index) {
return 2 + lst.get(index);
}
};
}
The returned list is not modifiable, but will change whenever the original list changes.
(This implements the iterator based on index access, thus it will be slow for a linked list. Then better implement it based on AbstractSequentialList.)
Of course, the resulting list will obviously not be of the same class as the original list.
Use this solution only if you really only need a read-only two added view of your original list, not if you want a modified copy with similar properties.
The whole point of using an interface, in this case List, is to abstract the fact that the implementation is hidden behind the interface.
Your intention is clear to me, however: the Clonable interface supports creating a new instance with the same state. This interface might not be defined on your List.
Often it's a good idea to rethink this situation: why do you need to clone the List in this place, this class? Shouldn't your list-creator be responsible for cloning the list? Or shouldn't the caller, who knows the type, make sure he passes in a clone of his list?
Probably, if you look for the semantics as you defined it, you can implement all your supported Lists:
static Vector<Integer> addTwo(Vector<Integer> vector) {
Vector<Integer> copy = null; // TODO: copy the vector
return addTwo_mutable(copy);
}
static ArrayList<Integer> addTwo(ArrayList<Integer> aList) {
ArrayList<Integer> copy = null; // TODO: copy the array list
return addTwo_mutable(copy);
}
static LinkedList<Integer> addTwo(LinkedList<Integer> lList) {
LinkedList<Integer> copy = null; // TODO: copy the linked list
return addTwo_mutable(copy);
}
private <T extends List<Integer>> static T addTwo_mutable(T list) {
return list; // TODO: implement
}
Even, when you don't support a data-type, you'll get a nice compiler error that the specified method does not exists.
(code not tested)
Just to show you that what you want to do is not possible in the general case, consider the following class:
final class MyList extends ArrayList<Integer> {
private MyList() {
super.add(1);
super.add(2);
super.add(3);
}
private static class SingletonHolder {
private static final MyList instance = new MyList();
}
public static MyList getInstance() {
return SingletonHolder.instance;
}
}
It is a singleton (also, a lazy, thread-safe singleton by the way), it's only instance can be obtained from MyList.getInstance(). You cannot use reflection reliably (because the constructor is private; for you to use reflection, you'd have to rely on proprietary, non-standard, non-portable APIs, or on code that could break due to a SecurityManager). So, there's no way for you to return a new instance of this list, with different values.
It's final as well, so that you cannot return a child of it.
Also, it would be possible to override every method of ArrayList that would modify the list, so that it would be really an immutable singleton.
Now, why would you want to return the exact same implementation of List?
OK well someone mentioned reflection. It seems to be an elegant solution:
import java.util.*;
public class ListAdd {
static List<Integer> add2 (List<Integer> lst) throws Exception {
List<Integer> result = lst.getClass().newInstance();
for (Integer i : lst) result.add(i + 2);
return result;
}
}
Concise, but it thows an checked exception, which is not nice.
Also, wouldn't it be nicer if we could use the method on concrete types as well, e.g. if a is an ArrayList with values 1, 2, 3, we could call add2(a) and get an ArrayList back? So in an improved version, we could make the signature generic:
static <T extends List<Integer>> T add2 (T lst) {
T res;
try {
res = (T) lst.getClass().newInstance();
} catch (InstantiationException e) {
throw new IllegalArgumentException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
for (Integer i : lst) res.add(i + 2);
return res;
}
I think throwing a runtime exception is the least worst option if a list without a nullary construcor is passed in. I don't see a way to ensure that it does. (Java 8 type annotations to the rescue maybe?) Returning null would be kind of useless.
The downside of using this signature is that we can't return an ArrayList etc as the default, as we could have done as an alternative to throwing an exception, since the return type is guaranteed to be the same type as that passed in. However, if the user actually wants an ArrayList (or some other default type) back, he can make an ArrayList copy and use the method on that.
If anyone with API design experience reads this, I would be interested to know your thoughts on which is the preferable option: 1) returning a List that needs to be explicity cast back into the original type, but enabling a return of a different concrete type, or 2) ensuring the return type is the same (using generics), but risking exceptions if (for example) a singleton object without a nullary constructor is passed in?
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());
}
});