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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

2回答

544閲覧

javaで関数を包む?関数を引数に取りたい?

ABC-..

総合スコア1

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

1クリップ

投稿2022/02/22 15:25

編集2022/02/23 02:17

java

1while (true) { 2 try { 3 func(arg1, arg2); 4 break; 5 catch (error e) { 6 // 解決したあとに、もう一度関数を叩いてほしい。 7 // 例外処理の内容は全て同じ。 8 // 何回か失敗する事もある。 9 continue; 10 } 11}

このfuncを包んでいる処理を他の関数でもやりたく、いい感じな書き方を知りたいです(その都度whileを書くのを避けたい)。
引数、戻り値は同じではなく、関数ごとに異なります。

フェーズのようなenumを作って、全体を包んでflagのような感じで、、みたいなのは思いつきましたが。。

java

1enum Phase { 2 FIRST, 3 SECOND, 4 THIRD; 5} 6 7var flag = Phase.FIRST; 8while (true) { 9 try { 10 if (flag == Phase.FIRST) { 11 func1(); 12 flag = Phase.SECOND; 13 } 14 if (flag == Phase.SECOND) { 15 func2(arg); 16 flag = Phase.THIRD; 17 } 18 19 // ... 20 21 break; 22 } catch (error e) { 23 // 処理 24 continue; 25 } 26}

pythonだったら以下のような解決策が思い浮かびます。

python

1def execute(func, *args, **kwargs): 2 while True: 3 try: 4 return func(*args, **kwargs) 5 except Exception: 6 # 解決する 7 input("enter") 8 continue 9 10def api(): 11 # 例外が発生する可能性がある処理 12 pass 13 14execute(api) 15execute(api2, arg1, arg2) 16# ...

これは関数自体を引数にすることができ、可変長引数が柔軟である必要があります。

どのように検索したら良いのか分からなく、皆様のお知恵を拝借したいです。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jimbe

2022/02/22 18:29

python でのコードを書いて頂いて、それを java でするにはどうしたら良いか? という感じにすると具体的で分かり易いと思うのですが、如何でしょうか。
xebme

2022/02/22 22:58

Java標準の関数型インターフェイスは例外を投げられないので、自分で例外を投げる関数型インターフェースを定義するか、Optionalを使ってorElseGetで再試行するなどの方針が考えられます。再試行の無限ループも考えてみたいところです。 プログラムを具体化しなければなりません。jimbeさんのおっしゃるように pythonのコードを提示していただくのが近道かなと思います。
ABC-..

2022/02/23 02:08

コメントありがとうございます。 pythonのコードを追加しました。 javaで実現するにはどうするかなのですが、調べてみて、javaで関数を引数に取るには引数、戻り値の型が同じである必要があるようです(引数、戻り値は関数ごとに違う)。 なので難しいですかね… >再試行の無限ループも考えてみたいところです。 ここの例外は人が解決するので無限ループは考慮しなくて大丈夫です。 リミットなども設ける予定です。
guest

回答2

0

すでに解決済みですがメモを残しておきます。やっていることはpythonと変わりません。

Java

1@FunctionalInterface 2public interface BiFunction<T,U,V> { 3 4 V apply(T x, U y) throws Exception; 5 6 static <T,U,V> Optional<V> execute(BiFunction<T,U,V> f, T x, U y) { 7 Optional<V> result = Optional.empty(); 8 for (int i = 0; i < 3; ++i) { 9 try { 10 V value = f.apply(x, y); 11 result = Optional.of(value); 12 break; 13 } catch (Exception e) { 14 //e.printStackTrace(); 15 } 16 } 17 return result; 18 } 19 20}

利用例です。

Java

1public class BiFunctionUsage { 2 3 public static void main(String[] args) { 4 5 var a = BiFunction.execute((x, y) -> x * y, 2.5, 5.8); 6 System.out.println(a.orElse(null)); 7 8 var b = BiFunction.execute((x, y) -> {if (y == 0) throw new Exception("Divide by Zero."); else return x/y;}, 2.5, 0); 9 System.out.println(b.orElse(null)); 10 11 var c = BiFunction.execute((x, y) -> x + y, "5 + 6 = ", (5+6) ); 12 System.out.println(c.orElse(null)); 13 14 } 15 16}

関数型インターフェイスから例外を投げるのは推奨されていません。例外を投げるとStreamのパイプライン処理が中断してしまうから、純粋関数にならないから、といった理由が挙げられています。

しかし、SQLExceptionのように、トランザクションをロールバックする目的で投げざるをえないことがあります。やむをえない場合を除いて、例外の代わりにOptionalを使ってください。

投稿2022/02/24 10:07

xebme

総合スコア1081

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ABC-..

2022/02/24 10:47

このようなインターフェースもあるのですね。 回答ありがとうございます。
guest

0

ベストアンサー

垢抜けない感じですが^^;

java

1public class Main { 2 public static void main(String[] args) { 3 int a1 = execute(new Api1()); 4 String a2 = execute(new Api2(100, "ABC")); 5 System.out.println("a1="+a1+", a2="+a2); 6 } 7 8 static <T> T execute(Func<T> func) { 9 while(true) { 10 try { 11 return func.exec(); 12 } catch(Func.Exception e) { 13 //input("enter") 14 } 15 } 16 } 17} 18 19abstract class Func<T> { 20 static class Exception extends Throwable {} 21 abstract T exec() throws Func.Exception; 22} 23 24class Api1 extends Func<Integer> { 25 public Integer exec() throws Func.Exception { 26 System.out.println("api1 の処理"); 27 return -123; 28 } 29} 30class Api2 extends Func<String> { 31 final int arg1; 32 final String arg2; 33 Api2(int arg1, String arg2) { 34 this.arg1 = arg1; 35 this.arg2 = arg2; 36 } 37 public String exec() throws Func.Exception { 38 System.out.println("api2 の処理 (arg1="+arg1+",arg2='"+arg2+"')"); 39 return "XYZ"; 40 } 41}

plain

1api1 の処理 2api2 の処理 (arg1=100,arg2='ABC') 3a1=-123, a2=XYZ

リトライ自体を Func に入れてしまって main は例外時の処理を渡す形にも出来ます。

java

1public class Main { 2 public static void main(String[] args) { 3 Func.Retry retry = (e) -> { 4 //input("enter") 5 }; 6 int a1 = new Api1().executeWithRetry(retry); 7 String a2 = new Api2(100, "ABC").executeWithRetry(retry); 8 System.out.println("a1="+a1+", a2="+a2); 9 } 10} 11 12abstract class Func<T> { 13 static class Exception extends Throwable {} 14 interface Retry { 15 void onRetry(Exception cause); 16 } 17 T executeWithRetry(Retry retry) { 18 while(true) { 19 try { 20 return exec(); 21 } catch(Func.Exception e) { 22 if(retry != null) retry.onRetry(e); 23 } 24 } 25 } 26 abstract T exec() throws Func.Exception; 27}

投稿2022/02/23 04:44

編集2022/02/23 06:37
jimbe

総合スコア12632

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

xebme

2022/02/23 10:02

例外を投げる関数型インターフェイスはアノテーションをつけてください。次のように書くと、例外が発生するラムダ式を引数として渡せるようになります。 import java.sql.SQLException; @FunctionalInterface public interface SQLFunction<T, U> { U apply(T in) throws SQLException; }
jimbe

2022/02/23 10:28

Func<T> は interface で良かったですね。ありがとうございます。
ABC-..

2022/02/23 13:30

なるほど。。 その関数専用のRunnableのような物を作って~という感じですよね。 勉強になりました。 回答ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問