62270


自身で定義したメソッドを別のメソッドに引数として渡す方法についてご教示いただきたいです。  
例えばBookServiceのgetBookメソッドに、呼び出し元のクラスで定義したfallbackメソッドを渡し、getBookメソッドの中で実行する方法はないでしょうか。  
よろしくお願いいたします。

追記：  
情報が欠落していましたので、追記させていだきます。  
fallbackメソッドは引数無し、戻り値として空のbookオブジェクトを返却する仕様を考えています。


CC BY-SA 4.0
2020-01-15T14:48:01.313
62269
2020-01-16T06:18:05.810
2020-01-16T00:46:22.050
37470
37470
question
java
メソッドにメソッドを渡す方法について教えてください


  1. fallbackメソッドを持つFooBase抽象クラスを定義します
  2. getBookの引数は、FooBase抽象クラスにします
  3. getBookの中で、fooBase.fallbackメソッドを呼びます。
  4. FooBaseを継承したSubFooクラスを作り、SubFoo.fallbackをオーバーライドして任意の処理を書きます

・FooBase抽象クラスより、Fooインターフェースのほうがいいかもしれません。  
・Javaには匿名クラスの文法があるので、SubFooクラスを定義することなく直接getBookに匿名クラスを渡すこともできます。


CC BY-SA 4.0
2020-01-15T15:13:24.123
62270
2020-01-15T15:13:24.123
25396
62269
answer


Java 8以降であれば、メソッド参照が使えるので、ご質問に書かれたような動作を比較的「直接」記述することができます。

### BookServiceのgetBookメソッド

[code]

    public class BookService {
    
        public BookService() {
            //...
        }
    
        public void getBook(Runnable callback) {
            //...
            //`callback`を呼び出す
            callback.run();
            //...
        }
    
    }
    
[/code]

`callback`が引数を取るかどうか、戻り値を返すかどうかで`Runnable`なんかの型や呼び出し方(`get()`だったり`apply(...)`だったり)も変えないといけませんが、特にご記載はないので、ここでは引数も戻り値も無しにしています。

### 呼び出し側

[code]

    public class CallbackSample {
    
        public static void main(String[] args) {
            BookService service = new BookService();
            service.getBook(CallbackSample::fallback); //<-fallbackメソッドのメソッド参照を渡す
        }
    
        public static void fallback() {
            System.out.println("fallback called");
            //...
        }
    }
    
[/code]


CC BY-SA 4.0
2020-01-15T21:22:10.113
62277
2020-01-15T21:22:10.113
13972
62269
answer


キーワードとしては[関数型インタフェース](https://docs.oracle.com/javase/jp/8/docs/api/java/util/function/package-
summary.html)(functional interface)になるかと思います。

[code]

    import java.util.Optional;
    import java.util.function.Supplier;
    
    public class BookService {
    
        public static void main(final String[] args) {
            final BookService service = new BookService();
    
            // fallback処理の定義(ここではBookインスタンス生成)
            final Supplier<Book> fallback = Book::new;
    
            service.getBook(100, fallback);
        }
    
        public Book getBook(final long id, final Supplier<Book> fallback) {
            // IDで検索してみて存在しなければ fallback実行、みたいな想定
            return findById(id).orElseGet(fallback);
        }
    
        private Optional<Book> findById(final long id) {
            // ...
        }
    }
    
    class Book {
    }
    
[/code]

質問文中の

> getBookメソッドに、呼び出し元のクラスで定義したfallbackメソッドを渡し、getBookメソッドの中で実行する

に該当するのが

[code]

    public Book getBook(final long id, final Supplier<Book> fallback) {
        // IDで検索してみて存在しなければ fallback実行、みたいな想定
        return findById(id).orElseGet(fallback);
    }
    
[/code]

> fallbackメソッドは引数無し、戻り値として空のbookオブジェクトを返却する

に該当するのが

[code]

        // fallback処理の定義(ここではBookインスタンス生成)
        final Supplier<Book> fallback = Book::new;
    
[/code]

になります。

上の例ははメソッド参照([method
references](https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html))を使っていますが、「空のbookオブジェクト」生成が単に
`new` するだけでないとすると、次のように書くことになります:

[code]

        final Supplier<Book> fallback = () -> {
            final Book book = new Book();
            // 何かいろいろ初期処理を実行
            // ...
            return book;
        };
    
[/code]

(ラムダ式([lambda
expressions](https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html))の利用)  
あるいは

[code]

        final Supplier<Book> fallback = new Supplier<>() {
            @Override
            public Book get() {
                final Book book = new Book();
                // 何かいろいろ初期処理を実行
                // ...
                return book;
            }
        };
    
[/code]

(匿名クラス([anonymous
classes](https://docs.oracle.com/javase/tutorial/java/javaOO/anonymousclasses.html))の利用)


CC BY-SA 4.0
2020-01-16T06:07:43.197
62283
2020-01-16T06:18:05.810
2020-01-16T06:18:05.810
2808
2808
62269
answer