20200526のJavaに関する記事は15件です。

Javaで直和型を使ってプログラミングする(ネタ)

(Javaよくわかっていないですが)デフォルトで直和型をサポートしていて良いと思いました。直和型を使う勉強を兼ねて、「逆ポーランド記法の式(1 2 + = 3 みたいな)を計算するインタープリター」を作ってみました。

今回書いたコード

package neta;

import java.util.Stack;

public class Main {
    // 数値型をあらわす型
    static class IntType extends Exception {
        int v;
        IntType(int v) {
            this.v = v;
        }

        @Override
        public String toString() {
            return Integer.toString(v);
        }
    }

    // プラス演算をあらわす型
    static class PlusOperation extends Exception {
        @Override
        public String toString() {
            return "+";
        }
    }

    private static void eval(String statement) throws IntType, PlusOperation {
        try {
            throw new IntType(Integer.parseInt(statement));
        } catch (NumberFormatException e) {
            if (statement.equals("+")) {
                throw new PlusOperation();
            } else {
                // Stackを使って逆ポーランド記法の計算をします
                Stack<Integer> stack = new Stack<>();
                // トークンは空白区切りであたえます
                for (String s : statement.split(" ")) {
                    try {
                        eval(s);
                    } catch (IntType iv) {
                        stack.push(iv.v);
                    } catch (PlusOperation op) {
                        stack.push(stack.pop() + stack.pop());
                    }
                }
                throw new IntType(stack.pop());
            }
        }
    }

    private static void test(String statement) {
        try {
            eval(statement);
        } catch (IntType | PlusOperation e) {
            System.out.println(e);
        }
    }

    public static void main(String[] args) {
        test("1");
        test("1 2 +");
        test("3 4 + 5 +");
        test("6 7 8 + +");
        test("+");
    }
}

このプログラムを実行すると下記の出力となります:

1
3
12
21
+

解説

戻り値の型

戻り値の型をあらわすには関数定義で throws キーワードを使うようです。

// 例
void eval(String statement) throws IntType, PlusOperation

今回の例では IntTypePlusOperation の直和型を eval() 関数の戻り値型としています。
最近のプログラミング言語(Go/Rust/..)のように、関数名の後に戻り値型を書くようでクールです。
関数であることをあらわすキーワードが void なのはちょっとよくわからないですが、文法的には最近の言語の流れを汲んでいるんじゃないかな、と思います。

値を返す

値を返す際には throw キーワードを使うようです。多くのプログラミング言語では return みたいなキーワードを使うと思うのですがめずらしいですね。

// 例: 数値型を返す
throw new IntType(Integer.parseInt(statement));

// 例: 足し算の演算子を返す
throw new PlusOperation();

値を返すときには、 IntType のような extends Exception したクラスのインスタンスにしないとコンパイルエラーになることに注意が必要です。若干手間ですね。

型に応じた処理

型に応じて条件分岐するには try/catch を使います。Scalaや最近の言語のmatch/caseみたいですね。

try {
    eval(s);
} catch (IntType iv) {
    // 型に応じた処理
} catch (PlusOperation op) {
    // 型に応じた処理
}

歴史のある言語だとビジターパターンというものを使ったり、instanceof みたいなもので型を調べて分岐させたりするらしいです。

エラー

Go言語のように、返されたエラーをチェックしないとコンパイルエラーになるようです。

try {
    throw new IntType(Integer.parseInt(statement));
} catch (NumberFormatException e) {
    // エラー型の値が返された場合の処理
}

上記では正常系の処理を一気に書けて、いちいち戻り値のエラーチェックをしないで済むのでモナドのようでもありますね。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

null かもしれない配列をストリームに変換する

毎回ちょっと悩むので備忘録として書いておく

まとめ

orElse で空のストリームを返す、というアイデアだけ覚えておけばOK

まとめ
Optional.ofNullable(arr)
  .map(Arrays::stream).orElse(Stream.empty())
  .forEach(System.out::println);

詳細

やりたいこと

null の可能性がある配列に対してストリーム処理をしたい。

問題

拡張 for 文や Arrays#streamStream#of は null セーフではない。
でも毎回 null チェックするのは面倒。

for文を使う場合
String[] arr = null;

for (String s : arr) { // ここで NullPointerException 
  System.out.println(s);
}
Arraysを使う場合
String[] arr = null;

Arrays.stream(arr) // ここで NullPointerException
  .forEach(System.out::println);

// Stream#of も内部で Arrays#stream を使っているらしく
Stream.of(arr) // ここで NullPointerException
  .forEach(System.out::println);

Optional を使う

  • Arrays#stream で配列をストリームに変換
  • Optional が空のときは Stream#empty で空のストリームを返す
Optionalを使う場合
String[] arr = null;

Optional.ofNullable(arr)     // この時点で Optional<String[]>
     .map(Arrays.stream)     // この時点で Optional<Stream<String>>
     .orElse(Stream.empty()) // この時点で Stream<String>, 配列の中身のストリーム
     .forEach(System.out::println);
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SPAの文字揃えゲーム作成

背景

過去記事:JavaとJavaScriptでwebブラウザとのソケット通信①

過去に非同期通信を用いてチャットアプリを作成した。
⇒改造してチャットとは異なるアプリケーションを作成。

twitterで見かけた『~揃えゲーム』を作成。
個人制作の備忘録。
無題.jpg

目的

  • ソケット通信で送受信されているデータを取得して編集する
  • JavaScriptを用いて受信データの表示方法を学ぶ

実践内容

  1. クライアントから送信されたデータをサーバーサイドプログラムによって編集
  2. 編集したデータをクライアントへ送信
  3. サーバーから送信されたデータ(文字列)を1文字ずつ順番に表示

