No, the fact that an interface is a functional interface doesn’t allow any alternative calling syntax; it’s methods are invoked like any other interface method.
But you can just factor out more of the common code to shorten the repeated code
Function<String, Supplier<IllegalArgumentException>> f = name ->
() -> new IllegalArgumentException("Property "+name+" is not set in the environment");
String valueA = Optional.of("A").map(System::getProperty).orElseThrow(f.apply("A"));
String valueB = Optional.of("B").map(System::getProperty).orElseThrow(f.apply("B"));
however, this still has no advantage over a conventional
public static String getRequiredProperty(String name) {
String value = System.getProperty(name);
if (value == null) {
throw new IllegalArgumentException("Property "+name+" is not set in the environment");
}
return value;
}
String valueA = getRequiredProperty("A");
String valueB = getRequiredProperty("B");
which has the advantage of having no code duplication (esp. regarding the constants "A" and "B"), thus less room for accidental inconsistencies.
No, there is no alternative like that. apply() is "just" a method of the Function interface, so that method must be called. There is no syntactic sugar to make that more concise.
You use lambda like this
public static void main(String[] args) {
BiFunction<Integer, Integer, Integer> add = (x, y) -> {
return x + y;
};
System.out.println(add.apply(1, 2));
}
If you're a long time Java coder, the new lambda stuff can be confusing -- it was(is?) for me. Lambdas are a contextual construct that the compiler interprets based on the context where it is used, just like a lot of other scripting languages. For most cases, you never need to create your own sub-types because the compiler does it for you based on where you are using them. Objectively, we think, "Yeah, I know. Duh." But it's tough making your brain change thought patterns. That's one of the big hurdles I think a lot of developers need to overcome.
I can see how we want to think, "Gee, I want my own BiConsumer that concatenates two Strings and adds them to a List." So you generate your class file in your favorite IDE and get
public static class StringConcat implements BiConsumer<String,String>{
private List<String> values = new ArrayList<>();
@Override
public void accept(String s, String s2) {
values.add(s,s2);
}
}
And when you go to try and find a good use for it you can't really seem to find one. That's because there isn't any need to create one.
I've been hard-pressed to find a situation where I need to create my own class that implements any of the java.util.function stuff. Not saying there aren't cases, I just haven't found too many.
It boils down to recognizing when you have something that takes a type that has a single abstract method, like Comparable.compare(T t1, T t2) or Runnable.run(). In these cases, you simply in-line the lambda construct.
So using the functionality of my StringConcat, given a Map<String,String> map
// I just passed it a new BiConsumer!
map.forEach((k,v)-> list.add(k+v));
EDIT: After your comments and re-reading your question, I think you still have a bit of a mental block. It looks as though you want to declare a lambda, instantiate it and call it in three distinct steps. That sort of defeats the purpose. When you use lambdas, you do the first two steps when you create the lambda inline with something that takes it.
// declare AND instantiate
stringList.stream().map(string -> Integer.parseInt(string))...
This is saying, "for every string in the list, apply this function, Integer.parseInt(string)." Notice you don't ever call apply(). That's done within the map method. This avoids the need to do what you are doing with creating an instance and separately trying to call it.
Lambdas are not a magic bullet. In most cases, you still need to have separate methods with distinct statements. Maybe the functionality you want doesn't play well with lambdas.
You can use a Stream with map and collect :
listB = listA.stream()
.map (a -> a*a)
.collect (Collectors.toList());
To add to @Eran's answer I have a helper method:
public static <T, R> List<R> apply(Collection<T> coll, Function<? super T, ? extends R> mapper) {
return coll.stream().map(mapper).collect(Collectors.toList());
}
can be used as:
List<Integer> listB = apply(listA, a -> a * a);
(Note: will require Java 1.8 or higher.)