How to use function interface, and use it as function argument? - java

I am not that good with function interface.
How to make Function<S, Set<S>> and how to send it as parameter?
public class Algorithms {
public static <S> Optional<Node<S>> search(S s0, Function<S, Set<S>> succ, Predicate<S> goal) {
.
.
.
return Optional.empty();
}
}

Any interface with exactly one non-default method is a functional interface, and Function meets that condition. That means you can implement it using a lambda expression. For example, let's say we're using this search function to search someone's family tree:
search(alice, (person) -> person.getChildren(), (person) -> person.getName().equals("Bob"));
The second argument, (person) -> person.getChildren(), creates a Function<Person, Set<Person>> that calls getChildren() on its argument. (We know it should accept a Person and return a Set<Person> from how we're passing it to search.) Likewise, the third argument creates a Predicate<Person> that checks if their name is "Bob".
Now, there are two "convenience" features I'm glossing over here. When the lambda only takes one argument (as is the case with both Function and Predicate), you can omit the parentheses around the name. Secondly, when a lambda only calls some method on its argument, you can use a method reference, which is just a more concise way of writing the lambda:
search(alice, Person::getChildren, person -> person.getName().equals("Bob"));
That's entirely equivalent, just more concise.
You can also implement functional interfaces the "old-school" way, i.e. by writing an (anonymous) class, but lambda syntax avoids a lot of boilerplate and is more readable. It's still fundamentally doing the same thing (and your IDE should be able to transform the one to the other, if that's helpful for you).

Related

What is the variable between parenthesis and the arrow (->) in a Java lambda?

The IDE's recommended fix generated code like the following.
col1.setCellValueFactory(
(Callback<CellDataFeatures<String, String>, ObservableValue<String>>) param ->
new SimpleObjectProperty<>(param.getValue().getValue())
);
I do not understand the param between ObservableValue<String>>) and ->. Is there a hint like what this is called so that I can search the web for more details about this type of code?
Below are the signatures of the methods and interface.
void setCellValueFactory(Callback<TreeTableColumn.CellDataFeatures<S, T>, ObservableValue<T>> var1)
public interface Callback<P, R> {
R call(P var1);
}
PS: Since some person told me to specify col1, it is an object of the TreeTableColumn class in JavaFX.
I think I was deceived by the parentheses and the param's not having parenthesis, and thought those in the parentheses were the parameters. I had expected a form like below.
On close inspection, the code inside the parentheses is just type declarations, not variables... And it seems that parentheses for parameters can be omitted when there is only one parameter.
param is the parameter that is being passed on to lambda. This code will help you understand what is happening:
Function<String,String> s = (Function<String,String>) param -> {
System.out.println(param);
return param;
};
s.apply("Hello World");
This above code is unnecessarily casting the lambda to (Function<String, String>).
If you change it to (Function<String,Long>), you will get compile time error.
You asked what param was and whether it could be searched on. You also asked about the "form" of the lambda expression (why parenthesis are present or not). My answer below addresses those questions.
Searching for the text param will not usually work as the text param is arbitrary... you could replace it with p or even arbitraryName and as long as the name on the right of the -> in the lambda expression changes to the same value the code should still work.
You can think of param as the name given to a "passed in" parameter. In the method declaration below there are two parameters (param and anotherParam).
public void myPrint(String param, String anotherParam) {
System.out.println(param+", "+anotherParam);
}
A lambda expression is like a method declaration (like the above) but unneeded text can be removed in the syntax of the lambda expression. If the above COULD be made into a Lambda expression it would look like the following:
(String param, String anotherParam) -> { System.out.println(param+", "+anotherParam); }
Notice how similar the lambda expression is to the method declaration. Notice also that the text "myPrint" does not appear in the above. A lambda expression can be thought of as a "nameless" method declaration. In Java, a lambda expression is providing the code to implement a SingleAbstractMethod (SAM) in an an interface that only has a single abstract method defined. Assuming you had an interface with "MyPrint" defined as the name of the SAM then "MyPrint" is not needed (it is the only abstract method in the interface). Lambda Expressions work because a SAM Interface is a "Functional Interface" and lambda expressions implement the SAM in a functional interface. In a lambda expression the method name that you are implementing is ALWAYS not needed. This is one of the things that makes lambda expressions hard to understand as you normally understand a method by its name (to some degree) and you would like to search on the method name the lambda expression is implementing but that name does not appear in the lambda code.
The code above could also be written as...
(param, anotherParam) -> { System.out.println(param+", "+anotherParam); }
if the Java Type system can figure out the parameter types (in this case String) for itself. Again, the names param and anotherParam are arbitrary but their types are not. They are defined by the SAM in the functional interface you are implementing with the lambda. Another reason lambdas are hard to understand is the type of the parameter(s) is often interesting... but it is often left off from the lambda expression as it is not always needed by Java.
If there was only one parameter needed by the SAM the lambda expression could be written like the following
(String param) -> { System.out.println(param); }
or if "String" could be determined by Java
(param) -> { System.out.println(param); }
or even the () are not needed in this last version
param -> { System.out.println(param); }
There are other simplifications as well. In some cases the {} on the right side of the -> can be removed if it is only a single statement or expression.
If there are no parameters in the SAM being implemented then the code () -> is used where () signifies no parameters.
The last thing that I'll mention that is hard to understand about a lambda expression is the large number of syntax simplifications that can be made (see all the above). This appears to be the majority of your confusion.
Bottom Line: a lambda expression can be thought of as a nameless method declaration where you are overriding a SAM in a functional interface. The left hand side of the -> are the parameter declarations... the parameter types and even the () are not always needed. The right hand side of the -> is the body of the method and in some cases the {} are not needed.
Keys to understanding a lambda expression is understanding the syntax (all the above forms) and determining and understanding the functional interface and SAM that is being implemented. Unfortunately neither the functional interface or the name of the SAM show up in the lambda expression syntax itself... it is simplified away as not being needed!