成果物

  1. なんでも揃えゲーム
    ⇒ 送信したデータがランダムに返信されるプログラム

言語

サーバープログラム:Java
クライアントプログラム:JavaScript

コード内容

  1. RandomSocket.java:ソケット通信のためのサーバープログラム
  2. RandomLogic.java:受信したデータを編集するプログラム
  3. randomView.html:表示用のHTML
  4. random.js:ソケット通信および動的表示のためのクライアントプログラム

ソケット通信(サーバー)

RandomSocket.java
package randomWeb;

import java.io.IOException;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint(value = "/random")
public class RandomSocket {
    private static Set<Session> user = new CopyOnWriteArraySet<>();

    @OnOpen//クライアントと接続したとき
    public void onOpen(Session mySession) {
        System.out.println("connect ID:"+mySession.getId());
        user.add(mySession);
    }

    @OnMessage//クライアントからデータが送信されたとき
    public void onMessage(String text , Session mySession) {
        RandomLogic randomLogic=new RandomLogic(text);
        System.out.println(text);
        String random=randomLogic.logic();
        for (Session user : user) {
            user.getAsyncRemote().sendText(random);
            System.out.println(user.getId()+"番目に"+mySession.getId()+"番目のメッセージを送りました!");
        }
        if(text.equals("bye")) onClose(mySession);
    }

    @OnClose//クライアントが切断したとき
    public void onClose(Session mySession) {
        System.out.println("disconnect ID:"+mySession.getId());
        user.remove(mySession);
        try {
            mySession.close();
        } catch (IOException e) {
            System.err.println("エラーが発生しました: " + e);
        }
    }

}

ポイント

  1. @onMessageでクライアントからデータを受信
  2. RandomLogicインスタンスを作成しデータを渡す
  3. 変数randomに編集後のデータを受け取り、それをクライアントに送信する

データ編集

RandomLogic.java
package randomWeb;

public class RandomLogic {
    private String text="";
    private String random="";

    public RandomLogic(String text) {//コンストラクタ
        this.text=text;
    }

    public String logic() {

        char[] textArray=text.toCharArray();//textを1文字ずつ配列に分割
        char[] textArray2=new char[textArray.length];//分身となる配列を作成
        int a=0;//配列の添え字
        for(int i=0;i<textArray.length;i++) {
            a=new java.util.Random().nextInt(textArray.length);
            textArray2[i]=textArray[a];//分身に本家の1文字をランダムに代入
            random+=textArray2[i];//変数randomに順番に文字を追加(for文が終了した時点で1単語分)
        }
        while(true) {
            String text2 = new String(textArray2);//分身の配列を文字列に変換
            if(text2.equals(text)) break;//分身の文字列が本家の文字列と等しいならbreak

            for(int i=0;i<textArray2.length-1;i++) {
                textArray2[i]=textArray2[i+1];//分身の文字を1文字ずつ前にずらす
            }

            a=new java.util.Random().nextInt(textArray2.length);
            textArray2[textArray2.length-1]=textArray[a];//分身の最後の文字を本家の文字からランダムに選ぶ
            random+=textArray2[textArray2.length-1];//追加された1文字を変数randomに追加する
        }
        return random;//最後にこれまでの文字列を返す
    }
}

ポイント

コメントの通り。
やりたいことは文字列を編集してreturnすること。

表示用のHTML

randomView.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>ランダムシステム</title>
    <script type="text/javascript" src="random.js"></script>
</head>
<body>
    <div style="width: 500px; height:500px; overflow-y: auto; border: 1px solid #333;" id="show">
    </div>
        <input type="text" size="80" id="msg" name="msg" />
        <input type="button" value="送信" onclick="sendMsg();" />
</body>
</html>

ポイント

特になし。

ソケット通信および動的表示

random.js
// WebSocketオブジェクト生成
var wSck= new WebSocket("ws://localhost:8080/randomWeb/random");

//ソケット接続時のアクション
wSck.onopen = function() {
    document.getElementById('show').innerHTML += "接続しました。" + "<br/>";
};

//メッセージを受け取ったときのアクション
wSck.onmessage = function(e) {
    var text=e.data;
    message(text);
};
//時間間隔を空けて表示する
var nextText='';
var length=''
function message(text){
    if (text !== '') {
        if(nextText==''){
            length=text.length;
        }
        var c = text.slice(0, 1);//テキストの先頭1文字を取得
        document.getElementById('show').innerHTML += c;//1文字を表示
        nextText = text.slice(1);//テキストの先頭1文字を削除
        setTimeout('message(nextText)', 1);//1ms毎にループ
    }else{
        document.getElementById('show').innerHTML += '<br/>『'+length+'文字目』でそろったよ!<br/>';//最後に改行
    }
}

//メッセージを送信するときのアクション
var sendMsg = function(val) {
    var line = document.getElementById('msg');//入力内容を取得
    wSck.send(line.value);//ソケットに送信
    console.log(line.value);
    line.value = "";//内容をクリア
};

ポイント

  1. データを受信したとき、message()メソッドで1文字ずつ順番に表示する
  2. 初回のみlength=text.length;で文字数を代入しておく
  3. var c = text.slice(0, 1)で先頭1文字を取得し表示する
  4. nextText = text.slice(1);で先頭1文字を削除
  5. setTimeout('message(nextText)', 1);で1ms毎にmessage()メソッドが実行される ⇒ setTimeout()メソッドでmessage()メソッドを入れ子構造にすることで無限ループとなる
  6. 全ての文字を表示し終わったら文字数等を表示して終了

実行結果

  1. ブラウザでHTMLファイルを実行。
  2. 文字列を入力し送信。(今回は『おぱんつ』)
  3. 送信した文字列の中から1文字ずつランダムに表示される。
  4. 元の文字列が揃えば終了。

