亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

包裝一個互逆的功能接口而不會失去通用性

包裝一個互逆的功能接口而不會失去通用性

DIEA 2021-05-14 22:13:11
我有一些具有這種一般結構的代碼:interface Func<A> {    double apply(Optional<A> a);}class Foo {    public double compute(Func<Double> f) {        // Sometimes amend the function to do something slightly different        Func<Double> g = f;        if (someCondition())            g = oa -> Math.max(0, f.apply(oa));        return g.apply(Optional.of(3.14)) + g.apply(Optional.empty());    }}就其本身而言,這已經足夠好了。現在,我想更加自由一些,這樣,如果有人擁有aFunc<Number>或Func<Object>代替a的話,Func<Double>他們仍然可以將其傳遞給compute。先驗的這應該是足夠安全的。很好,所以我將其更改為    public double compute(Func<? super Double> f) {        Func<? super Double> g = f;        if (someCondition())            g = oa -> Math.max(0, f.apply(oa));        ...不幸的是,現在lambda不會進行類型檢查(例如Eclipse),因為oa無法將類型傳遞給f.apply。f本身的賦值g似乎并不使編譯器感到擔心,并且如果to的參數apply為A而不是,也不會出現問題Optional<A>。不幸的是,似乎沒有成為一個方式來命名的? super Double參數類型,所以我可以再次使用它的類型g和/或用老式的內部類更換拉姆達。例如,在語法上甚至不允許這樣做:    public <T super Double> double compute(Func<T> f) {        Func<T> g = f;        ...有什么合理的優雅方法可以完成這項工作嗎?到目前為止,我想出的最好的方法是    public double compute(Func<? super Double> f) {        if (someCondition())            return computeInner(oa -> Math.max(0, f.apply(oa)));        else            return computeInner(f);    }    private double computeInner(Func<? super Double> g) {        return g.apply(Optional.of(3.14)) + g.apply(Optional.empty());    }編譯器接受了這一點,但是除了使類型檢查器滿意之外,間接調用實際上并不是我所說的“優雅”。
查看完整描述

3 回答

?
慕田峪7331174

TA貢獻1828條經驗 獲得超13個贊

試試這個奇怪的把戲:

g = oa -> Math.max(0, f.apply(oa.map(a -> a)));
                     // ^----------^

像這樣映射可選類型的類型,可使編譯器將“可選”的類型“轉換”為一致的類型。

Ideone demo

這確實存在創建新Optional實例的缺點。


但是,當然,我問了一個問題,它在思考這是否實際上是規范所允許的東西或錯誤。


就個人而言,我認為您的“迄今為止最好的”并不特別糟糕。當然,這取決于實際代碼的外觀。


查看完整回答
反對 回復 2021-05-26
?
翻閱古今

TA貢獻1780條經驗 獲得超5個贊

總的來說,我發現Java中超界的類型推斷是一個噩夢。.有很多編譯器錯誤,通常很難推理為什么編譯器會拒絕某種語法而不拒絕其他語法。


就是說,您可以通過強制轉換f為Func<Double>類型來解決這種問題。這并不是完全安全的方法。如果f具有任何狀態,我們可以假設其下限f是Double在現實中可能是Number或Object。使用強制轉換,您不會招致@AndyTurner提供的解決方案的性能損失,但是未經檢查的強制轉換也不是您的朋友。


public double compute(Func<? super Double> f) {

    // Sometimes amend the function to do something slightly different

    Func<? super Double> g = f;

    if (someCondition())

        g = oa -> Math.max(0, (((Func<Double>) f)).apply(oa));


    return g.apply(Optional.of(3.14)) + g.apply(Optional.empty());

}

總而言之,我認為您在問題中提出的解決方案是解決該問題的最佳解決方案。它有些冗長,但是編譯器應該能夠優化代碼。您不會因未經檢查的強制轉換而失去編譯時的安全性,并且不會由于創建其他Optional實例而導致運行時性能下降。


查看完整回答
反對 回復 2021-05-26
?
四季花海

TA貢獻1811條經驗 獲得超5個贊

解決方案是更改您的接口簽名:

double apply(Optional<? extends A> a);

分析

考慮一下您的界面是否僅僅是:

double apply(A a);

這樣就永遠不會發生錯誤。

這是因為Double可分配給Object。編譯器將自動調整類型。這意味著該接口實際上是:

double apply(? extends A a);

因此,您需要做的就是讓您的界面具有這種適應能力。

func(Number)可以接受Double作為參數。

func(Optional<Number>)也應該接受Optional<Double>

因此,您應該? extends在您的界面上添加。


查看完整回答
反對 回復 2021-05-26
  • 3 回答
  • 0 關注
  • 124 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號