Can you explain why the first unwrapped method reference does not compile?

In this example, passing a method reference to Stream.of does not work but once it's wrapped it works. I can't quite get my head around why this is. Isn't the method reference equivalent to the functional interface?
public class A {
String a() {
return "";
}
void b() {
Stream.of(this::a); // won't compile
Stream.of(wrap(this::a)); // will compile
}
static <T> Supplier<T> wrap(Supplier<T> f) {
return f;
}
}
Stream.of has the following signature:
public static<T> Stream<T> of(T t)
The following example will compile because you explicitly providing a type information for T.
Stream<Supplier<String>> a = Stream.of(this::a);
The first example Stream.of(this::a); equivalent to:
Object a = this::a;
where Object is not a functional interface and will not compile.
Providing with a functional interface this example compiles:
Runnable a = this::a;
Stream.of(a);
In the second example, wrap provides a functional interface Supplier
Stream.of(T) expects an Object and you pass to it a method reference in the first statement. But an Object parameter is not a functional interface, so it cannot accept a method reference or a lambda that is not specifically typed.
With lambda, it would produce also an error : Stream.of(()->this.a()).
A simpler example could be Stream.of(()-> "foo") that will just not compile.
But if you type the method reference or the lambda it works :
Stream.of((Supplier<String>) this::a)
or
Stream.of((Supplier<String>) () -> this.a())
In the working statement you pass to Stream.of(T) a parameter that is a Supplier<String>. That refers to a functional interface but that is typed as in the previous working examples, so it is valid as parameter that expects an Object.
this::a is contextless and could mean different things. You need to provide some context to help the compiler to figure out what you actually meant by this::a.
Stream.<Supplier<String>>of(this::a);
Though, that Stream<Supplier<String>> doesn't seem to be what you wanted. If you need a Stream<String>, use Stream.generate: no extra type information needed since the method takes a Supplier<T> (no ambiguity here).
Stream.generate(this::a);
On a side note, both statements expect you to save their results into variables. Defining variables of the right type often facilitates resolving such issues.
Stream<Supplier<String>> s1 = Stream.of(this::a);
Stream<String> s2 = Stream.generate(this::a);
All credit to #J-Alex and #Holger for their precious comments.

Why is there no Instance-level Stream.concat method in Java?