特に意味はないが、チャットアプリケーションを応用しているため、複数ブラウザで実行すると全てのクライアントにランダムな文字群が表示される。

ランダムシステム.gif

その他

改善点

・文字列が長すぎると処理に時間がかかりすぎる
完全ランダムなため、文字列が揃う確率は指数関数的に減衰していく。
3~6文字くらいでしか遊べない。

・ボックスをオーバーフローすると自動で観測できない
はみ出た分はスクロールで見ることができるが、自動で追ってくれないため手動でスクロールバーを操作しなければならない。
⇒ jQueryのanimateメソッドを使えばうまくスクロールできそうだが、今回は断念。要検討。

感想

以前コンソール上で動作する文字揃えゲームを作成したことがあるが、ブラウザで表示するとなると工数がかなり増える。
特に表示方法にこだわるとJavaScriptの記述もかなり必要になってくる。

改良すれば適宜更新していく。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

2変数、4分岐の if 文について

変数 min_value, max_value が存在するとき、それぞれの条件で処理を変えたい

例えば…

min_value max_value 処理
null null なにもしない
null not null 上限より小さいことを検証
not null null 下限より大きいことを検証
not null not null 範囲内にあることを検証

普通はこんな感じ

Main.java
class Main {

    public static void main(String[] args) {

    }

    private static String hoge(int value, Integer min_value, Integer max_value) {
        if (min_value == null && max_value == null) {
            // なにもしない
            return "";
        }
        if (min_value == null) {
            // 上限チェック
            return "";
        }
        if (max_value == null) {
            // 下限チェック
            return "";
        }
        // 範囲チェック
        return "";
    }

}

  • パッと見、分かりづらい
  • 比較が一つの場合と、四つの場合が存在し、データによっては速度に違いが出る
  • 見た目が悪い

これをなんとか解消したい…

main.swift
func hoge(_ value: Int, _ min_value: Int?, _ max_value: Int?) -> String {
    // Optional が外れない
    switch(min_value != nil, max_value != nil) {
        case (true,  true):
            return ""   // 範囲チェック
        case (true,  false):
            return ""   // 上限チェック
        case (false, true): 
            return ""   // 下限チェック
        case (false, false):
            return ""   // 何もしない
    }
}

Pytyon3 の場合

main.py
def hoge(value, min_value, max_value):
    command = {
        (True, True): lambda: "",    # 範囲チェック
        (True, False): lambda: "",   # 下限チェック
        (False, True): lambda: "",   # 上限チェック
        (False, False): lambda: "",  # なにもしない
    }

    return command[(min_value is not None, max_value is not None)]()

もっと良い方法がありましたら、教えていただきたいです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AtCoder【ABC086A】技術メモ

はじめに

第2弾、AtCoderのことをメモしていく

AtCoderの問題

シカのAtCoDeerくんは二つの正整数 a,bを見つけました。
aと bの積が偶数か奇数か判定してください。

解説

これまた入力された数字を元に計算を行えばいいので
nextInt()の出番かな。

入力できるように準備して

Scanner scanner = new Scanner(System.in);

int a = scanner.nextInt();
int b = scanner.nextInt();

if((a * b) % 2 == 1) {

 System.out.println("Odd");

} else {

 System.out.println("Even");

}

今回の問題は前回使ったScannerとnextInt()を使えたので瞬殺でした。

では、また次回。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaのHttpClientにおける3つのTimeoutの違いに関して

ApacheのHttpClientを使う際に、以下の3つのタイムアウト値(ミリ秒)を設定できるものの、違いをよくわかっていなかったので自分なりにまとめてみた。

import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;

RequestConfig config = RequestConfig.custom()
    .setConnectTimeout(30000)
    .setConnectionRequestTimeout(30000)
    .setSocketTimeout(30000)
    .build();

HttpClient httpClient = HttpClients.custom()
    .setDefaultRequestConfig(config)
    .build();

ConnetionTimeout

サーバーへの接続要求を送信して、接続が確立されたとレスポンスを受け取るまでのタイムアウト値。
要するに3ウェイハンドシェイクでコネクションが確立するまでに許容する時間を設定する。

ConnectionRequestTimeout

上記の接続が完了した後、サーバーへリクエストを送ってレスポンスが返ってくるまでのタイムアウト値。

SocketTimeut

ソケット通信の監視に使われるタイムアウト値。
ソケット通信では継続的にパケットを受信するが、受信間隔がこの値以上が開いた場合はタイムアウト(=SocketTimeoutException)となる。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Image Searchの検索Tips

V2から追加された IntAttr、StrAttrの挙動について調べました。

フィルタを使った絞り込み

フィルタを使い場合は、setFilterにフィルタ条件を設定します。

request.setFilter("int_attr=10000 AND str_attr=\"あああ\"");

全体のソースは、【検索編】を参照してください。

IntAttr の検証

int_attr フィールドは、>、>=、<、<=、= の演算子をサポートしています。

request.setFilter("int_attr=10000");

IntAttrの値が10,000の情報がヒットします。

request.setFilter("int_attr<10000");

IntAttrの値が10,000未満の情報がヒットします。

request.setFilter("int_attr>10000");

IntAttrの値が10,000より大きい情報と、設定されていない(NULL)のデータがヒットします。
設定されていない値が取れてしまうのは注意が必要ですね。

request.setFilter("int_attr>=10000 AND int_attr<=20000");

IntAttrの値が10,000以上、20,000以下のデータがヒットします。

request.setFilter("int_attr=");

エラーが返されます。値は設定する必要があります。

request.setFilter("int_attr<0");

0件のヒットです。整数しか設定できないので何もヒットしません。

request.setFilter("int_attr=30 OR int_attr=100000");

IntAttrの値が30か100,000の情報がヒットします。

request.setFilter("int_attr="+Integer.MAX_VALUE);

