Reputation: 3532
I have the following structure
public interface ICommon{
ICommon add(ICommon other);
}
public class Foo implements ICommon{
...
ICommon add(ICommon other){
return new Bar().add(other);
}
}
public class Bar implements ICommon{
...
ICommon add(ICommon other){
...
}
}
As part of a composite pattern.
I wanted to use the streams reduce operation, but somehow I can not force the type inference to the interface. I am using this.
List<Foo> list;
list.stream().reduce( new Foo(), (a,b) -> a.add(b));
I am getting an error that ICommon
can not be cast to Foo
.
I have tried to force cast on parameters but with no success.
Upvotes: 2
Views: 253
Reputation: 298123
There is the three-arg version of reduce
allowing to change the element type when performing the reduction:
list.stream().reduce(new Foo(), ICommon::add, ICommon::add);
While a reference to the same method is used here, the second argument is a function (BiFunction
) with an (ICommon,Foo) -> ICommon
signature, whilst the third argument is a function (BinaryOperator
) with an (ICommon,ICommon) -> ICommon
signature.
Another option is to do a type safe change of the existing List
’s type:
Collections.<ICommon>unmodifiableList(list).stream().reduce(new Foo(), ICommon::add);
Since immutable lists can guaranty to return values of the super type of the actual element type, while preventing the inserting of new elements, this wrapper allows to change the element type to a super type. Further, since stream operations are read-only operations, the wrapper redirects the stream()
invocation to the original list, just returning it as a stream of the supertype. So there is no performance difference to using list.stream()
directly.
Upvotes: 1
Reputation: 48404
The problem here is that your List
is parametrized with Foo
, but your reduction operations will be parametrized with ICommon
due to the add
invocation.
While all Foo
s are ICommon
s, not all ICommon
s will be Foo
s.
The easiest way for you would be to parametrize your List
with ICommon
instead, without changing anything else in your (visible) code.
Something like:
List<ICommon> list = [some list of Foos];
list.stream().reduce( new Foo(), (a,b) -> a.add(b));
Upvotes: 4
Reputation: 3532
Found the solution to the problem. The reduce operation has the signature
T reduce(T identity, BinaryOperator<T> accumulator);
All I had to do is cast to a stream of ICommon
list.stream().map(x-> (ICommon) x).reduce( new Foo(), (a,b) -> a.add(b));
Upvotes: 1