I know that Stream.concat exists (doc) to concatenate two streams. However, I have run into cases where I need to add "a few more" items to an existing stream, and then continue processing on it. In such a situation, I would have expected to be able to chain together methods like:
getStream(someArg)
.map(Arg::getFoo)
.concat(someOtherStreamOfFoos) // Or append, or...
.map(...)
However, no such instance-level chainable append/concat method exists.
This isn't a question asking for solutions to this problem, or more elegant approaches (although I would of course be grateful for any other viewpoints!). Rather, I'm asking about the design factors that led to this decision. The Stream interface was, I trust, designed by some extremely smart people who are aware of the Principle of Least Astonishment - so, I must assume that their decision to omit this (to me) intuitively-obvious method signifies either that the method is an antipattern, or that it is not possible due to some technical limitation. I'd love to know the reason.
I can give you one reason it wouldn't have worked.
Stream.concat is defined as
static <T> Stream<T> concat(Stream<? extends T> a,
Stream<? extends T> b)
You can concat a Stream<HashMap> and Stream<Map> into a Stream<Map>, or even concat a Stream<HashMap> and a Stream<TreeMap> into a Stream<Map>. To do that with an instance method, you would need to be able to declare a type parameter like <U super T>, which Java doesn't allow.
// It'd look kind of like this, if Java allowed it.
public <U super T> Stream<U> concat(Stream<? extends U> other)
Java only allows upper-bounded type parameters, not lower-bounded.
Concatenating a Stream<Something> and a Stream<SomethingElse> might seem unusual, but type inference often produces type parameters too specific to work with an instance method. For example,
Stream.concat(Stream.of(dog), animalStream)
which would require an explicit type parameter if written as
Stream.<Animal>of(dog).concat(animalStream)
I think it is just missed functionality of Stream API.
Note that RxJava's Observable has method "concatWith" with required functionality, so your question is reasonable:
Observable<String> o1 = ...;
Observable<Integer> o2 = ...;
o1.map(s -> s.length())
.concatWith(o2)
....
Java 8 has another functionality is nice to have is get another Optional if current Optional is empty, like:
Optional.ofNullable(x).orElse(anotherOptional)
What I want to say that this concat you described is possible, just not implemented in the Stream.

Java 8 sort on Class member's property

Class declaration:
class Entity {
String name;
SubEntity subEntity; // subEntity has a method getAmount() which returns int
}
I understand with Java 8 we can sort like:
entities.sort(Comparator.comparing(Entity::name));
But is there a way I can sort it on sub-entities' properties, for eg:
entities.sort(Comparator.comparing(Entity::SubEntity::getAmount()));
P.S: All in for any one-liners.
Not by using a method reference, no - but it's easy to do with a lambda instead:
entities.sort(Comparator.comparing(entity -> entity.getSubEntity().getAmount()));
Fundamentally there's nothing magical about Comparator.comparing - it just accepts a Function<? super T,? extends U> keyExtractor parameter, so you need to work out some way of creating such a function. A method reference is one convenient way of creating a function, but a lambda expression is more flexible one.
Guys gave you good answers. It isn't supposed to be an improvement over their answers. I just want to provide an alternative idea.
entities.sort(Comparator.comparing(((Function<Entity, SubEntity>)Entity::getSubEntity).andThen(SubEntity::getAmount)));
I formed a key extractor by combining two functions Entity::getSubEntity and SubEntity::getAmount with Function#andThen. Both have been written as method references. The cast is required to determine the type of an instance and call andThen on that instance.
You can do that via a lambda as opposed to a method reference:
entities.sort(Comparator.comparing(x -> x.getSubEntity().getAmount())
If you you have indeed an int as you say in your comments, then use :
Comparator.comparingInt(...)

How can I avoid using an interface in java 8?

I just want to know if its possible to avoid the use of an interface in this code
public interface FunctionT<T,R> {
R apply(Integer...args);
}
public static FunctionT sum = (params) -> Arrays.asList(params)
.stream()
.reduce(Integer::sum).get();
The type of a lambda expression in Java is a functional interface. This means that the lambda must be provided with a target type that is a functional interface. This could be yours (FunctionT) or a standard one like java.util.function.Function.
Put another way, function types in Java are nominal, not structural.
(Also, you don't want to blindly call get() on an Optional, you want to use one of the safe methods like orElse() or ifPresent(). Otherwise you lose all the safety of using Optional in the first place.)

Categories

Resources