IntAttrを設定していない情報がヒット。どうやら、登録時にIntAttrを省略するとIntegerの最大値が設定されるようです。

StrAttr の検証

str_attr フィールドは、=、!= の演算子をサポートしています。

request.setFilter("str_attr=\"家具\"");

"家具"に完全一致した情報がヒット。"家具、机"を設定した情報はヒットしなかった。

request.setFilter("str_attr!=\"家具:本棚\"");

"家具"に完全一致するもの以外と、StrAttrを設定していない情報がヒットする。

request.setFilter("str_attr=\"\"");

StrAttrの設定がされていない情報のみヒット。

まとめ

フィルタ条件が設定されていないデータについての挙動は考慮する必要があります。それぞれ上記の内容で取得する事はできるのでフィルタ条件に設定してみてください。
また、複数の条件を"AND"と"OR"を使う事で設定する事ができます。IntAttrとStrAttrも同時にフィルタ可能です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Image Searchのフィルタを検証してみる

V2から追加された IntAttr、StrAttrの挙動について調べました。

フィルタを使った絞り込み

フィルタを使い場合は、setFilterにフィルタ条件を設定します。

request.setFilter("int_attr=10000 AND str_attr=\"あああ\"");

全体のソースは、【検索編】を参照してください。

IntAttr の検証

int_attr フィールドは、>、>=、<、<=、= の演算子をサポートしています。

request.setFilter("int_attr=10000");

IntAttrの値が10,000の情報がヒットします。

request.setFilter("int_attr<10000");

IntAttrの値が10,000未満の情報がヒットします。

request.setFilter("int_attr>10000");

IntAttrの値が10,000より大きい情報と、設定されていない(NULL)のデータがヒットします。
設定されていない値が取れてしまうのは注意が必要ですね。

request.setFilter("int_attr>=10000 AND int_attr<=20000");

IntAttrの値が10,000以上、20,000以下のデータがヒットします。

request.setFilter("int_attr=");

エラーが返されます。値は設定する必要があります。

request.setFilter("int_attr<0");

0件のヒットです。整数しか設定できないので何もヒットしません。

request.setFilter("int_attr=30 OR int_attr=100000");

IntAttrの値が30か100,000の情報がヒットします。

request.setFilter("int_attr="+Integer.MAX_VALUE);

IntAttrを設定していない情報がヒット。どうやら、登録時にIntAttrを省略するとIntegerの最大値が設定されるようです。

StrAttr の検証

str_attr フィールドは、=、!= の演算子をサポートしています。

request.setFilter("str_attr=\"家具\"");

"家具"に完全一致した情報がヒット。"家具、机"を設定した情報はヒットしなかった。

request.setFilter("str_attr!=\"家具:本棚\"");

"家具"に完全一致するもの以外と、StrAttrを設定していない情報がヒットする。

request.setFilter("str_attr=\"\"");

StrAttrの設定がされていない情報のみヒット。

まとめ

フィルタ条件が設定されていないデータについての挙動は考慮する必要があります。それぞれ上記の内容で取得する事はできるのでフィルタ条件に設定してみてください。
また、複数の条件を"AND"と"OR"を使う事で設定する事ができます。IntAttrとStrAttrも同時にフィルタ可能です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Java SDKを使ってImage Searchの類似検索を試す【登録編】

はじめに

前回は、Image Searchのインポート機能を使って画像を登録しました。インポート機能では、V1の時のパラメータしか登録できずV2で新たに追加されたパラメータを登録する事はできませんでした。できました。すみません。

ということで、Image Searchにデータを投入するにはAPIを使って登録する方が良いと思います。データを登録する際はいくつか気を付ける点があるので、そのあたりを記述していきたいと思います。

データの登録方法

今回は、Java SDKを使って登録を行います。環境構築等は【検索編】を参照してください。

SimpleAdd.java
package imagesearch.sample;

import java.io.InputStream;
import java.util.Base64;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.imagesearch.model.v20190325.AddImageRequest;
import com.aliyuncs.imagesearch.model.v20190325.AddImageResponse;
import com.aliyuncs.imagesearch.model.v20190325.AddImageResponse.PicInfo;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;

public class SimpleAdd {
    /** AccessKey */
    private static final String ACCESS_KEY = "XXXXXXXXXXXXXxxx";
    /** SeacretKey */
    private static final String KEY_SEACRET = "YYYYYYYYYYYYYYY";

    public static void main(String[] args) throws Exception {
        // 初期化(Tokyoリージョンのケース
        DefaultProfile.addEndpoint("ap-northeast-1", "ImageSearch", "imagesearch.ap-northeast-1.aliyuncs.com");
        IClientProfile profile = DefaultProfile.getProfile("ap-northeast-1", ACCESS_KEY, KEY_SEACRET);
        IAcsClient client = new DefaultAcsClient(profile);

        AddImageRequest request = new AddImageRequest();
        request.setInstanceName("itemsearch");
        request.setProductId("id-0001");
        request.setPicName("item0001");
        request.setCategoryId(9);
        request.setCrop(true);
        request.setIntAttr(1000);
        request.setStrAttr("家具:椅子");
        request.setCustomContent("{'sample': 'さんぷる'}");
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        InputStream is = loader.getResourceAsStream("item01.jpg");
        String image = Base64.getEncoder().encodeToString(is.readAllBytes());
        request.setPicContent(image);

        AddImageResponse response = client.getAcsResponse(request);

        // Debug
        boolean checkShowJsonItemName = response.checkShowJsonItemName();
        Integer code = response.getCode();
        String message = response.getMessage();
        String requestId = response.getRequestId();
        Boolean success = response.getSuccess();
        PicInfo picInfo = response.getPicInfo();
        Integer categoryId = picInfo.getCategoryId();
        String region = picInfo.getRegion();

        System.out.printf("requestId:%s%nmessage:%s%ncheckShowJsonItemName:%s%ncode:%s%nsuccess:%s%n", requestId, message, checkShowJsonItemName, code, success);
        System.out.println("PicInfo");
        System.out.printf("\tcategoryId:%s%n\tregion:%s%n", categoryId, region);
    }
}
requestId:F009FFA3-D94C-4C95-A8D1-957F7EE06591
message:success
checkShowJsonItemName:false
code:0
success:true
PicInfo
        categoryId:9
        region:140,474,36,578

