質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.34%

総称型を、別の総称型に変換するメソッドのコンパイルエラーを解消したい

受付中

回答 1

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 3,116

score 12

前提・実現したいこと

ここに質問したいことを詳細に書いてください

下記のようなOrgクラスを、インターフェースと実装クラスに分割したいと考えております。
ここで、IBar::mapメソッドに問題を抱えています。

    /**
     * オリジナルのクラス。
     * これを、下記のインターフェースと実装クラスに分割したい。
     */
    public static class Org<E>
    extends java.util.ArrayList<E> {

        /**
         * Foo<E>を、Foo<O>に変換する。
         */
        public <O> Org<O> map(final Function<E,O> mapper) {
            return
                super
                    .stream()
                    .map(mapper)
                    .collect(Collectors.toCollection(Org::new));
        }

        /**
         * Bar<E>の要素をフィルターする。
         * ※質問の趣旨とは直接関係なし
         */
        public Org<E> filter(final Predicate<E> filter) {
            /* ロジックを簡略 */
            return this;
        }

        /**
         * Bar<E>の重複する要素を削除する。
         * ※質問の趣旨とは直接関係なし
         */
        public <K> Org<E> distinct(final Function<E,K> keySelector) {
            /* ロジックを簡略 */
            return this;
        }

        /**
         * Bar<E>の要素を昇順に並べる。
         * ※質問の趣旨とは直接関係なし
         */
        public Org<E> orderBy(final Function<E, Integer> keySelector) {
            /* ロジックを簡略 */
            return this;
        }

    }
    /**
     * インターフェース
     */
    public interface IBar<E, L extends IBar<E, L>>
    extends java.util.List<E>{

        /**
         * Bar<E>をBar<O>に変換する。
         */
        default
        <O, OL extends IBar<O, OL>>
        OL map(final Function<E,O> mapper){
            try {
                Constructor<OL> con = (Constructor<OL>) this.getClass().getConstructor();
                OL ol = con.newInstance();

                this.stream().map(mapper).forEach(value -> ol.add(value));

                return ol;
            }
            catch (Exception e) {
                return null;
            }
        }

        /**
         * Bar<E>の要素をフィルターする。
         * ※質問の趣旨とは直接関係なし
         */
        default L filter(final Predicate<E> filter) {
            /* ロジックを簡略 */
            return (L) this;
        }

        /**
         * Bar<E>の重複する要素を削除する。
         * ※質問の趣旨とは直接関係なし
         */
        default <K> L distinct(final Function<E,K> keySelector) {
            /* ロジックを簡略 */
            return (L) this;
        }

        /**
         * Bar<E>の要素を昇順に並べる。
         * ※質問の趣旨とは直接関係なし
         */
        default L orderBy(final Function<E, Integer> keySelector) {
            /* ロジックを簡略 */
            return (L) this;
        }

    }

    /**
     * IBar実装クラス。
     */
    public static class Bar<E>
    extends java.util.ArrayList<E>
    implements IBar<E, Bar<E>> {
        /**
         * ここには何も書きたくない
         */
    }

    /**
     * IBar実装クラス。
     */
    public static class Foo<E>
    extends java.util.LinkedList<E>
    implements IBar<E, Foo<E>> {
        /**
         * ここには何も書きたくない
         */
    }

発生している問題・エラーメッセージ

型の不一致: IBar<Object,IBar<Object,OL>> から Foo<Foo<Integer>> には変換できません

