According to Effective Java 2nd Ed, when you want to write a method signature that allows for varargs but still enforces that you have one element minimum at compile-time you should write the method signature this way:
public void something(String required, String ... additional) {
//... do what you want to do
}
If I want to stream all these elements, I've been doing something like this:
public void something(String required, String ... additional) {
Stream<String> allParams =
Stream.concat(Stream.of(required), Stream.of(additional));
//... do what you want to do
}
This feels really inelegant and wasteful, especially because I'm creating a stream of 1 and concatenating it with another. Is there a cleaner way to do this?
Here is a way for doing it without creating two Streams, although you might not like it.
Stream.Builder<String> builder = Stream.<String>builder().add(required);
for (String s : additional) {
builder.add(s);
}
Stream<String> allParams = builder.build();
There is nothing wrong with the composed streams. These objects are lightweight as they only refer to the source data but don’t copy data like array contents. The cost of such lightweight object might only be relevant if the actual payload is very small as well. Such scenarios can be handled with specialized, semantically equivalent overloads:
public void something(String required, String ... additional) {
somethingImpl(Stream.concat(Stream.of(required), Stream.of(additional)));
}
public void something(String required) {
somethingImpl(Stream.of(required));
}
public void something(String required, String second) {
somethingImpl(Stream.of(required, second));
}
private void somethingImpl(Stream<String> allParams) {
//... do what you want to do
}
so in the case of only one argument you’re not only saving Stream instances but also the varargs array (similar to Stream.of’s overload). This is a common pattern, see for example the EnumSet.of overloads.
However, in a lot of cases even these simple overloads are not necessary and might be considered premature optimization (libraries like the JRE offer them as it’s otherwise impossible for an application developer to add them if ever needed). If something is part of an application rather than a library you shouldn’t add them unless a profiler tells you that there’s a bottleneck caused by that parameter processing.
If you're willing to use Guava, you may Lists.asList(required, additional).stream(). The method was created to ease that varargs with minimum requirement idiom.
A side note, I consider the library really useful, but of course it's not a good idea to add it just because of that. Check the docs and see if it could be of more use to you.
Unfortunately, Java can be quite verbose. But another option to alleviate that is to simply use static imports. In my opinion, it does not make your code less clear since every method is stream-related.
Stream<String> allParams =
concat(of(required), of(additional));
Third-party extensions to Stream API like my StreamEx or jOOλ provide methods like append or prepend which allow you to do this in more clean way:
// Using StreamEx
Stream<String> allParams = StreamEx.of(required).append(additional);
// Using jOOL
Stream<String> allParams = Seq.of(required).append(additional);
Related
I often convert lists like that
myList.stream().map(el -> el.name).collect(Collectors.toList())
is there any shorter version for this?
There's no shorter way to do this using streams.
you could import import static java.util.stream.Collectors.*; and then use toList as follows to shorten the code a little bit but apart from this. The below is as compact as it gets using streams:
myList.stream().map(el -> el.name).collect(toList());
You could also use a method reference
myList.stream().map(T::getName).collect(toList());
where T is the name of type that contains name although this is not guaranteed to be shorter depending on how long the type name is but does provide better readability which is very important.
Ultimately, as said this is as compact as it gets.
You could create a static helper method that does all the work:
public static <FROM, TO> List<TO> convert(List<FROM> from, Function<FROM, TO> function) {
return from.stream().map(function).collect(Collectors.toList());
}
All you have to do is provide your list and any mapping function:
List<YourClass> yourList = ...;
Function<YourClass, String> func = YourClass::getName;
List<String> converted = convert(yourList, func);
Or even more concise:
List<String> converted = convert(yourList, YourClass::getName);
I think that you should stick to what you have already got. Why?
It’s already a one-liner. No real point in trying to squeeze it down further.
It’s idiomatic. Java developers are used to read conversions like yours, and if it’s all over the place in your code, programmers that read your code will be even more used to it. Even wrapping it in a method, like #QBrute suggested, even though a nice idea, risks harming readability because readers are not used to the wrapping method.
Remember: Brevity is not a goal. Clarity is. The two often go hand in hand, but not always, and my feeling is they may not in your case.
Reservation: My style and taste is in favour of the method reference that #Aomine uses, but it is a matter of taste. Use it if you find it clearer, not just because it’s a few chars shorter.
You could statically import Collectors.* and then use the mapping(Function, Collector) method, like this:
myList.stream().collect(mapping(T::getName, toList()));
Where T::getName is a method reference and T is the Type of the elements in the List. Using this is more readable and also almost identical to writing: el -> el.name
There is an event class:
public class Event {
private int index;
public int getIndex() {return index;}
}
Also there is a method - it selects an event sublist with certain values of "index" property. Extremely simple, but such functionality is widely used.
public List<Event> select(List<Event> scenario, List<Integer> indexesToInclude) {
Predicate<Event> indexMatcher = e -> indexesToInclude.contains(e.getIndex());
return scenario.stream().filter(indexMatcher).collect(Collectors.toList());
}
The task is to avoid usage of -> operator in favor of :: operator. Why? Because e -> ... looks like a workaround for such common task.
Is it possible to do?
I expect syntax like (this won't compile of course):
Predicate<Event> indexMatcher = { indexesToInclude.contains(Event::getIndex) };
however it can be a chain of methods or other solution without writing loops or creating new classes/methods.
Is it possible to do?
No. Lambda expressions (the so-called "workaround") are the way to do this. That's what they were added to the language for.
(Actually ... you could do this the old-school way by defining an anonymous inner class. But it won't be a one-liner.)
Why? Because e -> ... looks like a workaround for such common task.
I guess, it depends on your perspective. For instance, a syntax purist might consider s1 + i as a "workaround" for s1.concat(Integer.toString(i)).
In fact, these things are generally called "syntactic sugar" ... and they are added to a language to make it easier to write concise and readable code.
Obviously, to be able to read the code you first need to understand the syntax, then you need to get used to it.
Unfortunately, it seems that the real problem here seems to be that you don't like the Java lambda syntax. Sorry, but you will just need to get used to it. Fighting it is not going to work.
For example, some method has the next implementation:
void setExcludedCategories(List<Long> excludedCategories) {
if (excludedCategories.contains(1L)) {
excludedCategories.remove(1L);
}
}
And it's called in the next way:
setExcludedCategories(Array.asList(1L, 2L, 3L));
Of course, it will lead ot an exception java.lang.UnsupportedOperationException when it will try to remove item.
The question: how can I modify this code to be sure that the input parameter excludedCategories supports remove?
UPD:
Thanks for answers. Let's summarize results:
Always create new ArrayList from the input list to be sure it's mutable - a lot of useless memory would be used -> NO.
Catch the UnsupportedOperationException.
Specify in the JavaDoc that a caller mustn't pass an immutable list - anybody read the JavaDoc? When something doesn't work only :)
Don't use Arrays.asList() in a caller's code - that's an option, if you an owner of this code, but anyway you should know if this concrete method allows immutable or not (see 3).
It seems the second variant is the only way to resolve this problem.
How can I modify this code to be sure that the input parameter excludedCategories supports remove?
In the general case, you can't. Given an arbitrary class that implements the List API, you cannot tell (statically or dynamically) if the optional methods are supported.
You can use instanceof tests to check if the class of the list is known to implement the method or to not implement it. For example ArrayList and LinkedList do, but Collections.UnmodifiableList does not. The problem is that your code could encounter list classes that your tests don't cover. (Especially if it is a library that is intended to be reusable in other peoples applications.)
You could also try to test the behavior of previously unknown classes; e.g. create a test instance, try a remove to see what happens, and record the behavior in a Map<Class, Boolean>. There are two problems with this:
You may not be able to (correctly) instantiate the list class to test it.
The behavior could depend on how you instantiate the class (e.g. constructor parameters) or even on the nature of the element you are trying to remove ... though the latter is pushing the boundary of plausibility.
In fact, the only completely reliable approach is to call the method and catch the exception (if it is thrown) each and every time.
In short, you can't know. If an object implements an interface (such as List) you can't know if it will actually do what is expected for all of the methods. For instance Collections.unmodifiableList() returns a List that throws UnsupportedOperationException. It can't be filtered out via the method signature if you want to be able to get other List implementations.
The best you can do is to throw IllegalArgumentException for known subtypes that don't support what you want. And catch UnsupportedOperationException for other types of cases. But really you should javadoc your method with what is required and that it throws IllegalArgumentException in other cases.
That depends somewhat on what you're trying to do. In your posted example for example you could just catch the UnsupportedOperationException and do something else instead.
This assumes that you can assume that non-mutable containers will throw that on every attempt to modify the container and will do so without side effects (that is they are indeed non-mutable).
In other cases where your code has other side effects than trying to modify the container you will have to make sure these doesn't happen before knowing that you can modify the container.
You can catch the exception in an utility class like in the example below (as others mentioned). Bad thing is you have to do insert/delete to test if there will be exception. You can not use instanceof since all Collections.Unmodifiablexxx classes have default access.
CollectionUtils:
import java.util.List;
public class CollectionUtils {
public <T> boolean isUnmodifiableList(List<T> listToCheck) {
T object = listToCheck.get(0);
try {
listToCheck.remove(object);
} catch (UnsupportedOperationException unsupportedOperationException) {
return true;
}
listToCheck.add(0, object);
return false;
}
}
Main:
import java.util.Arrays;
import java.util.List;
public class Main {
private static final CollectionUtils COLLECTION_UTILS = new CollectionUtils();
public static void main(String[] args) {
setExcludedCategories(Arrays.asList(1L, 2L, 3L));
}
private static void setExcludedCategories(List<Long> excludedCategories) {
if (excludedCategories.contains(1L)) {
if(!COLLECTION_UTILS.<Long>isUnmodifiableList(excludedCategories)){
excludedCategories.remove(1L);
}
}
}
}
Arrays.asList(T... a) returns the List<java.util.Arrays.ArrayList<E>> which is an immutable list. To get your code working just wrap the result with java.util.ArrayList<T> like shown below
setExcludedCategories(new ArrayList<Long>(Arrays.asList(1L, 2L, 3L)));
Always create new ArrayList from the input list to be sure it's mutable - a lot of useless memory would be used -> NO.
Thats actually the preferred way to do things. "A lot of useless memory" isn't a lot in most practical situations, certainly not in your cited exampled.
And ignoring that, its the only robust and inutitively understood idiom.
The only workable alternative would be to explicitly change the name of your method (thus communicating its behavior better), form the example you show, name it "removeExcludedCategories" if its meant to modify the argument list (but not an objects state).
Otherwise if it is meant as a bulk-setter, you're out of luck, there is no commonly recognized naming idiom that clearly communicates that the argument collection is directly incorporated into the state of an object (its dangerous also because the objects state can then be altered without the object knowing about it).
Also, only marginally related, I would design not an exclusion list, but an exclusion set. Sets are conceptually better suited (no duplicates) and there are set implementations that have far better runtime complexity for the most commonly asked question: contains().
I read an article on Joel On Software about the idea of using higher order functions to greatly simplify code through the use of map and reduce. He mentioned that this was difficult to do in Java. The article: http://www.joelonsoftware.com/items/2006/08/01.html
The example from the article below, loops through an array, and uses the function fn that was passed as an argument on each element in the array:
function map(fn, a)
{
for (i = 0; i < a.length; i++)
{
a[i] = fn(a[i]);
}
}
This would be invoked similar to the below in practice:
map( function(x){return x*2;}, a );
map( alert, a );
Ideally I'd like to write a map function to work on arrays, or Collections of any type if possible.
I have been looking around on the Internet, and I am having a difficult time finding resources on the subject. Firstly, are anonymous functions possible in java? Is this possible to do in another way? Will it be available in a future version of java? If possible, how can I do it?
I imagine that if this is not possible in Java there is some kind of 'pattern'/technique that people use to achieve the same effect, as I imagine anonymous functions are a very powerful tool in the software world. the only similar question I was able to find was this: Java generics - implementing higher order functions like map and it makes absolutely no sense to me.
Guava provides map (but it's called transform instead, and is in utility classes like Lists and Collections2). It doesn't provide fold/reduce, however.
In any case, the syntax for using transform feels really clunky compared to using map in Scheme. It's a bit like trying to write with your left hand, if you're right-handed. But, this is Java; what do you expect. :-P
Looks like this one?
How can I write an anonymous function in Java?
P.S: try Functional Java. Maybe it could give you hints.
Single method anonymous classes provide a similar, but much more verbose, way of writing an anonymous function in Java.
For example, you could have:
Iterable<Source> foos = ...;
Iterable<Destination> mappedFoos = foos.map(new Function<Source, Destination>()
{
public Destination apply(Source item) { return ... }
});
For an example of a Java library with a functional style, see Guava
interface Func<V,A> {
V call (A a);
}
static <V,A> List<V> map (Func<V,A> func, List<A> as) {
List<V> vs = new ArrayList<V>(as.size());
for (A a : as) {
Vs.add(func.call(a));
}
return vs;
}
Paguro has an open-source implementation of higher order functions. Initial test show it to be 98% as fast as the native Java forEach loop. The operations it supports are applied lazily without modifying the underlying collection. It outputs to type-safe versions of the immutable (and sometimes mutable) Clojure collections. Transformable is built into Paguro's unmodifiable and immutable collections and interfaces. To use a raw java.util collection as input, just wrap it with the xform() function.
Assume a class (for instance URI) that is convertable to and from a String using the constructor and toString() method.
I have an ArrayList<URI> and I want to copy it to an ArrayList<String>, or the other way around.
Is there a utility function in the Java standard library that will do it? Something like:
java.util.collections.copy(urlArray,stringArray);
I know there are utility libraries that provide that function, but I don't want to add an unnecessary library.
I also know how to write such a function, but it's annoying to read code and find that someone has written functions that already exist in the standard library.
I know you don't want to add additional libraries, but for anyone who finds this from a search engine, in google-collections you might use:
List<String> strings = Lists.transform(uris, Functions.toStringFunction());
one way, and
List<String> uris = Lists.transform(strings, new Function<String, URI>() {
public URI apply(String from) {
try {
return new URI(from);
} catch (URISyntaxException e) {
// whatever you need to do here
}
}
});
the other.
No, there is no standard JDK shortcut to do this.
Have a look at commons-collections:
http://commons.apache.org/collections/
I believe that CollectionUtils has a transform method.
Since two types of collections may not be compatible, there is no built-in method for converting one typed collection to another typed collection.
Try:
public ArrayList<String> convert(ArrayList<URI> source) {
ArrayList<String> dest=new ArrayList<String>();
for(URI uri : source)
dest.add(source.toString());
return dest;
}
Seriously, would a built-in API offer a lot to that?
Also, not very OO. the URI array should probably be wrapped in a class. The class might have a .asStrings() method.
Furthermore you'll probably find that you don't even need (or even want) the String collection version if you write your URI class correctly. You may just want a getAsString(int index) method, or a getStringIterator() method on your URI class, then you can pass your URI class in to whatever method you were going to pass your string collection to.