パラメータ説明

ProductId

request.setProductId(productId);

入力必須。商品ID、最大 512 文字をサポートします。1つの商品に複数の画像を含めることができます。

PicName

request.setPicName(picName);

入力必須。画像名、最大 512 文字をサポートします。

  1. ProductId + PicName で画像を特定します。
  2. 複数回追加した画像に同じ ProductId + PicName がある場合、最後に追加された画像が上書きされます。

1つの商品に複数の画像を登録する事で、検索の精度を上げる事ができます。正面画像、斜め画像などいくつかのパターン画像を登録しておくと良いと思います。

CategoryId

request.setCategoryId(9);

入力任意。画像カテゴリ。
1. 商品検索の場合:カテゴリが設定されている場合はその設定が優先され、設定されていない場合はシステムがカテゴリ予測を実行し、予測されたカテゴリの結果を Response で取得できます。
2. ユニバーサル検索の場合:カテゴリが設定されているかどうかに関わらず、システムによりカテゴリが 88888888 に設定されます。

設定可能なカテゴリ

カテゴリー ID 説明
0 トップス
1 ドレス
2 ボトムズ
3 バッグ
4 シューズ
5 アクセサリー
6 スナック
7 メイクアップ
8 ボトルドリンク
9 家具
20 おもちゃ
21 下着
22 デジタル機器
88888888 その他

PicContent

request.setPicContent(encodePicContent);

入力必須。Base64 でエンコードした画像コンテンツ。
最大 2 MB サイズの画像と 5 秒の送信待ち時間をサポートします。現在 jpg および png の画像形式のみサポートしています。
縦と横の画素数は共に 200 以上 1024 以下でなければならず、画像に回転情報を含めることはできません。

本番運用では、登録前に変換ロジックを入れるのが良いかもしれません。あと、ここで行っている「5秒の送信待ち時間をサポートします」というのは、どういう意味か分かっていません。。。なんでしょう。知っている人がいたら教えてください。(そのうちソースで確認してみます。。。)

Crop

request.setCrop(true);

入力任意。被写体認識の要否、デフォルトは true です。
1. true の場合、システムにより被写体認識が行われ、認識された被写体による検索が実行されます。被写体認識結果を Response で取得できます。
2. false の場合、被写体は認識されず、画像全体として検索されます。

商品検索の場合、trueで良いと思います。例えば、部屋の雰囲気みたいなものを検索したいのであればfalseで登録しても良いかもしれません。

Region

request.setRegion("280,486,232,351");

入力任意。x1、x2、y1、y2 の形式で表される画像の被写体範囲、x1、y1 は左上の点、x2、y2 は右下の点です。
ユーザーが Region を設定した場合、Crop パラメーターの値に関わらず、その Region で検索を実行します。

登録対象の画像に複数のオブジェクトがある場合(例えば椅子を登録しようとして、カーテンやテーブルなども写っている場合)に、検索の精度を上げるために対象のオブジェクトの位置情報を設定する事で、検索の精度を上げる事ができます。

IntAttr

request.setIntAttr(intAttr);

入力任意。検索時のフィルタリングに使用できる整数型属性、検索された際にこのフィールドが返されます。
たとえば、サイトの画像 / ユーザーの画像ごとに IntAttr をそれぞれ設定することができ、検索された際にフィルタリングすることで分離できます。

V2から追加されたフィルタに使用できるパラメータです。後述のStrAttrと組み合わせてフィルタする事が可能になりました。フィルタを使う事で、Image Searchからフィルタ条件にマッチしたデータを取得する事ができます。以前はデータを取得した後フィルタするしかなかったので便利になりましたね。
要望を言えば、複数の値を設定できると助かるのですが。。。フィルタ条件は「>、>=、<、<=、=」です。商品の金額などを設定すると、ECサイトでよくある10,000円~30,000円の商品などで絞ることができるかなと思います。

StrAttr

request.setStrAttr(strAttr);

入力任意。文字列型属性、最大 128 文字をサポートします。検索された際のフィルタリングに使用できます。検索された際にこのフィールドが返されます。

こちらは、文字列を設定してフィルタする事ができます。使用できるフィルタ条件は「=,!=」です。しかも、完全一致でのフィルタとなります。かなり使い勝手が悪いですね。。。現実的な使い方としては、パラメータをビット化して設定するとかですかね。。。それでも使いづらいけど。複数パラメータの設定と正規表現などが使えるとかなり助かります。

CustomContent

request.setCustomContent("カスタム");

入力任意。ユーザーがカスタマイズした内容、最大 4096 文字をサポートします。
検索された際にこのフィールドが返されます。たとえば、画像の説明などのテキストを追加できます。

JSONなどを設定する事で使いやすくすることができます。

システム制限

システム制限 - ユーザーガイド| Alibaba Cloud ドキュメントセンター
https://jp.alibabacloud.com/help/doc-detail/74408.htm

