Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Better way to create a stream of functions?

I wish to do lazy evaluation on a list of functions I've defined as follows;

Optional<Output> output = Stream.<Function<Input, Optional<Output>>> of(
                    classA::eval, classB::eval, classC::eval)
            .map(f -> f.apply(input))
            .filter(Optional::isPresent)
            .map(Optional::get)
            .findFirst();

where as you see, each class (a, b & c) has an Optional<Output> eval(Input in) method defined. If I try to do

Stream.of(...)....

ignoring explicit type, it gives

T is not a functional interface

compilation error. Not accepting functional interface type for T generic type in .of(T... values)


Is there a snappier way of creating a stream of these functions? I hate to explicitly define of method with Function and its in-out types. Wouldn't it work in a more generic manner?

This issue stems from the topic of the following question;
Lambda Expression and generic method

like image 321
buræquete Avatar asked Dec 17 '17 08:12

buræquete


People also ask

How many ways we can create streams in Java?

Create a stream from Collection The Java Collection framework provides two methods, stream() and parallelStream() , to create a sequential and parallel stream from any collection, respectively.

Which class helps in creating a stream from a topic?

The Kafka Streams application consists of a single Java Class that creates a stream from the Kafka Topic.

What are the methods of stream API?

Stream of Primitives. Java 8 offers the possibility to create streams out of three primitive types: int, long and double. As Stream<T> is a generic interface, and there is no way to use primitives as a type parameter with generics, three new special interfaces were created: IntStream, LongStream, DoubleStream.

How to create a stream with the specified T values?

Stream.of (T…t) method can be used to create a stream with the specified t values, where t are the elements. This method returns a sequential Stream containing the t elements. Below is the implementation of the above approach:

What is the use of stream in Java?

The Stream API, introduced in Java 8, it is used to process collections of objects. Stream is a sequence of objects, that supports many different methods which can be pipe lined to produce the desired result.

How do you streamline processes and workflows?

Streamlining processes and workflows may take some time and is best completed in small steps that contribute to your organization’s improved efficiency goals. Businesses may streamline processes by reviewing the details of how they manage their individual challenges.

What is the difference between the builder () and iterate () methods of stream?

The builder () method is used when the desired type should be additionally specified in the right part of the statement, otherwise the build () method will create an instance of the Stream. The iterate () method returns an infinite sequential ordered Stream produced by iterative application of a function f to an initial element seed.


2 Answers

You can break it into two lines:

Stream<Function<Input, Optional<Output>>> stream = Stream
          .of(classA::eval, classB::eval, classC::eval);
Optional<Output> out = stream.map(f -> f.apply(input))
          .filter(Optional::isPresent)
          .map(Optional::get)
          .findFirst();

or use casting:

Optional<Output> out = Stream.of(
                (<Function<Input, Optional<Output>>>)classA::eval, 
                classB::eval, 
                classC::eval)
        .map(f -> f.apply(input))
        .filter(Optional::isPresent)
        .map(Optional::get)
        .findFirst();

but I don't think you can avoid specifying the type of the Stream element - Function<Input, Optional<Output>> - somewhere, since otherwise the compiler can't infer it from the method references.

like image 131
Eran Avatar answered Oct 18 '22 05:10

Eran


There is a way that allows to omit the Function<Input, Optional<Output>> type, but it’s not necessarily an improvement

Optional<Output> o =
        Stream.concat(Stream.of(input).map(classA::eval),
                Stream.concat(Stream.of(input).map(classB::eval),
                              Stream.of(input).map(classC::eval)))
                .filter(Optional::isPresent)
                .map(Optional::get)
                .findFirst();

and it doesn’t scale.

It seems, the best option is to wait for Java-9 where you can use

Optional<Output> o = classA.eval(input)
           .or(() -> classB.eval(input))
           .or(() -> classC.eval(input));
like image 37
Holger Avatar answered Oct 18 '22 03:10

Holger