java8 intfunction,为什么Java 8的ToIntFunction< T>扩展函数< T,整数>

If I wrote the ToIntFunction interface, i'd want to encode in the interface the fact that it's just a function that returns a primitive int, like this:

@FunctionalInterface

public interface ToIntFunction extends Function {

int applyAsInt(T value);

@Override

default Integer apply(T value) {

return Integer.valueOf(applyAsInt(value));

}

}

I was wondering, is there a compelling reason Java 8 API designers chose to keep the primitive alternatives completely separate from Function? Is there some evidence that they considered doing so and decided against it? I guess similar question goes for at least some of the other 'special' functional interfaces like Consumer (could be Function) and Supplier (Function).

I haven't thought very deeply and thoroughly about all the ramifications of this, so I'm probably missing something.

If ToIntFunction (and the other primitive generic functional interfaces) had this relation with Function, it would allow one to use it in place where Function parameter is expected (what comes to mind is composition with other functions, e.g. calling myFunction.compose(myIntFunction) or to avoid writing several specialized functions in an API when such auto(un)boxing implementation as described above would be sufficient).

This is very similar to this question: Why doesn't Java 8's Predicate extend Function but I've realized that the answer might be different for semantic reasons. Therefore i'm reformulating the question for this case of a simple primitive alternative to Function, where there can't be any semantics, just primitive vs. wrapped types and even possibility of the null wrapped object is eliminated.

解决方案

The interface explosion in the JDK 8 is the product of one small problem in Java: the lack of value types.

This implies that we cannot use primitive types with generics, and therefore, we are forced to use wrapper types.

In other words, this is not possible:

Function myFunction;

But this is:

Function myFunction;

The problem with this is boxing/unboxing. This can become expensive and make algorithms dealing with primitive data types difficult to optimize due to the constant need of creating wrapper objects for the primitive values and vice versa.

This explains why there is an explosion of interfaces in the JDK 8, like Function and IntFunction, the latter using primitive types as arguments.

This was discussed at some point in the Lambda Mailing List revealing that the expert group was struggling with this.

Brian Goetz, spec leader of the lambda project, wrote there:

More generally: the philosophy behind having specialized primitive

streams (e.g., IntStream) is fraught with nasty tradeoffs. On the one

hand, it's lots of ugly code duplication, interface pollution, etc.

On the other hand, any kind of arithmetic on boxed ops sucks, and

having no story for reducing over ints would be terrible. So we're

in a tough corner, and we're trying to not make it worse.

Trick #1 for not making it worse is: we're not doing all eight

primitive types. We're doing int, long, and double; all the others

could be simulated by these. Arguably we could get rid of int too,

but we don't think most Java developers are ready for that. Yes,

there will be calls for Character, and the answer is "stick it in an

int." (Each specialization is projected to ~100K to the JRE

footprint.)

Trick #2 is: we're using primitive streams to expose things that are

best done in the primitive domain (sorting, reduction) but not trying

to duplicate everything you can do in the boxed domain. For example,

there's no IntStream.into(), as Aleksey points out. (If there were,

the next question(s) would be "Where is IntCollection? IntArrayList?

IntConcurrentSkipListMap?) The intention is many streams may start as

reference streams and end up as primitive streams, but not vice versa.

That's OK, and that reduces the number of conversions needed (e.g., no

overload of map for int -> T, no specialization of Function for int ->

T, etc.)

Probably, in the future (maybe JDK 9) when we get Support for Value Types in Java, we will be able to get rid of (or at least no longer need to use anymore) these interfaces.

The expert group struggled with several design issues, not just this. The need, requirement or constraint to keep backwards compatibility made things difficult, then we have other important conditions like the lack of value types, type erasure and checked exceptions. If Java had the first and lacked of the other two the design of JDK 8 would have been very different. So, we all must understand that it was a difficult problem with lots of tradeoffs and the EG had to draw a line somewhere and make a decision.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值