登録時に気を付ける点は以下の通りです。

  1. 画像のサイズは 2 MB以下で、長さと幅のピクセルは 200 以上 1024 以下
  2. JPG と PNG の 2 種類の画像をサポートしており、画像には回転情報を含むことはできません
  3. 並行処理の使用制限
    1. 検索、追加の並行処理数 (インスタンス作成時に選択した クエリ/秒(QPS)) はコンソールで確認できます。現在 5 クエリ/秒、10 クエリ/秒を選択できます。つまり、1 秒あたり最大 5または10 の検索リクエストを並行処理できます。(無料版の場合は1秒当たり最大1リクエスト)
    2. 削除操作のデフォルトのクエリ/秒(QPS)は 20 です。つまり、1 秒あたり最大 20 つの削除リクエストを並行処理できます。

まとめ

気を付ける点は以下の通り
1. 画像の種類
2. 画像のサイズ
3. 連続登録の場合は、APIの呼び出し制限をうける
4. フィルタ条件に使えるIntAttr、StrAttrの設計はむずかしい
5. 同じキーで登録すれば上書きされる(主キー制約などはないので注意)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

java Scannerクラス

Scannerクラスについて

導入

Scannerクラスはjava.utilパッケージに含まれるクラスです。

主にコンソール画面の入力、csvファイルの読み込みに使います。

説明読むのめんどくさいんで例題行きます。
スクリーンショット 2020-05-26 15.37.27.png

例題

まずよく使う型指定の入力について見てみましょう。
コード画面
スクリーンショット 2020-05-26 14.32.14.png

コンソール画面
スクリーンショット 2020-05-26 14.32.20.png

はい、こんな感じになります。
ちなみにこれでは不完全なのですが見やすいので一旦解説します。

順番としては

まず、Scannerクラスをimportします。importの決まりはimport パッケージ名.クラス名です。

次にインポートしたScannerクラスをインスタンス化します。
System.inがコンソールでの入力(標準入力)です。


指定の型の変数を作成。
そこにScannerクラスのnextInt()メソッドで値を取得し初期化します。

他にも型指定だとnextByte, nextShort, nextLong, nextFloat, nextDouble, nextBoolean があります。char 型のメソッドだけがないですね。文字列にはnext と nextLine があります。


最後にcloseメソッドでScannerを閉じる必要があります。
closeがないと予期せぬエラーを引き起こすため気をつけましょう。

例外処理

不完全と言ったのは、実は上記のコンソール入力の画面でint型以外の入力をしてしまうとエラーが起きてしまいます。
コンソール画面
スクリーンショット 2020-05-26 15.17.01.png

このように予期せぬ処理を行おうとするとエラーが起きるので、この場合の処理を予期しときます。(日本語わからん)

例外が起きる可能性の処理はtry-catch構文で覆います。if文と同じ要領です。
try{
例外の起こる可能性のある処理;
}catch(<例外クラス> <変数名>){
例外が起きた時に行う処理;
}

です。今回ですと

コード
スクリーンショット 2020-05-26 15.24.23.png

コンソール画面
スクリーンショット 2020-05-26 15.24.35.png

注意点としては 

例外処理のクラスをimportする必要があります。
よく見ると一番上にimport java.util.InputMismatchException; // 例外処理用のものが追加されているのがわかります。


System.out.println("入力された数値は " + num + " です。");をtry-catch文のそとに出すと例外の場合も処理を行ってしまいます。(今回は num のスコープが try ブロックの中なのでエラーが起きますが)
スクリーンショット 2020-05-26 15.35.29.png
これは気持ち悪いですね〜。

まとめ

超基本的なScannerの使い方をまとめてみました。
次は正常処理を行うまで入力をループさせるコードの記事をまとめました。

次へ

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Javaのコンストラクタ

コンストラクタ

インスタンスフィールドが増えるとコードが冗長になります。
クラスには、コンストラクタというものがあり、newを使ってインスタンスを生成した後に自動で呼び出される特別なメソッドを使います。
コンストラクタは特別なメソッドのため、定義方法が決まっています。
①コンストラクタ名はクラス名と同じにする
②戻り値を書いてはいけない(voidも書かない)
【例】今回は人(Person)にします

Person.java
class クラス名 {
  クラス名() {  //コンストラクタ〜
  //インスタンス生成時に行いたい処理を記述
  }  //〜コンストラクタ
}

【例】

Main.java
class Main {
  public static void main(String[] args) {
    Person person1 = new Person();
    Person person2 = new Person();
  }
}
Person.java
class Person {
 Person() {
    System.out.println("おはよう");
 }
}

次は、インスタンスを生成する際に、インスタンスフィールドにセットしたい値を引数に渡し、コンストラクタでセットします。
thisを用いてインスタンスを利用することができます。
【例】

MAin.java
class Main {
  public static void main(String[] args) {
    Person person1 = new Person("佐藤");
    person1.hello();

    Person person2 = new Person("鈴木");
    person2.hello();
  }
}
Person.java
class Person {
  public String name;
  Person(String name) {  //コンストラクタがString型の引数を受け取るようにしています
    System.out.println("おはよう");
    this.name = name;  //インスタンスフィールドnameに値をセットしています
  }

  public void hello() {
    System.out.println("私は" + this.name + "です");
  }
}

上記だと「new Person("佐藤");」の佐藤の部分がPerson.javaの「Person(String name)」のnameが佐藤(鈴木)になり、さらに「this.name = name;」の右側のnameからthis.nameに佐藤(鈴木)が入る感じです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Javaのクラス定義とインスタンスの生成

クラス定義とインスタンスの生成

クラスからインスタンスを生成するには「new クラス名()」を使います。
【例】

class Main {
  public static void main(String[] args) {
  new Person();  //Person(今回は人)クラスのインスタンスを生成します
  }
}
Person.java
class Person{
}

変数にインスタンス

変数にインスタンスを代入するには「クラス型 変数名 = new クラス名()」を使います。
インスタンスの代入ではクラス型を指定し、クラス名がそのままクラス型になります。
【例】