該当のソースコード

    public static void main(final String[] args) {
        try {
            // (1)このケースは問題なく動作する。
            Bar<String> strBar = new Bar<>(...);
            Bar<Integer> intBar = strBar.map(item -> item.length());

            // (2)このケースはコンパイルエラー
            Foo<Foo<String>> strFooFoo = new Foo<>(...);
            Foo<Foo<Integer>> intFooFoo = strFooFoo.map(bar -> bar.map(item -> item.length())); /* 型の不一致! */

            // (3)このケースは問題なく動作するが、こんな書き方をさせたくない
            Foo<Foo<String>> strFooFoo2 = new Foo<>(...);
            Foo<Foo<Integer>> intFooFoo2 = strFooFoo2.<Foo<Integer>, Foo<Foo<Integer>>>map(foo -> foo.<Integer, Foo<Integer>>map(item -> item.length()));

            // (4)オリジナルのクラスでも、問題なく動作する。
            Org<Org<String>> strOrgOrg = new Org<>(...);
            Org<Org<Integer>> intOrgOrg = strOrgOrg.map(org -> org.map(item -> item.length()));

        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

イメージ説明

ご質問

「型の不一致」エラーが出ている(2)について、
ソースコード側ではなく、IBarインターフェース側に何らかの手を加えて、コンパイルエラーを解消できないでしょか?

補足情報(言語/FW/ツール等のバージョンなど)

言語:Java8(JDK1.8)
IDE:Eclipse 4.5
実行環境:Windows 10

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • swordone

    2017/05/25 09:34

    IBarのジェネリクスのLってどこかで使ってるんですか?

    キャンセル

  • crescendocres

    2017/05/25 10:33

    はい、IBar別メソッドの戻り値の型として利用しています。 質問文に、そのインターフェースを追記しました。(質問の趣旨とは異なる例ですが…)

    キャンセル

回答 1

+1

訂正とお詫び:本件、自分はIntelliJ IDEA & Javacでビルドできたことをもって以下の回答をしましたが、eclipse 4.5.2でコンパイルエラーになることを確認しました。質問者さんに失礼な回答をしてしまった点、訂正してお詫びいたします。

以下、元の回答です

質問が成立していないような気がします。

最初に挙げておられたコードは単にthrows句のシグナチャーの問題でコンパイルエラーになっていただけですが、回答しようとしたらコードが編集されていました・・・

編集後の実装では(2)はコンパイルエラーにならないのですが・・・


なんとなくですが、明示されていない部分の文法(or 意味)エラーに引きずられてエラーが起こっているだけではないかと推測します。

自分は以下のコードで試してみましたがコンパイルエラーにはなりません。

import java.lang.reflect.Constructor;
import java.util.function.Function;

public class Test1 {
  public interface IBar<E, L extends IBar<E, L>>
    extends java.util.List<E>{
    default
    <O, OL extends IBar<O, OL>>
    OL map(final Function<E,O> mapper){
      try {
        Constructor<OL> con = (Constructor<OL>) this.getClass().getConstructor();
        OL ol = con.newInstance();

        this.stream().map(mapper).forEach(value -> ol.add(value));

        return ol;
      }
      catch (Exception e) {
        return null;
      }
    }
  }

  public static class Bar<E>
    extends java.util.ArrayList<E>
    implements IBar<E, Bar<E>> {
  }

  public static class Foo<E>
    extends java.util.LinkedList<E>
    implements IBar<E, Foo<E>> {
  }

  public static void main(final String[] args) {
    // (1)このケースは問題なく動作する。
    Bar<String> strBar = new Bar<>();
    Bar<Integer> intBar = strBar.map(item -> item.length());

    // (2)このケースは問題ない。
    Foo<Foo<String>> strFooFoo = new Foo<>();
    Foo<Foo<Integer>> intFooFoo = strFooFoo.map(bar -> bar.map(item -> item.length()));

    // (3)このケースはIDE(IntelliJ IDEA)に「型引数の明示は冗長」と警告されます
    Foo<Foo<String>> strFooFoo2 = new Foo<>();
    Foo<Foo<Integer>> intFooFoo2 = strFooFoo2.<Foo<Integer>, Foo<Foo<Integer>>>map(foo -> foo.<Integer, Foo<Integer>>map(item -> item.length()));
  }
}

なお、コードの編集が中途半端です。最初のコードにあったmapメソッドのthrows句を取ったのですからmainメソッドのtry-catchに意味がありません。
また、本件とは関係ありませんがmapメソッドでチェック例外を握りつぶしnullをreturnしているのはいただけません。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/05/24 23:01

    こんなコードを書くかどうかはさて置き、特にエラーにはなりませんねぇ。 いちおう Intellij IDEA(2017.1)と Eclipse (4.6.3)で試した。
    何か設定があるのかも知れんけど、もう Eclipse の使い方を忘れた。

    キャンセル

  • 2017/05/24 23:43

    先ほどのエラーの話は前のPCでの話でした。
    今入れているEclipse4.6.2ではエラーになりませんでした。

    キャンセル

  • 2017/05/25 09:11 編集

    皆様、検証していただいたうえで、ご回答ありがとうございます。

    残念ながら、客先を含めた開発環境要件がEclipse 4.5.2で固まってしまっています。

    ご質問に挙げたクラス(Org)は、ライブラリ(Jar)として提供しているものですが、それを利用している既存コードがコンパイルされる環境はEclipse4.5.2ですので、私の端末でのみEclipseのバージョンを上げたとしても、問題は解消されない見込みです。

    ご質問に挙げたクラス(IBar、Bar、Foo等)、またはプロジェクト固有設定をどうにかする方法を考えてみます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.34%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る