class Main {
  public static void main(String[] args) {
  Person person = new Person();
  }
}
Person.java
class Person{
}

インスタンスメソッド

インスタンスメソッドは「public 戻り値の型 メソッド名()」を使います。

Main.java
class Main {
  public static void main(String[] args) {
    Person person = new Person();  //voidは戻り値の型です
    person.hello();
  }
}
Person.java
class Person {
  public void hello() {
  System.out.println("おはよう");
  }
}

インスタンスフィールドの定義

インスタンスフィールドの定義は「public データ型 変数名」というように、変数定義の前にpublicを付けます。
【例】

Person.java
class Person {
  public String name;
}

String nameで名前を入れる定義を定義しています。
インスタンスフィールドには、「インスタンス名.フィールド名」を使います。
【例】

Main.java
省略
    Person person = new Person();
    person.name("佐藤");
    System.out.println(person.name);  //person.nameでnameの値を取得しています
省略

【例】

Main.java
class Main {
  public static void main(String[] args) {
    Person person = new Person();
    person.hello();
    person.name = "佐藤";
    System.out.println(person.name); 
    }
}
Person.java
class Person {
  public String name;
  public void hello() {
    System.out.println("おはよう");
  }
}

this

メソッド内でインスタンスフィールドにアクセスするためには「this」の変数を用います。
thisはクラス内のメソッドの定義の中でのみ使用できます。
thisはメソッドが呼ばれた時に、そのメソッドを呼び出しているインスタンスに置き換えられます。
【例】

Main.java
class Main {
  public static void main(String[] args) {
    Person person = new Person();
    person.hello();  //personがthisを呼び出します
    person.name = "佐藤";
    System.out.println(person.name); 
    }
}
Person.java
class Person {
  public String name;
  public void hello() {
    System.out.println("おはよう" + this.name);  //this.(今回は)helloメソッドのnameフィールド
  }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

processingで作る簡単な障害物レースfor Java

prossesingはプログラミング初心者におすすめ

prossesingはデザインアートを作ることができる環境です。
言語はJavaベースで作ってありますが、Pythonなど他の言語で書くことも可能です。
また、文の構造なども他のものに比べて見やすいので、まず簡単に動くプログラミングを作りたい!という方にはおすすめです。
ここでは、prossesing初心者の僕が1日で作れた簡単なゲームを紹介していきます。
コードの読みにくさはあるかもしれませんが、ご了承ください(汗

今回作るゲーム

今回は、向かってくる障害物を避けるゲームを作っていきたいと思います。
機能としては、ジャンプ・衝突判定で作ることができます。
ここでは、コードと簡単な流れをご紹介します。
不明点があれば、コメントして頂けたらお答えします。

コード紹介

簡単な流れだけご紹介します。
今回は棒人間を走らせるようにします。
まず必要な画像をダウンロードし、繰り返し表示するものはリストに格納していきます。

次に棒人間をジャンプさせるために、yの更新式を工夫します。
クリックした瞬間に上方向に速度を持たせ、重力に見立てた力を働かせることで落下させています。
簡単な物理計算をしています。

また、向かってくる障害物は一定の速度でこちらに向かってくるものと考えて、速度をv、位置をxとして、位置に関する更新式を書いています。

最後に、衝突判定はAND演算子(2つの条件を満たしたときに衝突したと判定)を用いて判定してます。
判定条件は、画像下の部分が障害物よりも下の位置に来た時にループを停止するようにしています。

以下にコードを載せておきます。
画像は自分のPCにある画像を使っているため、直接のコピペでは動きません。
棒人間の動きをずらした画像を8枚と、河野大臣の画像が1枚必要です。笑

prossesing-for-java
int numFrames = 8;  // The number of frames in the animation
int currentFrame = 0;
PImage[] img = new PImage[numFrames];
PImage img2;
float y,vy,Fy,x,z,vx;

void setup() {
  frameRate(24);
  size(600, 600);
  y = 0;
  vy = 0;
  Fy = 0;
  x = 570;
  z = 570;
  vx = 5;
  // The image file must be in the data folder of the current sketch 
  // to load successfully
  img2 = loadImage("kouno-tarou.jpg");
  img[0] = loadImage("stick0.png");  // Load the image into the program  
  img[1] = loadImage("stick1.png");
  img[2] = loadImage("stick2.png");
  img[3] = loadImage("stick3.png");
  img[4] = loadImage("stick4.png");
  img[5] = loadImage("stick5.png");
  img[6] = loadImage("stick6.png");
  img[7] = loadImage("stick7.png");
}

void draw() {
  background(255);

  vy = vy +Fy;

  y = y + vy;

  x = x - vx;

  if(y > 0){
  vy = 0;
  Fy = 0;
  y = 0;
  }

  if(x < 0){
    x = 570;
  }
  currentFrame = (currentFrame+1) % numFrames;
  image(img[currentFrame], 0, 450 + y);

  fill(0);
  rect(x,z,30,30);

  if ( ((0<x) && (x<100)) && (600+y > 570)){
  fill(253);
  rect(0,0,600,600);
  image(img2,0,0);
  noLoop();
  }
}

void mouseClicked(){
  Fy =1.2;
  vy = -20;
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

java(インターフェース)

インターフェースとしてできる条件

抽象クラスの親玉(一番上の方)
①すべてのメソッドは抽象メソッド
②基本的にフィールドを持たない

抽象度の高いHumanクラス

Human.java
public abstract class Human {     //上の①②を満たしている
  public abstract void run();
}

インターフェースとして宣言したHumanクラス

Human.java
public interface Human {
  void run();                        //public abstract を省略可能
}

インターフェースの実装

Hero.java
public class Hero implements Human { 
}

インターフェースによる多重継承

Hero.java
public class PrincessHero 
    implements Hero, Princess {    //親のインターフェースを複数継承できる
}

クラスでは多重継承はできないが、インターフェースなら可能

インターフェースの継承

Hero.java
public interface Human extend Creature {
  void talk();
  void watch();
  void hear();
  //さらに、親インターフェースからrun()を継承している
}

implements(実装)、extend(継承)の使い分け

  • クラス同士、インターフェース同士ならextend(継承)
  • クラスでインターフェースを使う(異種)ならimplements(実装)

implements(実装)、extend(継承)の両方を使ったクラスの定義

Hero.java
public class Hero extends Charaater implements Human{
  // Charaaterからhpやnameなどのフィールドを継承
  // Charaaterから継承した抽象メソッドattack()実装
  public void attack(Goblin g) {
    System.out.println(this.name + "5のダメージをあたえた");
  }
  // さらにHumanから継承した4つの抽象メソッドを実装
  public void talk(){
    System.out.println("・・・");
  }
  public void watch(){
    System.out.println("・・・");
  }
  public void hear(){
    System.out.println("・・・");
  }
  public void run(){
    System.out.println("・・・");
  }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

文字操作の基本(java)

文字操作(java)

初投稿です。
今回は文字操作についてまとめました。
基本的なものなので、わすれたときに見返そうと思います。

public class Main{
    public static void main(String[] args){
        String s1 = "Javaの勉強";
        String s2 = "Java";
        String s3 = "java";
        String s4 = "Javascript";
        String s5 = "javascript";
        String s6 = "";
        String s7 = "勉強Java";
        String s8 = " j a v a ";
        String s9 = " j a v a ";
        String s10 = "jjjjjjjjjj";
        String s11 = "jjjjjaaaaavvvvvaaaaa";
        String s12 = "j";
        String s13 = "0123456789";
        String s14 = "a0b1c2d3e4f5g6h7i8j9k10";
        String s15 = "0a1b2c3d4e5f6g7h8i9j10k";
        String s16 = "a,0,b,1,c,2,d,3,e,4,f,5,g,6,h,7,i,8,j,9,k,10";

//文字の内容が等しいかを調べる
//検索したい文字.equals(検索したい文字)
if(s2.equals(s3)){
  System.out.println("s2とs3は同じ文字");
  }else{
        System.out.println("s2とs3は等しく無い");
  }

//大文字小文字区別せず文字が等しいかを調べる 検索したい文字.equalsIgnoreCase(検索したい文字)
if(s2.equalsIgnoreCase(s3)){
 System.out.println("s2とs3は同じ文字");
 }else{
  System.out.println("s2とs3は等しく無い");
 }

//文字列の長さを表示する 検索したい文字.lenght()
System.out.println(s4.length());

//空文字か調べる 検索したい文字.isEmpty()
if(s6.isEmpty()){
  System.out.println("s6は空文字");
 }else{
  System.out.println("s6は空文字では無い");
 }

//文字列sが含まれるかを調べる 検索したい文字.contains(検索したい文字)
if(s4.contains(s2)){
 System.out.println("s4にs2は含まれる");
 }else{
 System.out.println("s4にs2は含まれない");
 }

//文字列sで始まるかを調べる 検索したい文字.startsWith(検索したい文字)
if(s4.startsWith(s2)){
  System.out.println("s4はJavaから始まる");
  }else{
  System.out.println("s4はJavaから始まらない");
  }

//文字列sで終わるかを調べる 検索したい文字.endsWith(検索したい文字)
  if(s4.endsWith(s2)){
  System.out.println("s4はJavaで終わる");
  }else{
   System.out.println("s4はJavaで終わらない");
  }

//文字列sが最初に現れる場所を先頭から探す。検索したい文字.indexof(検索文字)
System.out.println(s2.indexOf(s4)); //-1なら検索文字は存在しない
System.out.println(s4.indexOf(s2)); //0以上が検索文字の発生位置

//文字列sが最初に現れる場所を後ろから探す。検索したい文字.lastIndexOf(検索文字)
System.out.println(s2.lastIndexOf(s4)); //-1なら検索文字は存在しない
System.out.println(s7.lastIndexOf(s2)); //0以上が検索文字の発生位置

//指定した位置の文字を1文字だけ切り出す 検索したい文字.charAt(切り出したい文字の場所)
System.out.println(s7.charAt(1)); //強が表示

//指定した位置から任意の長さだけ文字を切り出す 検索したい文字.substring(切り出したい文字の場所)
System.out.println(s7.substring(1)); //強Javaが表示
System.out.println(s7.substring(1,4)); //強Jaが表示

//大文字を小文字に変換 変換したい文字.toLowerCase()
System.out.println(s2.toLowerCase()); //Javaがjavaになる

//小文字を大文字に変換 変換したい文字.toUpperCase()
System.out.println(s2.toUpperCase()); //javaがJAVAになる

//文字の前後の空白を消す 変換したい文字.trim()
System.out.println(s8.trim()); // j a v a がJAVAになる

//文字列を置き換える 変換したい文字.replace(変換したい文字,変換後の文字)
System.out.println(s9.replace("j","a")); // a a v a と表示
System.out.println(s9.replace(" ","")); //javaと表示 文字内の空白を削除する

StringBuilder hoge = new StringBuilder(); //hogeにStringBuilderインスタンスをnewする
  for(int i = 0; i < 1000; i++) { //for内処理を1000回繰り返す
  hoge.append("a"); //hogeにaを追加
  hoge.append("z"); //hogeにzを追加
 }

//文字パターンのチェック(正規表現) 検索したい文字.matches(比較する文字)
//変数の文字がJavaの文字と一致しているか?
System.out.println(s7.matches("勉強Java")); //true
System.out.println(s7.matches("勉強")); //false
System.out.println(s7.matches("Java")); //false

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む