20190524のJavaに関する記事は20件です。

Arrylist and linked list difference in java

In Java collections framework ArrayList and LinkedList are two different implementations of List interface (LinkedList also implement Deque interface though).
In most of the cases we do use ArrayList and it works very well but there are some use cases where using LinkedList may be a better choice.
So let's see some of the differences between ArrayList and LinkedList in Java, it will help you in making an informed choice when to use ArrayList and when a LinkedList.
ArrayList Vs LinkedList in Java
1- If we have to list the differences between the LinkedList and ArrayList in Java, first difference is in the implemenation itself-
LinkedList is implemented using a doubly linked list concept where as ArrayList internally uses an array of Objects which can be resized dynamically.
2- ArrayList class provides a constructor ArrayList(int initialCapacity) even if the default constructor ArrayList() is used an empty list is constructed with an initial capacity of ten. Where as LinkedList just provides one constructor LinkedList() which constructs an empty list. Note that in LinkedList there is no provision of initial capacity or default capacity.
What it means is that if elements are added at the last every time and capacity is not breached then ArrayList will work faster because it already has an initial capacity and just need to add that element at the index in the underlying array. Where as in LinkedList a new node has to be created and references for Next and Prev are to be adjusted to accommodate the new Node.

Refer post How ArrayList works internally in Java to know more about internal working of ArrayList.

Refer post How Linked List class works internally in Java to know more about internal working of LinkedList.
3- One more difference is that LinkedList implementation provides a descendingIterator() which comes from implementing the Deque interface. descendingIterator() returns an iterator over the elements in this deque in reverse sequence.
In ArrayList there is no such iterator.
ArrayList Vs LinkedList performance wise
It is mainly the performance in specific scenarios which dictates whether to go with ArrayList or with LinkedList. Let's go through some of the operations to see how ArrayList Vs LinkedList fares performance wise.
Adding an element- If you are frequently adding element at the beginning of the listthen LinkedList may be a better choice because in case of ArrayList adding at the beginning every time will result in shuffling all the existing elements within the underlying array by one index to create space for the new element.
In the case of adding at the last ArrayList may give O(N) performance in the worst case. That will happen if you add more elements than the capacity of the underlying array, as in that case a new array (1.5 times the last size) is created, and the old array is copied to the new one.
So for LinkedList add(e Element) is always O(1) where as for ArrayList add(e Element)operation runs in amortized constant time, that is, adding n elements requires O(N) time. So the amortized time (i.e. time per insertion) is O(1).
Retrieving an element- Retrieving an element from the list using get(int index) is faster in ArrayList than in LinkedList. Since ArrayList internally uses an array to store elements so get(int index) means going to that index directly in the array. In Linked list get(int index) will mean traversing through the linked list nodes.
So, for ArrayList get(int index) is O(1) where as for LinkedList get(int index) is O(N).
Removing an element- If you are removing element from a list using the remove(int index) method then for LinkedList class it will be O(N) as list has to be traversed to get to that index and then the element removed. Though the LinkedList provides methods like removeFirst() and removeLast() to remove the first or last element and in that case it will be O(1).
In case of ArrayList getting to that index is fast but removing will mean shuffling the remaining elements to fill the gap created by the removed element with in the underlying array. It ranges from O(1) for removing the last element to O(N). Thus it can be said remove(int index) operation is O(N - index) for the ArrayList.
Removing an element while iterating- if you are iterating the list and removing element using iterator.remove() then for LinkedList it is O(1) as the iterator is already at the element that has to be removed so removing it means just adjusting the Next and Prev references. Where as for ArrayList it is again O(N - index) because of an overhead of shuffling the remaining elements to fill the gap created by the removed elements.
While using ArrayList we generally use add() method, very rarely we use add method where index is also passed to add element at any specific position in the ArrayList and to fetch elements from List we use get(int index) which also is faster in ArrayList. That's why we normally use ArrayList, even JavaDocs advocate the same thing-

Related blog:

Spring boot hibernate crud example with mysql

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

compareToの大小比較について

CompareToについて値の結果、どの比較がどの値になるか忘れてしまうことがあるので、備忘録。

①文字列で比較する場合はcompareTo()

public class Test {
    public static void main(String[] args) {
         String a = "a";
         String b = "b";
         System.out.println(a.compareTo(b));
         System.out.println(b.compareTo(a));
         System.out.println(a.compareTo(a));
    }
}

下が実行結果です。

-1
1
0

辞書的に文字の位置が離れている場合に、-1か1を返します。
aはbの前なので-1
bはaのあとなので1
同一の場合は0

②数値で比較する場合はInteger.compare()

public class Test {
    public static void main(String[] args) {
         int one = 1;
         int two = 2;
         System.out.println(Integer.compare(one,two));
         System.out.println(Integer.compare(two,one));
         System.out.println(Integer.compare(one,one));
    }
}

下が実行結果です。

-1
1
0

単純に計算結果。
1-2=-1
2-1=1
1-1=0です。

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

ABC - 010 - A&B&C

AtCoder ABC 010 A&B&C

AtCoder - 010

A - ハンドルネーム

    private void solveA() {
        out.println(next() + "pp");
    }

B - 花占い

  • 最初分岐して・・・ってやったけど、よく考えたら2と3の最小公倍数の6の余りで分岐したほうが読みやすかった
    • コメントアウトしているif文の方もACではある
    private void solveB() {
        int n = nextInt();
        int[] wk = IntStream.range(0, n).map(i -> nextInt()).toArray();
        int res = Arrays.stream(wk).reduce(0, (sum, i) -> {
            switch (i % 6) {
            case 1:
                return sum;
            case 2:
                return ++sum;
            case 3:
                return sum;
            case 4:
                return ++sum;
            case 5:
                return sum += 2;
            case 0:
                return sum += 3;
            }
            //          if (i % 2 == 1) {
            //              switch (i % 3) {
            //              case 0:
            //              case 1:
            //                  return sum;
            //              case 2:
            //                  return sum += 2;
            //              }
            //
            //          } else {
            //              switch (i % 3) {
            //              case 0:
            //                  return sum += 3;
            //              case 1:
            //              case 2:
            //                  return ++sum;
            //              }
            //          }

            return sum;
        });

        out.println(res);
    }

C - 浮気調査

  • 三平方の定理を久しぶりに見た
  • ごり押しでも通るんだーって思った後に解法見たら楕円の定理でも解けるとな。。。わからん。。。
    private void solveC() {
        int sX = nextInt();
        int sY = nextInt();
        int gX = nextInt();
        int gY = nextInt();
        int t = nextInt();
        int v = nextInt();
        int n = nextInt();

        for (int i = 0; i < n; i++) {
            int tmpX = nextInt();
            int tmpY = nextInt();
            double total = (Math.hypot(Math.abs(tmpX - sX), Math.abs(tmpY - sY))
                    + Math.hypot(Math.abs(tmpX - gX), Math.abs(tmpY - gY)));
            if (total <= t * v) {
                out.println("YES");
                return;
            }
        }

        out.println("NO");
    }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SpringBoot + Redis 簡単に作るデモ

はじめに

springbootとは、java開発者にとって一番使いやすいフレームワークだと思います。
redisとは、人気のNOSQLのDBの一つです。
今回はspringbootとredisを使ってCURDのデモを作ります。

事前準備

1.環境:
     SpringBoot
     Redis
     Gradle
 
 2.プロジェクト構築
  Spring Initializrを頼んで自動的にプロジェクト雛形を生成されます。

  以下のように設定してください。
   ① Gradle Project
   ② Java
   ③ Spring Boot 2.1.5

  Spring_project.jpg

やったこと

1.まずはプロジェクト用のライブラリを導入するため、以下の設定を行う。
 ① build.gradleファイルを開いて以下のようにkey-valueの形で設定します。

   dependencies {
      implementation('org.springframework.boot:spring-boot-starter-data-redis')
      implementation('org.springframework.boot:spring-boot-starter-web')
      testImplementation('org.springframework.boot:spring-boot-starter-test')
   }

2.redis サービスの配置
  application.propertiesを開く、以下の内容を追加する。(パスワードなくてもいいです。)

   server.port=8088
   spring.redis.database=0
   spring.redis.host=localhost
   spring.redis.port=6379
   spring.redis.password=
   spring.redis.timeout=200

 3.実装したソースです。
   
   まずはRedisConfig.javaを作って、

@Configuration
public class RedisConfig {

@Bean
public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory){
    RedisTemplate<String,Object> template = new RedisTemplate <>();
    template.setConnectionFactory(factory);

    Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new  Jackson2JsonRedisSerializer(Object.class);
    ObjectMapper om = new ObjectMapper();
    om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    jackson2JsonRedisSerializer.setObjectMapper(om);

    StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
    // key采用String的序列化方式
    template.setKeySerializer(stringRedisSerializer);
    // hash的key也采用String的序列化方式
    template.setHashKeySerializer(stringRedisSerializer);
    // value序列化方式采用jackson
    template.setValueSerializer(jackson2JsonRedisSerializer);
    // hash的value序列化方式采用jackson
    template.setHashValueSerializer(jackson2JsonRedisSerializer);
    template.afterPropertiesSet();
    return template;
  }
}

 後はRedisService.javaを作って、いろんな機能を実装します。

    @Service
    public class RedisService {

      /**
       * 注入redisTemplate bean
       */
      @Autowired
      private RedisTemplate<String,Object> redisTemplate;

      /**
       * 删除缓存
       *
       * @param key 可以传一个值 或多个
       */
      @SuppressWarnings("unchecked")
      public void del(String... key) {
        if (key != null && key.length > 0) {
          if (key.length == 1) {
            redisTemplate.delete(key[0]);
          } else {
            redisTemplate.delete(CollectionUtils.arrayToList(key));
          }
        }
      }

      /**
       * 普通缓存获取
       *
           * @param key 键
       * @return 值
           */
      public Object get(String key) {
        return key == null ? null : redisTemplate.opsForValue().get(key);
      }

      /**
       * 普通缓存放入
       *
       * @param key   键
       * @param value 值
       * @return true成功 false失败
       */
      public boolean set(String key, Object value) {
        try {
          redisTemplate.opsForValue().set(key, value);
          return true;
        } catch (Exception e) {
          e.printStackTrace();
          return false;
        }
      }
}

 最後に機能をテストため、コントローラを作ってみました。

@RestController
@RequestMapping(value = "/redis")
public class RedisController {
    /**
     * 注入redisTemplate bean
     */
      @Autowired
      private RedisService redisService;

      /**
       * 保存(更新)数据
       * @param key
       * @param value
       * @return
       */
      @RequestMapping(value="/add",method=RequestMethod.GET)
      public String add(String key,String value) {
          redisService.set(key, value);

          return "add successfully";
      }

      /**
       * 删除指定数据
       * @param key
       * @return
       */
      @GetMapping(value="/delete")
      public String delete(String key) {

          redisService.del(key);
          return "delete successfully";
      }

      /**
       * 读取指定数据
       * @param key
       * @return
       */
      @GetMapping(value="/get")
      public String get(String key) {
          return redisService.get(key)==null ? "data don't exist!" :     redisService.get(key).toString();
      }
}

テスト

 まずはRedisサーバーをredis-server redis.windows.confで起動します。以下のようなです。
 redis.jpg

その後、プロジェクトをスタートする。
 
 ① 保存機能をテスト
  テストテータ:{city:tokyo}
URL : localhost:8088/redis/add?key=city&value=tokyo
ブラウザでテストURLを入力し、アクセスすると正常に保存することが見えます。
  保存数据.jpg

② 取得機能をテスト
  URL : localhost:8088/redis/get?key=city
ほら、先に保存したデータを取得します。

读取数据.jpg

 ③ 削除機能をテスト
  URL : localhost:8088/redis/delete?key=city

保存されたデータを削除します。

删除数据.jpg

テストはここまでです。

最後に

この記事に興味があれば、ぜひ、ここにソースをダウンロードします。

本来の記事サイト:http://160.16.146.245/u/hyman/blogs/11

以上
 

 

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

【Spring Data JPA】登録時に独自シーケンスでカスタムIDを採番

はじめに

「Spring Data JPA」でデータを登録するときに、
シーケンスで採番したものに接頭辞(プレフィックス)つけた時のコードをまとめています。

 

環境

Java 8
PostgreSQL 10.5

 

やったこと

独自Generatorを実装する。(接頭辞を付ける人)

SequenceStyleGeneratorを継承します。
シーケンスで採番をするのは内部(スーパークラス)の処理をそのまま使います。
独自Generatorは採番されたものに prefix を付ける役割です。

EntityにGeneratorの指定とパラメータを記載する

Entityでシーケンスの指定や接頭辞、フォーマットの指定をします。
シーケンスを指定しないと hibernate_sequence を使おうとします。
(ここでちょっとハマった)

ソース

実装したソースです。

独自Generator

import java.io.Serializable;
import java.util.Properties;

import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.id.enhanced.SequenceStyleGenerator;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.LongType;
import org.hibernate.type.Type;

public class PrefixedIdGenerator extends SequenceStyleGenerator {

    public static final String VALUE_PREFIX_PARAMETER = "valuePrefix";
    public static final String VALUE_PREFIX_DEFAULT = "";
    private String valuePrefix;


    public static final String NUMBER_FORMAT_PARAMETER = "numberFormat";
    public static final String NUMBER_FORMAT_DEFAULT = "%d";

    private String numberFormat;

    @Override
    public Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException {
        return valuePrefix + String.format(numberFormat, super.generate(session, object));
    }

    @Override
    public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException {
        super.configure(LongType.INSTANCE, params, serviceRegistry);
        valuePrefix = ConfigurationHelper.getString(VALUE_PREFIX_PARAMETER, params, VALUE_PREFIX_DEFAULT);
        numberFormat = ConfigurationHelper.getString(NUMBER_FORMAT_PARAMETER, params, NUMBER_FORMAT_DEFAULT);
    }
}

Entity

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import lombok.Data;

import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;

@Entity
@Data
@Table(name = "trial")
public class Trial {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_trial")
    @GenericGenerator(
            name = "seq_trial",
            strategy = "PrefixedIdGenerator",
            parameters = {
                @Parameter(name = PrefixedIdGenerator.SEQUENCE_PARAM, value = "seq_trial"),
                @Parameter(name = PrefixedIdGenerator.VALUE_PREFIX_PARAMETER, value = "B_"),
                @Parameter(name = PrefixedIdGenerator.NUMBER_FORMAT_PARAMETER, value = "%05d") })
    @Column(name = "trial_id")
    private String trialId;

    @Column(name = "trial_name")
    private String trialName;
}

Service

@Service
public class TrialService {

    @Autowired
    private TrialRepository repository;

    @Transactional
    public void insert() {

        Trial entity = new Trial();
        entity.setTrialName("trial_xxxxxxxx");

        repository.save(entity);
    }
}

実行時ログ

2019/05/24 17:54:18.505 [http-nio-8099-exec-1] DEBUG SqlStatementLogger 92 : 
    select
        nextval ('seq_test')
2019/05/24 17:54:22.313 [http-nio-8099-exec-1] DEBUG SqlStatementLogger 92 : 
    insert 
    into
        trial
        (trial_name, trial_id) 
    values
        (?, ?)
2019/05/24 17:54:22.318 [http-nio-8099-exec-1] TRACE BasicBinder 65 : binding parameter [1] as [VARCHAR] - [trial_xxxxxxxx]
2019/05/24 17:54:22.319 [http-nio-8099-exec-1] TRACE BasicBinder 65 : binding parameter [2] as [VARCHAR] - [B_00001]

参考にしたサイト

How to Implement a Custom, Sequence-Based ID Generator

 

以上

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

Spring BootのHot Swapping設定

最近Spring Bootに入門しまして、Hot Swappingを設定しようとして調べていたら、記事によって若干情報が古かったり設定が足りなかったりして意外と苦戦したので、ここにまとめておきます。

環境情報

  • Mac
  • IntelliJ IDEA 2019.1.2 (Community Edition)
  • Spring Boot Gradle Plugin 2.1.4
  • Spring Boot Devtools 2.1.4

設定手順

PreferencesでBuild project automaticallyにチェックを入れます。

image.png

Shift+Command+Aでコマンド検索ウィンドウを表示し、Registry...を実行します。

image.png

compiler.automake.allow.when.app.runningにチェックを入れます。

image.png

build.gradleで以下の設定を追加します。

bootRun {
    sourceResources sourceSets.main
}

application.propertiesに以下を追加します(テンプレートエンジンにThymeleafを使用している場合)。

spring.thymeleaf.cache = false

リロードの動きについて

例えば、src/main/java/hello/GreetingController.javaのソースに変更を加えると、アプリケーションがリロードされます。
自分の環境ではリロードが走るにはソースファイルをCommand+Sで保存してあげる必要がありました。

...
サービスがシャットダウンされた
2019-05-24 16:18:26.310  INFO 37740 --- [      Thread-33] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'

アプリが再起動した
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.4.RELEASE)

2019-05-24 16:18:31.397  INFO 37740 --- [  restartedMain] hello.Application                        : Starting Application on xxx.local with PID 37740 (/Users/takehiro/Documents/git/sprint-web-mvc/build/classes/java/main started by takehiro in /Users/user/Documents/git/sprint-web-mvc)
2019-05-24 16:18:31.398  INFO 37740 --- [  restartedMain] hello.Application                        : No active profile set, falling back to default profiles: default
2019-05-24 16:18:31.563  INFO 37740 --- [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
...

また、静的ファイルであるsrc/main/resources/templates/greeting.htmlに変更を加えたときは、ブラウザをリロードすることで反映されました。
こちらの場合アプリケーションのリロードは発生しませんでした。

ライブリロード

ブラウザのLiveReloadエクステンションと組み合わせることで、いちいちブラウザのリロードボタンをクリックしなくても自動でリロードをさせることができるようになります。
これはSpring Boot DevtoolsにLiveReloadサーバーが組み込まれているためです。

エクステンションはこちらからインストールできます。

先にアプリケーションを起動しておき、ブラウザで画面を表示します。
LiveReloadエクステンションのアイコンをクリックし、ステータスがLiveReload is connected, click to disableになっていることを確認します。

image.png

これでライブリロードが実現されます。

livereload.gif

参考

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

Tomcatで「サーバーの再起動があるかもしれません」と言われます

javaのeclipse 安定版2018-09 使用pcはThinkpad e585です。

サーバーを再起動しないと古いファイルを読み込んでいるのか
サーブレットやJSPファイルの変更箇所が反映されません。
表示する文字列を一文字だけ変更しても再起動が必要になります。
再起動を2回しないと反映されないこともあります。
また、何度か再起動をしていると「ポートが既に使用されています」というエラーがでます。
そのときにポート番号を変更しても、変更したポート番号で同じエラーがでます。

プログラミングスクールに通っているのですが、他の人は再起動なしで変更内容が反映されています。
スクールの指導者に尋ねても原因がわかりませんでした。
metadataの削除やeclipseをzipファイルから新しいものに入れなおしてみましたが改善されませんでした。

再起動なしで、もしくは再起動1回で変更内容が反映される方法がありましたら教えていただきたいです。

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

Minecraft で「だるまさんがころんだ」ができるプラグインを作っていく#1

Minecraftで「だるまさんがころんだ」を作ってみました。需要はないけどなかなか見かけないから作ってみたかった
コードはきっとまだ短くできたり改善できたりするだろうけどとりあえず自分のかけた分で

環境

  • IntelliJ IDEA CE
  • MacBook Pro
  • Minecraft 1.13.2

書き始める

メインクラス

public final class Daruma extends JavaPlugin{
    @Override
    public void onEnable() {
        getLogger().info("だるま起動しました");
        // Plugin startup logic
    }
    @Override
    public void onDisable() {
        // Plugin shutdown logic
    }
}

メインクラス。ここから色々書く

コマンドクラス

public class Daruma_commands implements CommandExecutor {
    @Override
    public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
        if(!(sender instanceof Player)) {//OPがあるか否か
            return false;
        }
        return true;
    }
}

(sender instanceof Player)
これは、「コマンドを実行した者がOPであるか」というものです。
上記のIF文では、「実行者がOPでなければ、コマンドを実行しない」ということに
なります。


ところで

例えばマイクラ界では有名なHypixelのサーバーのパーティコマンド。あれを実行するとき、
/party 〜〜
って打ちますよね。
この、コマンドの最初の部分に必ずある「party」みたいなやつ
超やってみてぇ


というわけで

public class Daruma_commands implements CommandExecutor {
    @Override
    public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
        if(!(sender instanceof Player)) {//OPがあるか否か
            return false;
        }
        if(args.length==1) {//lengthが1であるか
            switch (args[0].toLowerCase()) {
                case "start"://length1が"start"だった場合
                //ここに処理を書く
                default:
                    //ここにも
            }
        }
        return true;
    }
}
public final class Daruma extends JavaPlugin {
    @Override
    public void onEnable() {
        getLogger().info("だるま起動しました");
        Objects.requireNonNull(this.getCommand("Daruma")).setExecutor(new Daruma_commands());
        // Plugin startup logic
    }
    @Override
    public void onDisable() {
        // Plugin shutdown logic
    }
}

とりあえずメインクラスには/darumaでコマンドが実行されるように登録します。
そしてコマンドを処理するクラスには、コマンドのlengthを取得して、それが1であるかどうか、という処理を
書きます。
例えば/daruma helloworldと打った時、dramaがlength0で、helloworld
length1になるので、lengthは1で、判定はtrueになります。
さらにそのIF文の中にあるcaseは、length1(上の例だとhello worldの部分)
が"start"という処理であるかどうか、というものです。
ここから、他のコマンドと同時進行で処理を書いて行きますが、全部を一発で書くとクソほど長くなるので今回はここまで。#2に続きます。

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

Desktop : OpenCV SqrBox Filter

Goal

Test OpenCV sqrbox filter.

OpenCV_SqrBoxFilter.java
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.image.BufferedImage;

public class OpenCV_SqrBoxFilter {
    static{System.loadLibrary(Core.NATIVE_LIBRARY_NAME);}
    private JFrame frmjavaSwing;
    double alpha = 2;
    double beta = 50;

    /**
        * Launch the application .
        */
    public static void main(String[] args){

        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    OpenCV_SqrBoxFilter window = new OpenCV_SqrBoxFilter();
                    window.frmjavaSwing.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
        *   Create the application.
        */
    public OpenCV_SqrBoxFilter() {
        init();
    }

    /**
     * Initialize the contents of the frame.
     */
    private void init() {
        final Mat source = Imgcodecs.imread(
                "D:\\projects\\Java\\OpenCV_Samples\\resource\\imgs\\lena.jpg");

        BufferedImage image=matToBufferedImage(source);

        frmjavaSwing = new JFrame();
        frmjavaSwing.setTitle("讀取影像至Java Swing視窗");
        frmjavaSwing.setBounds(100, 100, 520, 550);
        frmjavaSwing.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frmjavaSwing.getContentPane().setLayout(null);

        final JLabel showAlphaValue = new JLabel("1");
        showAlphaValue.setBounds(277, 10, 46, 15);
        frmjavaSwing.getContentPane().add(showAlphaValue);

        final JLabel lblNewLabel = new JLabel("");
        lblNewLabel.setBounds(10, 68, 438, 438);
        lblNewLabel.setIcon(new ImageIcon(image));
        frmjavaSwing.getContentPane().add(lblNewLabel);

        final JSlider slider_alpha = new JSlider();
        slider_alpha.setMinimum(1);
        slider_alpha.setValue(1);
        slider_alpha.addChangeListener(new ChangeListener() {
            public void stateChanged(ChangeEvent arg0) {
                //System.out.println(slider_alpha.getValue());
                showAlphaValue.setText(slider_alpha.getValue()+"");
                BufferedImage newImage=matToBufferedImage(matConvertTo(source,slider_alpha.getValue()));
                lblNewLabel.setIcon(new ImageIcon(newImage));
            }
        });
        slider_alpha.setBounds(63, 10, 200, 25);
        frmjavaSwing.getContentPane().add(slider_alpha);

        JLabel lblAlpha = new JLabel("ksize");
        lblAlpha.setBounds(10, 20, 46, 15);
        frmjavaSwing.getContentPane().add(lblAlpha);

    }
    public Mat matConvertTo(Mat src,double alpha){
        Mat dst=new Mat();
        Imgproc.sqrBoxFilter(src, dst, CvType.CV_8U, new Size(alpha,alpha));
        return dst;

    }

    public BufferedImage matToBufferedImage(Mat matrix) {
        int cols = matrix.cols();
        int rows = matrix.rows();
        int elemSize = (int)matrix.elemSize();
        byte[] data = new byte[cols * rows * elemSize];
        int type;
        matrix.get(0, 0, data);
        switch (matrix.channels()) {
            case 1:
                type = BufferedImage.TYPE_BYTE_GRAY;
                break;
            case 3:
                type = BufferedImage.TYPE_3BYTE_BGR;
                // bgr to rgb
                byte b;
                for(int i=0; i<data.length; i=i+3) {
                    b = data[i];
                    data[i] = data[i+2];
                    data[i+2] = b;
                }
                break;
            default:
                return null;
        }
        BufferedImage image2 = new BufferedImage(cols, rows, type);
        image2.getRaster().setDataElements(0, 0, cols, rows, data);
        return image2;
    }
}
Result

opencv_sqr_box_filter.JPG

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

JavaはPDFテキストと画像の抽出を実現します

PDFファイルは常に多くの優れた情報コンテンツを携帯するために使われています。これらの情報をより良く利用するためには、いくつかのツールを使ってPDFからテキストと画像情報を抽出する必要があります。以下はJavaを通してPDFを抽出するテキストと写真を紹介します。

ツール使用:
Jarパッケージ導入:
  • 方法1: Free Spire.Pdf for Javaのストレスをオフィシャルサイトからダウンロードした後、IDEA又はEclipseにおいてShift+Ctrl+Alt+Sに追加導入Spire.Pdf.jarパケットをプログラムに追加することで、jarファイルを伸張経路下のlibフォルダで取得することができる。jarパッケージの導入結果は以下の通り:

image.png

テストソースドキュメントは以下の通り:
image.png

Javaコードの例参照:

【例1】PDFのテキスト内容を抽出する

ステップ1: 名前空間を追加します;

import com.spire.pdf.*;
import java.io.FileWriter;

ステップ2: PDFのインスタンスを作成し、PDFソースファイルをロードする;

//Create the PDF
PdfDocument doc = new PdfDocument();
//Load the PDF file
doc.loadFromFile("data/Sample.pdf");

ステップ3: StringBuider法を使用して、PDFドキュメント全体を巡回巡回する文字バッファの例を定義する;

// Traverse the PDF
StringBuilder buffer = new StringBuilder();
for(int i = 1; i<doc.getPages().getCount(); i++){
    PdfPageBase page = doc.getPages().get(i);
    buffer.append(page.extractText());
}

ステップ4: 1つのwriterのインスタンスを定義してバッファエリアにデータを書き込み、write()を使ってバッファエリアのデータをtext.txtファイルに書き込み、保存する。

//save text
String fileName = "output/text.txt";
FileWriter writer = new FileWriter(fileName);
writer.write(buffer.toString());
writer.flush();
writer.close();

テキスト抽出結果:
image.png

【例2】PDF中のピクチャを抽出する

ステップ1: 名前空間を追加します;

import com.spire.pdf.*;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;

ステップ2: PDFのインスタンスを作成し、PDFソースファイルをロードする;

        //Create the PDF
        PdfDocument pdf = new PdfDocument();
       //Load the PDF file
        pdf.loadFromFile("data/Sample.pdf");

ステップ3: forループはPDFの各ページを巡回し、extractImages()方法を使って指定ページの画像を取得し、最後にPNG形式で画像を保存します。

        // Declare an int variable
     int index = 0;
        // loop through the pages
        for (int i= 0;i< pdf.getPages().getCount(); i ++){
            //Get the PDF pages
            PdfPageBase page = pdf.getPages().get(i);
            // Extract images from a particular page 
            for (BufferedImage image : page.extractImages()) {
            //specify the file path and name
                File output = new File("output/" + String.format("Image_%d.png", index++));                
            //Save image as .png file    
            ImageIO.write(image, "PNG", output);
            }
        }

画像抽出結果:
image.png
image.png
image.png
image.png

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

Desktop : OpenCV Customized Filter

Goal

OpenCV Customized Filter.

import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;

public class OpenCV_Customized {

    static { System.loadLibrary(Core.NATIVE_LIBRARY_NAME);}
    private JFrame frmjavaSwing;

    /**
        * Launch the application.
        */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    OpenCV_Customized window = new OpenCV_Customized();
                    window.frmjavaSwing.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
        * Create the application.
        */
    public OpenCV_Customized(){
        init();
    }

    /**
        * Init tha contents of the frame.
        */
        private void init(){
            final Mat src = Imgcodecs.imread(
                    "D:\\projects\\Java\\OpenCV_Samples\\resource\\imgs\\lena.jpg");

            BufferedImage image=matToBufferedImage(src);

            frmjavaSwing = new JFrame();
            frmjavaSwing.setTitle("opencv ¦Û¤vªºfilter½m²ß");
            frmjavaSwing.setBounds(100, 100, 560, 620);
            frmjavaSwing.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frmjavaSwing.getContentPane().setLayout(null);

            final JLabel lblNewLabel = new JLabel("");
            lblNewLabel.setBounds(5, 60, image.getHeight()+10, image.getWidth()+10);
            lblNewLabel.setIcon(new ImageIcon(image));
            frmjavaSwing.getContentPane().add(lblNewLabel);

            JButton btnR0 = new JButton("C0");
            btnR0.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent arg0) {
                    BufferedImage newImage=matToBufferedImage(Convolution(src,0));
                    lblNewLabel.setIcon(new ImageIcon(newImage));
                }
            });
            btnR0.setBounds(5, 10, 63, 23);
            frmjavaSwing.getContentPane().add(btnR0);

            JButton btnR1 = new JButton("C1");
            btnR1.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent arg0) {
                    BufferedImage newImage=matToBufferedImage(Convolution(src,1));
                    lblNewLabel.setIcon(new ImageIcon(newImage));
                }
            });
            btnR1.setBounds(72, 10, 63, 23);
            frmjavaSwing.getContentPane().add(btnR1);

            JButton btnR2 = new JButton("C2");
            btnR2.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent arg0) {
                    BufferedImage newImage=matToBufferedImage(Convolution(src,2));
                    lblNewLabel.setIcon(new ImageIcon(newImage));
                }
            });
            btnR2.setBounds(136, 10, 63, 23);
            frmjavaSwing.getContentPane().add(btnR2);

            JButton btnR3 = new JButton("C3");
            btnR3.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent arg0) {
                    BufferedImage newImage=matToBufferedImage(Convolution(src,3));
                    lblNewLabel.setIcon(new ImageIcon(newImage));
                }
            });
            btnR3.setBounds(202, 10, 63, 23);
            frmjavaSwing.getContentPane().add(btnR3);

            JButton btnR4 = new JButton("C4");
            btnR4.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent arg0) {
                    BufferedImage newImage=matToBufferedImage(Convolution(src,4));
                    lblNewLabel.setIcon(new ImageIcon(newImage));
                }
            });
            btnR4.setBounds(268, 10, 63, 23);
            frmjavaSwing.getContentPane().add(btnR4);

            JButton btnR5 = new JButton("C5");
            btnR5.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent arg0) {
                    BufferedImage newImage=matToBufferedImage(Convolution(src,5));
                    lblNewLabel.setIcon(new ImageIcon(newImage));
                }
            });
            btnR5.setBounds(336, 10, 63, 23);
            frmjavaSwing.getContentPane().add(btnR5);
        }

    public Mat Convolution(Mat source,int type){
        Mat kernel =new Mat(3,3, CvType.CV_32F);
        if (type==0){
            kernel.put(0, 0, new float[]{0,-1,5});
            kernel.put(1, 0, new float[]{-1,4,-1});
            kernel.put(2, 0, new float[]{0,-1,3});

        }else if (type==1){
            kernel.put(0, 0, new float[]{0,-1,5});
            kernel.put(1, 0, new float[]{-1,4,-1});
            kernel.put(2, 0, new float[]{0,-1,6});


        }else if (type==2){
            kernel.put(0, 0, new float[]{0,-1,5});
            kernel.put(1, 0, new float[]{-1,4,-1});
            kernel.put(2, 0, new float[]{0,-1,9});


        }else if (type==3){
            kernel.put(0, 0, new float[]{-1,-2,1});
            kernel.put(1, 0, new float[]{0,0,0});
            kernel.put(2, 0, new float[]{1,2,1});



        }else if (type==4){
            kernel.put(0, 0, new float[]{-3,-0,-3});
            kernel.put(1, 0, new float[]{-10,0,10});
            kernel.put(2, 0, new float[]{-3,10,3});



        }else if (type==5){
            kernel.put(0, 0, new float[]{-3,-0,3});
            kernel.put(1, 0, new float[]{-10,0,10});
            kernel.put(2, 0, new float[]{-3,10,3});

        }
        Mat destination=new Mat(source.rows(),source.cols(),source.type());
        Imgproc.filter2D(source, destination, -1, kernel);
        return destination;

    }

    public BufferedImage matToBufferedImage(Mat matrix) {
        int cols = matrix.cols();
        int rows = matrix.rows();
        int elemSize = (int)matrix.elemSize();
        byte[] data = new byte[cols * rows * elemSize];
        int type;
        matrix.get(0, 0, data);
        switch (matrix.channels()) {
            case 1:
                type = BufferedImage.TYPE_BYTE_GRAY;
                break;
            case 3:
                type = BufferedImage.TYPE_3BYTE_BGR;
                // bgr to rgb
                byte b;
                for(int i=0; i<data.length; i=i+3) {
                    b = data[i];
                    data[i] = data[i+2];
                    data[i+2] = b;
                }
                break;
            default:
                return null;
        }
        BufferedImage image2 = new BufferedImage(cols, rows, type);
        image2.getRaster().setDataElements(0, 0, cols, rows, data);
        return image2;
    }

}
Result

opencv_customized.JPG

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

Desktop : OpenCV Emboss

Goal

Test OpenCV Emboss.

OpenCV_Emboss.java
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;

public class OpenCV_Emboss {
    static{ System.loadLibrary(Core.NATIVE_LIBRARY_NAME); }
    private JFrame frmjavaSwing;

    /**
        * Launch the application.
        */
    public static void main(String[] args){
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    OpenCV_Emboss window = new OpenCV_Emboss();
                    window.frmjavaSwing.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
        * Create the application.
        */
    public OpenCV_Emboss(){
        init();
    }

    /**
        * Initialize the contents of the frame.
        */
    public void init(){
        final Mat source = Imgcodecs.imread("D:\\projects\\Java\\OpenCV_Samples\\resource\\imgs\\lena.jpg");

        BufferedImage image=matToBufferedImage(source);

        frmjavaSwing = new JFrame();
        frmjavaSwing.setTitle("opencv 浮雕練習");
        frmjavaSwing.setBounds(100, 100, 560, 620);
        frmjavaSwing.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frmjavaSwing.getContentPane().setLayout(null);

        final JLabel lblNewLabel = new JLabel("");
        lblNewLabel.setBounds(5, 60, image.getHeight()+10, image.getWidth()+10);
        lblNewLabel.setIcon(new ImageIcon(image));
        frmjavaSwing.getContentPane().add(lblNewLabel);

        JButton btnX = new JButton("浮雕處理");
        btnX.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                BufferedImage newImage=matToBufferedImage(Convolution(source));
                lblNewLabel.setIcon(new ImageIcon(newImage));
            }
        });
        btnX.setBounds(42, 10, 114, 23);
        frmjavaSwing.getContentPane().add(btnX);
    }

    public Mat Convolution(Mat source){
        Mat  kernel = new Mat(3,3, CvType.CV_32F);
        kernel.put(0, 0, new float[]{1,0,0});
        kernel.put(1, 0, new float[]{0,0,0});
        kernel.put(2, 0, new float[]{0,0,-1});
        Mat destination=new Mat(source.rows(),source.cols(),source.type());
        Imgproc.filter2D(source, destination, -1, kernel);
        return destination;

    }
    public BufferedImage matToBufferedImage(Mat matrix) {
        int cols = matrix.cols();
        int rows = matrix.rows();
        int elemSize = (int)matrix.elemSize();
        byte[] data = new byte[cols * rows * elemSize];
        int type;
        matrix.get(0, 0, data);
        switch (matrix.channels()) {
            case 1:
                type = BufferedImage.TYPE_BYTE_GRAY;
                break;
            case 3:
                type = BufferedImage.TYPE_3BYTE_BGR;
                // bgr to rgb
                byte b;
                for(int i=0; i<data.length; i=i+3) {
                    b = data[i];
                    data[i] = data[i+2];
                    data[i+2] = b;
                }
                break;
            default:
                return null;
        }
        BufferedImage image2 = new BufferedImage(cols, rows, type);
        image2.getRaster().setDataElements(0, 0, cols, rows, data);
        return image2;
    }

}
Result

opencv_emboss.JPG

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

Desktop : OpenCV Kirsch Filter

Goal

Test OpenCV Kirsch Filter.

import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;

public class OpenCV_KirschFilter {

    static{ System.loadLibrary(Core.NATIVE_LIBRARY_NAME); }
    private JFrame frmjavaSwing;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {

        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    OpenCV_KirschFilter window = new OpenCV_KirschFilter();
                    window.frmjavaSwing.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the application.
     */
    public OpenCV_KirschFilter() {
        initialize();
    }

    /**
     * Initialize the contents of the frame.
     */
    private void initialize() {
        final Mat source = Imgcodecs.imread("D:\\projects\\Java\\OpenCV_Samples\\resource\\imgs\\baboon.jpg");

        BufferedImage image=matToBufferedImage(source);

        frmjavaSwing = new JFrame();
        frmjavaSwing.setTitle("opencv Kirsch filter練習");
        frmjavaSwing.setBounds(100, 100, 560, 620);
        frmjavaSwing.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frmjavaSwing.getContentPane().setLayout(null);

        final JLabel lblNewLabel = new JLabel("");
        lblNewLabel.setBounds(5, 60, image.getHeight()+10, image.getWidth()+10);
        lblNewLabel.setIcon(new ImageIcon(image));
        frmjavaSwing.getContentPane().add(lblNewLabel);

        JButton btnRK0 = new JButton("K0");
        btnRK0.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                BufferedImage newImage=matToBufferedImage(Convolution(source,0));
                lblNewLabel.setIcon(new ImageIcon(newImage));
            }
        });
        btnRK0.setBounds(5, 10, 63, 23);
        frmjavaSwing.getContentPane().add(btnRK0);

        JButton btnK1 = new JButton("K1");
        btnK1.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                BufferedImage newImage=matToBufferedImage(Convolution(source,1));
                lblNewLabel.setIcon(new ImageIcon(newImage));
            }
        });
        btnK1.setBounds(72, 10, 63, 23);
        frmjavaSwing.getContentPane().add(btnK1);

        JButton btnK2 = new JButton("K2");
        btnK2.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                BufferedImage newImage=matToBufferedImage(Convolution(source,2));
                lblNewLabel.setIcon(new ImageIcon(newImage));
            }
        });
        btnK2.setBounds(136, 10, 63, 23);
        frmjavaSwing.getContentPane().add(btnK2);

        JButton btnK3 = new JButton("K3");
        btnK3.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                BufferedImage newImage=matToBufferedImage(Convolution(source,3));
                lblNewLabel.setIcon(new ImageIcon(newImage));
            }
        });
        btnK3.setBounds(202, 10, 63, 23);
        frmjavaSwing.getContentPane().add(btnK3);

        JButton btnK4 = new JButton("K4");
        btnK4.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                BufferedImage newImage=matToBufferedImage(Convolution(source,4));
                lblNewLabel.setIcon(new ImageIcon(newImage));
            }
        });
        btnK4.setBounds(268, 10, 63, 23);
        frmjavaSwing.getContentPane().add(btnK4);

        JButton btnK5 = new JButton("K5");
        btnK5.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                BufferedImage newImage=matToBufferedImage(Convolution(source,5));
                lblNewLabel.setIcon(new ImageIcon(newImage));
            }
        });
        btnK5.setBounds(336, 10, 63, 23);
        frmjavaSwing.getContentPane().add(btnK5);

        JButton btnK6 = new JButton("K6");
        btnK6.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                BufferedImage newImage=matToBufferedImage(Convolution(source,6));
                lblNewLabel.setIcon(new ImageIcon(newImage));
            }
        });
        btnK6.setBounds(403, 10, 63, 23);
        frmjavaSwing.getContentPane().add(btnK6);

        JButton btnK7 = new JButton("K7");
        btnK7.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                BufferedImage newImage=matToBufferedImage(Convolution(source,7));
                lblNewLabel.setIcon(new ImageIcon(newImage));
            }
        });
        btnK7.setBounds(476, 10, 63, 23);
        frmjavaSwing.getContentPane().add(btnK7);
    }

    public Mat Convolution(Mat source,int type){
        Mat kernel =new Mat(3,3, CvType.CV_32F);
        if (type==0){
            kernel.put(0, 0, new float[]{-3,-3,5});
            kernel.put(1, 0, new float[]{-3,0,5});
            kernel.put(2, 0, new float[]{-3,-3,5});


        }else if (type==1){
            kernel.put(0, 0, new float[]{-3,5,5});
            kernel.put(1, 0, new float[]{-3,0,5});
            kernel.put(2, 0, new float[]{-3,-3,-3});

        }else if (type==2){
            kernel.put(0, 0, new float[]{5,5,5});
            kernel.put(1, 0, new float[]{-3,0,-3});
            kernel.put(2, 0, new float[]{-3,-3,-3});

        }else if (type==3){
            kernel.put(0, 0, new float[]{5,5,-3});
            kernel.put(1, 0, new float[]{5,0,-3});
            kernel.put(2, 0, new float[]{-3,-3,-3});

        }else if (type==4){
            kernel.put(0, 0, new float[]{5,-3,-3});
            kernel.put(1, 0, new float[]{5,0,-3});
            kernel.put(2, 0, new float[]{5,-3,-3});


        }else if (type==5){
            kernel.put(0, 0, new float[]{-3,-3,-3});
            kernel.put(1, 0, new float[]{5,0,-3});
            kernel.put(2, 0, new float[]{5,5,-3});


        }else if (type==6){
            kernel.put(0, 0, new float[]{-3,-3,-3});
            kernel.put(1, 0, new float[]{-3,0,-3});
            kernel.put(2, 0, new float[]{5,5,5});


        }else if (type==7){
            kernel.put(0, 0, new float[]{-3,-3,-3});
            kernel.put(1, 0, new float[]{-3,0,5});
            kernel.put(2, 0, new float[]{-3,5,5});

        }
        Mat destination=new Mat(source.rows(),source.cols(),source.type());
        Imgproc.filter2D(source, destination, -1, kernel);
        return destination;

    }

    public BufferedImage matToBufferedImage(Mat matrix) {
        int cols = matrix.cols();
        int rows = matrix.rows();
        int elemSize = (int)matrix.elemSize();
        byte[] data = new byte[cols * rows * elemSize];
        int type;
        matrix.get(0, 0, data);
        switch (matrix.channels()) {
            case 1:
                type = BufferedImage.TYPE_BYTE_GRAY;
                break;
            case 3:
                type = BufferedImage.TYPE_3BYTE_BGR;
                // bgr to rgb
                byte b;
                for(int i=0; i<data.length; i=i+3) {
                    b = data[i];
                    data[i] = data[i+2];
                    data[i+2] = b;
                }
                break;
            default:
                return null;
        }
        BufferedImage image2 = new BufferedImage(cols, rows, type);
        image2.getRaster().setDataElements(0, 0, cols, rows, data);
        return image2;
    }
}
Result

opencv_kirsch_filter.JPG

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

Desktop : OpenCV Robinson Filter

Goal

Test OpenCV robinson filter.

OpenCV_Robinson_Filter.java
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;

public class OpenCV_Robinson_Filter {

    static {System.loadLibrary(Core.NATIVE_LIBRARY_NAME);}
    private JFrame frmjavaSwing;

    /**
        * Lunch the application.
        */
    public static void main(String[] args){
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    OpenCV_Robinson_Filter window = new OpenCV_Robinson_Filter();
                    window.frmjavaSwing.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
        * Create the application.
        */
    public OpenCV_Robinson_Filter(){
        init();
    }

    /**
        * Init the contents of the frame.
        */
    private void init(){
        final Mat source = Imgcodecs.imread(
                "D:\\projects\\Java\\OpenCV_Samples\\resource\\imgs\\lena.jpg");

        BufferedImage image=matToBufferedImage(source);

        frmjavaSwing = new JFrame();
        frmjavaSwing.setTitle("opencv Robinson filter練習");
        frmjavaSwing.setBounds(100, 100, 560, 620);
        frmjavaSwing.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frmjavaSwing.getContentPane().setLayout(null);

        final JLabel lblNewLabel = new JLabel("");
        lblNewLabel.setBounds(5, 60, image.getHeight()+10, image.getWidth()+10);
        lblNewLabel.setIcon(new ImageIcon(image));
        frmjavaSwing.getContentPane().add(lblNewLabel);

        JButton btnR0 = new JButton("R0");
        btnR0.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                BufferedImage newImage=matToBufferedImage(Convolution(source,0));
                lblNewLabel.setIcon(new ImageIcon(newImage));
            }
        });
        btnR0.setBounds(5, 10, 63, 23);
        frmjavaSwing.getContentPane().add(btnR0);

        JButton btnR1 = new JButton("R1");
        btnR1.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                BufferedImage newImage=matToBufferedImage(Convolution(source,1));
                lblNewLabel.setIcon(new ImageIcon(newImage));
            }
        });
        btnR1.setBounds(72, 10, 63, 23);
        frmjavaSwing.getContentPane().add(btnR1);

        JButton btnR2 = new JButton("R2");
        btnR2.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                BufferedImage newImage=matToBufferedImage(Convolution(source,2));
                lblNewLabel.setIcon(new ImageIcon(newImage));
            }
        });
        btnR2.setBounds(136, 10, 63, 23);
        frmjavaSwing.getContentPane().add(btnR2);

        JButton btnR3 = new JButton("R3");
        btnR3.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                BufferedImage newImage=matToBufferedImage(Convolution(source,3));
                lblNewLabel.setIcon(new ImageIcon(newImage));
            }
        });
        btnR3.setBounds(202, 10, 63, 23);
        frmjavaSwing.getContentPane().add(btnR3);

        JButton btnR4 = new JButton("R4");
        btnR4.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                BufferedImage newImage=matToBufferedImage(Convolution(source,4));
                lblNewLabel.setIcon(new ImageIcon(newImage));
            }
        });
        btnR4.setBounds(268, 10, 63, 23);
        frmjavaSwing.getContentPane().add(btnR4);

        JButton btnR5 = new JButton("R5");
        btnR5.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                BufferedImage newImage=matToBufferedImage(Convolution(source,5));
                lblNewLabel.setIcon(new ImageIcon(newImage));
            }
        });
        btnR5.setBounds(336, 10, 63, 23);
        frmjavaSwing.getContentPane().add(btnR5);

        JButton btnR6 = new JButton("R6");
        btnR6.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                BufferedImage newImage=matToBufferedImage(Convolution(source,6));
                lblNewLabel.setIcon(new ImageIcon(newImage));
            }
        });
        btnR6.setBounds(403, 10, 63, 23);
        frmjavaSwing.getContentPane().add(btnR6);

        JButton btnR7 = new JButton("R7");
        btnR7.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                BufferedImage newImage=matToBufferedImage(Convolution(source,7));
                lblNewLabel.setIcon(new ImageIcon(newImage));
            }
        });
        btnR7.setBounds(476, 10, 63, 23);
        frmjavaSwing.getContentPane().add(btnR7);
    }

    public Mat Convolution(Mat source,int type){
        Mat kernel =new Mat(3,3, CvType.CV_32F);
        if (type==0){
            kernel.put(0, 0, new float[]{-1,0,1});
            kernel.put(1, 0, new float[]{-2,0,2});
            kernel.put(2, 0, new float[]{-1,0,1});

        }else if (type==1){
            kernel.put(0, 0, new float[]{0,1,2});
            kernel.put(1, 0, new float[]{-1,0,1});
            kernel.put(2, 0, new float[]{-2,-1,0});


        }else if (type==2){
            kernel.put(0, 0, new float[]{1,2,1});
            kernel.put(1, 0, new float[]{0,0,0});
            kernel.put(2, 0, new float[]{-1,-2,-1});


        }else if (type==3){
            kernel.put(0, 0, new float[]{2,1,0});
            kernel.put(1, 0, new float[]{1,0,-1});
            kernel.put(2, 0, new float[]{0,-1,-2});


        }else if (type==4){
            kernel.put(0, 0, new float[]{1,0,-1});
            kernel.put(1, 0, new float[]{2,0,-2});
            kernel.put(2, 0, new float[]{1,0,-1});


        }else if (type==5){
            kernel.put(0, 0, new float[]{0,-1,-2});
            kernel.put(1, 0, new float[]{1,0,-1});
            kernel.put(2, 0, new float[]{2,1,0});


        }else if (type==6){
            kernel.put(0, 0, new float[]{-1,-2,-1});
            kernel.put(1, 0, new float[]{0,0,0});
            kernel.put(2, 0, new float[]{1,2,1});


        }else if (type==7){
            kernel.put(0, 0, new float[]{-2,-1,0});
            kernel.put(1, 0, new float[]{-1,0,1});
            kernel.put(2, 0, new float[]{0,1,2});
        }
        Mat destination=new Mat(source.rows(),source.cols(),source.type());
        Imgproc.filter2D(source, destination, -1, kernel);
        return destination;

    }

    public BufferedImage matToBufferedImage(Mat matrix) {
        int cols = matrix.cols();
        int rows = matrix.rows();
        int elemSize = (int)matrix.elemSize();
        byte[] data = new byte[cols * rows * elemSize];
        int type;
        matrix.get(0, 0, data);
        switch (matrix.channels()) {
            case 1:
                type = BufferedImage.TYPE_BYTE_GRAY;
                break;
            case 3:
                type = BufferedImage.TYPE_3BYTE_BGR;
                // bgr to rgb
                byte b;
                for(int i=0; i<data.length; i=i+3) {
                    b = data[i];
                    data[i] = data[i+2];
                    data[i+2] = b;
                }
                break;
            default:
                return null;
        }
        BufferedImage image2 = new BufferedImage(cols, rows, type);
        image2.getRaster().setDataElements(0, 0, cols, rows, data);
        return image2;
    }
}
Result

opencv_robinson_filter.JPG

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

Desktop : OpenCV Scharr Filter

Goal

Test OpenCV Scharr Filter.

OpenCV_ScharrFilter.java
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;

public class OpenCV_ScharrFilter {

    static {System.loadLibrary(Core.NATIVE_LIBRARY_NAME);}

    private JFrame frmjavaSwing;

    /**
        *   Launch the application.
        */
    public static void main(String[] args){
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try{
                    OpenCV_ScharrFilter window = new OpenCV_ScharrFilter();
                    window.frmjavaSwing.setVisible(true);
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        });
    }

    /**
        * Create the application.
        */
    public OpenCV_ScharrFilter(){
        init();
    }

    /**
        *   Init the contents of the frame.
        */
    private void init(){
        final Mat src = Imgcodecs.imread(
                "D:\\projects\\Java\\OpenCV_Samples\\resource\\imgs\\lena.jpg");

        BufferedImage image = matToBufferedImage(src);
        frmjavaSwing = new JFrame();
        frmjavaSwing.setTitle("opencv Sharr filter練習");
        frmjavaSwing.setBounds(100, 100, 560, 620);
        frmjavaSwing.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frmjavaSwing.getContentPane().setLayout(null);

        final JLabel lblNewLabel = new JLabel("");
        lblNewLabel.setBounds(5, 60, image.getHeight()+10, image.getWidth()+10);
        lblNewLabel.setIcon(new ImageIcon(image));
        frmjavaSwing.getContentPane().add(lblNewLabel);

        JButton btnX = new JButton("水平處理");
        btnX.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                BufferedImage newImage=matToBufferedImage(Convolution(src,1));
                lblNewLabel.setIcon(new ImageIcon(newImage));
            }
        });
        btnX.setBounds(42, 10, 114, 23);
        frmjavaSwing.getContentPane().add(btnX);

        JButton btnY = new JButton("垂直處理");
        btnY.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                BufferedImage newImage=matToBufferedImage(Convolution(src,2));
                lblNewLabel.setIcon(new ImageIcon(newImage));
            }
        });
        btnY.setBounds(211, 10, 102, 23);
        frmjavaSwing.getContentPane().add(btnY);
    }

    public Mat Convolution(Mat source,int type){
        Mat kernel =new Mat(3,3, CvType.CV_32F);
        if (type==1){


            kernel.put(0, 0, new float[]{-3,-10,-3});
            kernel.put(1, 0, new float[]{0,0,0});
            kernel.put(2, 0, new float[]{3,10,3});
        }else if (type==2){

            kernel.put(0, 0, new float[]{-3,0,3});
            kernel.put(1, 0, new float[]{-10,0,10});
            kernel.put(2, 0, new float[]{-3,0,3});

        }
        Mat destination=new Mat(source.rows(),source.cols(),source.type());
        Imgproc.filter2D(source, destination, -1, kernel);
        return destination;

    }

    public BufferedImage matToBufferedImage(Mat matrix) {
        int cols = matrix.cols();
        int rows = matrix.rows();
        int elemSize = (int)matrix.elemSize();
        byte[] data = new byte[cols * rows * elemSize];
        int type;
        matrix.get(0, 0, data);
        switch (matrix.channels()) {
            case 1:
                type = BufferedImage.TYPE_BYTE_GRAY;
                break;
            case 3:
                type = BufferedImage.TYPE_3BYTE_BGR;
                // bgr to rgb
                byte b;
                for(int i=0; i<data.length; i=i+3) {
                    b = data[i];
                    data[i] = data[i+2];
                    data[i+2] = b;
                }
                break;
            default:
                return null;
        }
        BufferedImage image2 = new BufferedImage(cols, rows, type);
        image2.getRaster().setDataElements(0, 0, cols, rows, data);
        return image2;
    }
}
Result

opencv_scharr_filter.JPG

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

javaでaudioファイルの長さを取得する方法

audioファイルの長さを取得する方法

背景を簡単に説明

LINE Messaging APIを使って、チャネルトークという弊社ウェブ接客チャットツールとLINE公式アカウントを連動※させる際に、音声ファイルの長さ(duration)を取得するところでつまづいたので、共有。

※LINE公式アカウントでのエンドユーザーとの対話を、接客チャットプラットフォームであるチャネルトークで返信、声かけが可能になる。
サイトに設置した接客チャットからの問い合わせと、LINE公式アカウントからの問い合わせに、チャネルトークの管理者画面から対応可能

チャネルトークでアップロードされた音声ファイルをLINE公式アカウントでエンドユーザ側からも見えるように同期するのに、Messaging APIに音声ファイルを送るのだが音声ファイルの長さ(duration)も送らなくてはならない。

実装方法

ただ、この音声ファイルの長さをファイルから取得するようなAPIはない。

でも方法は簡単。自分で実装すれば良い。
音声ファイルから取得できる総フレーム数とフレームレートから計算すれば良い。

File file = new File(fileUrl);

try {
    // 音声ファイルのmetadataを取得する準備
    AudioInputStream stream = AudioSystem.getAudioInputStream(file);

    // 音声ファイルの総フレーム数
    long length = stream.getFrameLength();
    AudioFormat format = stream.getFormat();

    // frame -> 1秒あたりに処理するフレーム数
    float frame = format.getSampleRate();
    // 総フレーム数➗1秒あたりに処理するフレーム数 = 長さ 
    int duration = (int)(length/frame);

} catch (UnsupportedAudioFileException e) {
    return false;
}

色々探さないで、素直に最初からこれやればよかったかも。。。
とりあえず思ったよりも簡単でした!

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

Effective Java 第3版 第3章全てのオブジェクトに共通のメソッド まとめ

Java中級者以上の必須本である、Effective Java 第3版に Kindle版が出たので、まとめる。

前:Effective Java 第3版 第2章オブジェクトの生成と消滅
次:Effective Java 第3版 第4章クラスとインタフェース(作成中)

項目10 equalsをオーバーライドするときは一般契約に従う

  • equalsを間違ったやり方でオーバーライドしてしまうと、その結果は悲惨なものになる。
  • 問題を避ける最も簡単な方法は、オーバーライドしないこと。

次の条件のどれかに当てはなるなら、オーバーライドしないのが正しいやり方。

  • クラスの個々のインスタンスが本質的に一意である。
  • クラスが「論理的等価性」の検査を提供する必要がない。
  • スーパークラスがすでにequalsをオーバーライドしており、スーパークラスの振る舞いがこのクラスに対して適切である、
  • クラスがprivateあるいはパッケージプライベートであり、そのequalsメソッドが呼び出されないことが確かである。

equalsメソッドは同値関係を実装し、以下の性質を持つ

  • 反射的: nullではに任意の参照値xに対して、x.equals(x)はtrueを返さなければなりません。
  • 対照的: nullではない任意の参照値xとyに対して、y.equals(x)がtrueを返す場合のみ、x.equals(y)はtrueを返さなければなりません。
  • 推移的: nullでない任意の参照値x、y、zに対して、もし、x.equals(y)y.equals(z)がtrueを返すならば、x.equals(z)はtrueを返さなければなりません。
  • 整合的: nullでない任意の参照値x、yに対して、x.equals(y)の複数回の呼び出しは、equalsの比較で使われる情報に変更がなければ、一貫してtrueを返すか、一貫してfalseを返さなければなりません。
  • nullではない任意の参照値xに対して、x.equals(null)はfalseを返さなければなりません。
[Good]equalのオーバーライド例
public final class PhoneNumber {
    private final short areaCode, prefix, lineNum;

    public PhoneNumber(int areaCode, int prefix, int lineNum) {
        this.areaCode = rangeCheck(areaCode, 999, "area code");
        this.prefix = rangeCheck(prefix, 999, "prefix");
        this.lineNum = rangeCheck(lineNum, 9999, "line num");
    }

    private static short rangeCheck(int val, int max, String arg) {
        if (val < 0 || val > max) {
            throw new IllegalArgumentException(arg + ": " + val);
        }
        return (short) val;
    }

    // 【良い例】 equalのオーバーライド例
    @Override
    public boolean equals(Object o) {
        if (o == this) {
            // 自分自身のオブジェクトへの参照であるか?
            return true;
        }
        if (!(o instanceof PhoneNumber)) {
            // 正しい型であるか?
            return false;
        }
        // 正しい型でキャストする
        PhoneNumber pn = (PhoneNumber) o;
        // 意味のあるフォールドのそれぞれについて一致するか?
        return pn.lineNum == lineNum && pn.prefix == prefix && pn.areaCode == areaCode;
    }
}
IntelliJで自動生成されるequalsメソッド
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        PhoneNumber that = (PhoneNumber) o;
        return areaCode == that.areaCode &&
                prefix == that.prefix &&
                lineNum == that.lineNum;
    }
  • GoogleのAutoValueフレームワークを使うことで、アノテーションによるequalsとhashCodeの自動生成をしてくれる。

項目11 equalsをオーバーライドするときは常にhashCodeをオーバーライドする

hashメソッドの契約

  • アプリケーション実行中に同じオブジェクトにhashCodeメソッドが繰り返し呼び出された場合、equal比較で使われるオブジェクトの情報に変更がなければ、hashCodeメソッドは常に一貫して同じ値を返さなければなりません。この値は、同じアプリケーションの一回の実行と別の実行で一致している必要はありません。
  • 二つのオブジェクトがequals(Obeject)メソッドにより等しければ、二つのオブジェクトそれぞれに対するhashCodeメソッド呼び出しは、同じ整数の結果を生成しなければなりません。
  • 二つのオブジェクトがequals(Object)メソッドにより等しくなければ、二つのオブジェクトそれぞれに対するhashCodeメソッド呼び出しが、異なる整数の結果を生成しなければならないことは要求されていません。しかし、等しくないオブジェクトに対して異なる整数の結果を生成することは、ハッシュテーブルのパフォーマンスを改善するかもしれないことをプログラマは認識しておくべきです。
hashCodeのオーバーライド例
    // 【良い例】hashCodeのオーバーライド例
    @Override
    public int hashCode() {
        int result = Short.hashCode(areaCode);
        result = 31 * result + Short.hashCode(prefix);
        result = 31 * result + Short.hashCode(lineNum);
        return result;
    }
  • 31は、奇数の素数であり、パフォーマンスが良いので、伝統的に選ばれる。
  • GuavaのHashingは、衝突が少ない。
  • 以下のhashCodeは、ボクシング/アンボクシングを行うので、パフォーマンスはあまり良くない。
IntelliJで自動生成されるhashCodeメソッド
    @Override
    public int hashCode() {
        return Objects.hash(areaCode, prefix, lineNum);
    }

項目12 toStringを常にオーバーライドする

  • 作成する全てのインスタンス化可能なクラスでは、スーパークラスがすでにオーバーライドしていないのなら、ObjectのtoStringの実装をオーバーライドする。
  • それにより、クラスは使いやすくなり、デバッグに役立つ。
  • toStringメソッドは、美的で優れた形式で、オブジェクトの簡潔で役立つ説明を返すべき。

項目13 cloneを注意してオーバーライドする

  • Cloneableインタフェースは、クラスは複製可能を許可していることを示している。
  • Objectのcloneメソッドはprotectedだが、Cloneableを実装しているクラスは適切に機能するpublicのcloneメソッドを提供することが期待されている。
  • 不変クラスは無駄な複製を作ってしまうため、cloneを提供すべきではない。
可変な状態への参照を持たないクラスのcloneメソッド
// Cloneableを実装する
public final class PhoneNumber implements Cloneable {
// 省略
    @Override
    public PhoneNumber clone() {
        try {
            return (PhoneNumber) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new AssertionError(); // 起こりえない
        }
    }
可変な状態への参照を持つクラスのcloneメソッド
public class Stack implements Cloneable {
// 省略
    @Override
    public Stack clone() {
        try {
            Stack result = (Stack) super.clone();
            // 配列をcloneしてメンバ変数に入れる。
            result.elements = elements.clone();
            return result;
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }

項目14 Comparableの実装を検討する

  • 自然な順序を持っていることを示す、Comparableインタフェースは、唯一のメソッドcompareToを持っている。
コンパレータ構築メソッドを持つComparable
public final class PhoneNumber implements Comparable<PhoneNumber> {
// 省略
    private static final Comparator<PhoneNumber> COMPARATOR =
            Comparator.comparingInt((PhoneNumber pn) -> pn.areaCode)
            .thenComparingInt(pn -> pn.prefix)
            .thenComparingInt(pn -> pn.lineNum);

    @Override
    public int compareTo(PhoneNumber pn) {
        return COMPARATOR.compare(this, pn);
    }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Effective Java 第3版 第3章全てのオブジェクトに共通のメソッド

Java中級者以上の必須本である、Effective Java 第3版に Kindle版が出たので、まとめる。

前:Effective Java 第3版 第2章オブジェクトの生成と消滅
次:Effective Java 第3版 第4章クラスとインタフェース(作成中)

項目10 equalsをオーバーライドするときは一般契約に従う

  • equalsを間違ったやり方でオーバーライドしてしまうと、その結果は悲惨なものになる。
  • 問題を避ける最も簡単な方法は、オーバーライドしないこと。

次の条件のどれかに当てはなるなら、オーバーライドしないのが正しいやり方。

  • クラスの個々のインスタンスが本質的に一意である。
  • クラスが「論理的等価性」の検査を提供する必要がない。
  • スーパークラスがすでにequalsをオーバーライドしており、スーパークラスの振る舞いがこのクラスに対して適切である、
  • クラスがprivateあるいはパッケージプライベートであり、そのequalsメソッドが呼び出されないことが確かである。

equalsメソッドは同値関係を実装し、以下の性質を持つ

  • 反射的: nullではに任意の参照値xに対して、x.equals(x)はtrueを返さなければなりません。
  • 対照的: nullではない任意の参照値xとyに対して、y.equals(x)がtrueを返す場合のみ、x.equals(y)はtrueを返さなければなりません。
  • 推移的: nullでない任意の参照値x、y、zに対して、もし、x.equals(y)y.equals(z)がtrueを返すならば、x.equals(z)はtrueを返さなければなりません。
  • 整合的: nullでない任意の参照値x、yに対して、x.equals(y)の複数回の呼び出しは、equalsの比較で使われる情報に変更がなければ、一貫してtrueを返すか、一貫してfalseを返さなければなりません。
  • nullではない任意の参照値xに対して、x.equals(null)はfalseを返さなければなりません。
[Good]equalのオーバーライド例
public final class PhoneNumber {
    private final short areaCode, prefix, lineNum;

    public PhoneNumber(int areaCode, int prefix, int lineNum) {
        this.areaCode = rangeCheck(areaCode, 999, "area code");
        this.prefix = rangeCheck(prefix, 999, "prefix");
        this.lineNum = rangeCheck(lineNum, 9999, "line num");
    }

    private static short rangeCheck(int val, int max, String arg) {
        if (val < 0 || val > max) {
            throw new IllegalArgumentException(arg + ": " + val);
        }
        return (short) val;
    }

    // 【良い例】 equalのオーバーライド例
    @Override
    public boolean equals(Object o) {
        if (o == this) {
            // 自分自身のオブジェクトへの参照であるか?
            return true;
        }
        if (!(o instanceof PhoneNumber)) {
            // 正しい型であるか?
            return false;
        }
        // 正しい型でキャストする
        PhoneNumber pn = (PhoneNumber) o;
        // 意味のあるフォールドのそれぞれについて一致するか?
        return pn.lineNum == lineNum && pn.prefix == prefix && pn.areaCode == areaCode;
    }
}
IntelliJで自動生成されるequalsメソッド
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        PhoneNumber that = (PhoneNumber) o;
        return areaCode == that.areaCode &&
                prefix == that.prefix &&
                lineNum == that.lineNum;
    }
  • GoogleのAutoValueフレームワークを使うことで、アノテーションによるequalsとhashCodeの自動生成をしてくれる。

項目11 equalsをオーバーライドするときは常にhashCodeをオーバーライドする

hashメソッドの契約

  • アプリケーション実行中に同じオブジェクトにhashCodeメソッドが繰り返し呼び出された場合、equal比較で使われるオブジェクトの情報に変更がなければ、hashCodeメソッドは常に一貫して同じ値を返さなければなりません。この値は、同じアプリケーションの一回の実行と別の実行で一致している必要はありません。
  • 二つのオブジェクトがequals(Obeject)メソッドにより等しければ、二つのオブジェクトそれぞれに対するhashCodeメソッド呼び出しは、同じ整数の結果を生成しなければなりません。
  • 二つのオブジェクトがequals(Object)メソッドにより等しくなければ、二つのオブジェクトそれぞれに対するhashCodeメソッド呼び出しが、異なる整数の結果を生成しなければならないことは要求されていません。しかし、等しくないオブジェクトに対して異なる整数の結果を生成することは、ハッシュテーブルのパフォーマンスを改善するかもしれないことをプログラマは認識しておくべきです。
hashCodeのオーバーライド例
    // 【良い例】hashCodeのオーバーライド例
    @Override
    public int hashCode() {
        int result = Short.hashCode(areaCode);
        result = 31 * result + Short.hashCode(prefix);
        result = 31 * result + Short.hashCode(lineNum);
        return result;
    }
  • 31は、奇数の素数であり、パフォーマンスが良いので、伝統的に選ばれる。
  • GuavaのHashingは、衝突が少ない。
  • 以下のhashCodeは、ボクシング/アンボクシングを行うので、パフォーマンスはあまり良くない。
IntelliJで自動生成されるhashCodeメソッド
    @Override
    public int hashCode() {
        return Objects.hash(areaCode, prefix, lineNum);
    }

項目12 toStringを常にオーバーライドする

  • 作成する全てのインスタンス化可能なクラスでは、スーパークラスがすでにオーバーライドしていないのなら、ObjectのtoStringの実装をオーバーライドする。
  • それにより、クラスは使いやすくなり、デバッグに役立つ。
  • toStringメソッドは、美的で優れた形式で、オブジェクトの簡潔で役立つ説明を返すべき。

項目13 cloneを注意してオーバーライドする

  • Cloneableインタフェースは、クラスは複製可能を許可していることを示している。
  • Objectのcloneメソッドはprotectedだが、Cloneableを実装しているクラスは適切に機能するpublicのcloneメソッドを提供することが期待されている。
  • 不変クラスは無駄な複製を作ってしまうため、cloneを提供すべきではない。
可変な状態への参照を持たないクラスのcloneメソッド
// Cloneableを実装する
public final class PhoneNumber implements Cloneable {
// 省略
    @Override
    public PhoneNumber clone() {
        try {
            return (PhoneNumber) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new AssertionError(); // 起こりえない
        }
    }
可変な状態への参照を持つクラスのcloneメソッド
public class Stack implements Cloneable {
// 省略
    @Override
    public Stack clone() {
        try {
            Stack result = (Stack) super.clone();
            // 配列をcloneしてメンバ変数に入れる。
            result.elements = elements.clone();
            return result;
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }

項目14 Comparableの実装を検討する

  • 自然な順序を持っていることを示す、Comparableインタフェースは、唯一のメソッドcompareToを持っている。
コンパレータ構築メソッドを持つComparable
public final class PhoneNumber implements Comparable<PhoneNumber> {
// 省略
    private static final Comparator<PhoneNumber> COMPARATOR =
            Comparator.comparingInt((PhoneNumber pn) -> pn.areaCode)
            .thenComparingInt(pn -> pn.prefix)
            .thenComparingInt(pn -> pn.lineNum);

    @Override
    public int compareTo(PhoneNumber pn) {
        return COMPARATOR.compare(this, pn);
    }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaでJWTを使ってみた

概要

Javaのライブラリを使ってJWTを導入した際の事をメモとして残しておく。

JWTとは

  • Web Tokenの略称で「署名の出来るJSONを含んだURL Safeなトークン」です。
  • JWTはHeader、Payload、Signatureで構成されていて、Header、PayloadはJsonをBase64エンコードした情報なので、ユーザー情報やパスワードなど外に公開したくないものは入れないようにするのがいいみたい。
  • 署名されているのでJson部分を改ざんしても検証時にチェックできる

トークンの例

  • トークン全体はこんな感じ
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.izVguZPRsBQ5Rqw6dhMvcIwy8_9lQnrO3vpxGwPCuzs
  • Header部分
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
  • Headerをデコードすると
{"typ":"JWT","alg":"HS256"}
  • Payload部分
eyJpc3MiOiJhdXRoMCJ9
  • Payloadをデコードすると
{"iss":"auth0"}

実際にJavaで書いてみた

  • 環境
    • java8
    • java-jwt(jwt.ioでも公開されてるjwtを扱うjavaライブラリ)
  • 今回はIssuerとExpireTime付のJWTを作ってみて動作を確認した
  • アルゴリズムはHS256を採用
  • いざトークン生成
try {
    Date expireTime = new Date();
    expireTime.setTime(expireTime.getTime() + 600000l);

    Algorithm algorithm = Algorithm.HMAC256("secret");
    String token = JWT.create()
            .withIssuer("auth0")
            .withExpiresAt(expireTime)
            .sign(algorithm);
} catch (JWTCreationException exception){
    //Invalid Signing configuration / Couldn't convert Claims.
}
  • トークンの検証
String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.izVguZPRsBQ5Rqw6dhMvcIwy8_9lQnrO3vpxGwPCuzs";
try {
    Algorithm algorithm = Algorithm.HMAC256("secret");
    JWTVerifier verifier = JWT.require(algorithm)
            .withIssuer("auth0")
            .build(); //Reusable verifier instance
    DecodedJWT jwt = verifier.verify(token);
} catch (JWTVerificationException exception){
    //Invalid signature/claims
}

使った感じ

  • java-jwtの公式ページに書いてあるコードを拝借すれば動作確認は簡単にできた。
  • ちゃんとJson部分(HeaderやPayload部分)が改ざんされた場合にJWTVerificationExceptionが投げられチェックされている。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

リファクタリング(コマンド・インタプリタもどき)

ここは?

コマンド・インタプリタもどきのプログラムをリファクタリングする記事です。

プログラム概要

コンソールから入力された文字列を解析、コマンドとして認識させ、レジスタA、B、Cに対し何らかの値を格納したり、演算を施した値を別のレジスタに格納したり、値をコンソールに出力したりするプログラムです。

機能

このプログラムは、次に掲げる機能を実装しています。

  • レジスタに値を格納する機能
    • コマンドは「ST(A、B又はC)+半角スペース+格納する値」とする。
    • 例えば、レジスタAに値10を格納するなら「STA 10」となる。
  • レジスタに格納されている値に対し加算又は減算する機能
    • コマンドは「(AD又はSB)(A、B又はC)+半角スペース+演算させる値」とする。
    • 例えば、レジスタBの値に20を足すなら「ADB 20」、Cの値から-30を引くなら「SBC -30」となる。
  • レジスタに格納されている値を出力する機能
    • コマンドは「PR(A、B又はC)」とする。
    • 例えば、「PRC」とすると、コンソールにレジスタCの値が表示される。
  • レジスタに格納されている値を別のレジスタに上書きする機能
    • コマンドは「LD(A、B又はC)+半角スペース+(A、B又はC)」とする。
    • 例えば、レジスタCにレジスタBの値を上書きするなら「LDC B」となる。
  • レジスタに格納されている値に対し加算又は減算してから、別のレジスタに上書きする機能
    • コマンドは「LD(A、B又はC)+半角スペース+演算させる値+半角コンマ+(a、b又はc)」とする。
    • 例えば、レジスタAの値に10足した値をレジスタBに上書きするなら「LDB 10,a」となる。
    • 例えば、レジスタBの値から10引いた値をレジスタCに上書きするなら「LDC -10,b」となる。
    • この場合において、加算や減算を示すコマンドは実装しない。また、演算処理を施す元となるレジスタの値には影響を及ぼさないものとする。
  • レジスタに格納されている値を初期化する機能
    • コマンドは「IT(A、B又はC)」とする。
    • 例えば、レジスタCを初期化するなら「ITC」とする。
  • レジスタA、B、Cに格納されている値を半角スペース区切りですべて出力する機能
    • コマンドは「APR」とする。
    • 例えば、レジスタA、B、Cの値がそれぞれ3、8、14とすると、コンソールには「3 8 -14」が表示される。

「65C816」のようなコマンド構成ですが、気にしない気にしない。
なお、この機能そのものは見直さないものとします。

仕様

  • レジスタに格納する値は整数(int型)とし、負数も考慮する。
    • 格納する値及び演算させる値の範囲は「-999から999まで」とする。
  • レジスタの初期値及び初期化値は0とする。
  • 例外処理は省略する(余裕があったら後々やってみます)。
  • コマンドに含まれる大文字及び小文字は区別する。

テストケース

次に掲げる順に処理を行いテストします。

処理内容 コマンド レジスタA レジスタB レジスタC コンソール
レジスタAに値10を格納 STA 10 10 0 0
レジスタBに値-5を格納 STB -5 10 -5 0
レジスタCに値3を格納 STC 3 10 -5 3
すべてのレジスタの値を表示 APR 10 -5 3 10 -5 3
レジスタAの値に5を足す ADA 5 15 -5 3
レジスタBの値から10を引く SBB 10 15 -15 3
レジスタCの値から-30を引く SBC -30 15 -15 33
すべてのレジスタの値を表示 APR 15 -15 33 15 -15 33
レジスタAの値を出力 PRA 15 -15 33 15
レジスタCの値を出力 PRC 15 -15 33 33
レジスタCにレジスタBの値を上書きする LDC B 15 -15 -15
レジスタBの値から10引いた値を
レジスタCに上書きする
LDC -10,b 15 -15 -25
レジスタAを初期化 ITA 0 -15 -25
すべてのレジスタの値を表示 APR 0 -15 -25 0 -15 -25

あまり良いとは言えないテストケースかもしれませんが、とりあえず。

元となるソースコード(手続き型)

初心者なら上出来なコードだけど、中級者以上ではちょっと・・・。
Scanner sc = new Scanner(System.in);

Pattern set = Pattern.compile("ST([ABC]) (-?\\d{1,3})");
Pattern calc = Pattern.compile("(AD|SB)([ABC]) (-?\\d{1,3})");
Pattern print = Pattern.compile("PR([ABC])");
Pattern load = Pattern.compile("LD([ABC]) ([ABC])");
Pattern calcAndLoad = Pattern.compile("LD([ABC]) (-?\\d{1,3}),([abc])");
Pattern init = Pattern.compile("IT([ABC])");
Pattern printAll = Pattern.compile("APR");

int[] registers = {0, 0, 0}; // [0]=A、[1]=B、[2]=C
while (true) {
  String str = sc.nextLine();
  Matcher set_m = set.matcher(str);
  Matcher calc_m = calc.matcher(str);
  Matcher print_m = print.matcher(str);
  Matcher load_m = load.matcher(str);
  Matcher calcAndLoad_m = calcAndLoad.matcher(str);
  Matcher init_m = init.matcher(str);
  Matcher printAll_m = printAll.matcher(str);

  // レジスタに値を格納する機能
  if (set_m.matches()) {
    String register = set_m.group(1);
    int value = Integer.parseInt(set_m.group(2));
    switch (register) {
      case "A": registers[0] = value; break;
      case "B": registers[1] = value; break;
      case "C": registers[2] = value; break;
    }
  // レジスタに格納されている値に対し加算又は減算する機能
  } else if (calc_m.matches()) {
    String operation = calc_m.group(1);
    String register = calc_m.group(2);
    int value = Integer.parseInt(calc_m.group(3));
    switch (register) {
      case "A":
        switch (operation) {
          case "AD": registers[0] += value; break;
          case "SB": registers[0] -= value; break;
        }
        break;
      case "B":
        switch (operation) {
          case "AD": registers[1] += value; break;
          case "SB": registers[1] -= value; break;
        }
        break;
      case "C":
        switch (operation) {
          case "AD": registers[2] += value; break;
          case "SB": registers[2] -= value; break;
        }
        break;
    }
  // レジスタに格納されている値を出力する機能
  } else if (print_m.matches()) {
    String register = print_m.group(1);
    switch (register) {
      case "A": System.out.println(registers[0]); break;
      case "B": System.out.println(registers[1]); break;
      case "C": System.out.println(registers[2]); break;
    }
  // レジスタに格納されている値を別のレジスタに上書きする機能
  } else if (load_m.matches()) {
    String register_tgt = load_m.group(1);
    String register_src = load_m.group(2);
    switch (register_tgt) {
      case "A":
        switch (register_src) {
          case "B": registers[0] = registers[1]; break;
          case "C":registers[0] = registers[2]; break;
        }
        break;
      case "B":
        switch (register_src) {
          case "A": registers[1] = registers[0]; break;
          case "C":registers[1] = registers[2]; break;
        }
        break;
      case "C":
        switch (register_src) {
          case "A": registers[2] = registers[0]; break;
          case "B":registers[2] = registers[1]; break;
        }
        break;
    }
  // レジスタに格納されている値に対し加算又は減算してから、別のレジスタに上書きする機能
  } else if(calcAndLoad_m.matches()) {
    String register_tgt = calcAndLoad_m.group(1);
    int value = Integer.parseInt(calcAndLoad_m.group(2));
    String register_src = calcAndLoad_m.group(3);
    switch (register_tgt) {
      case "A":
        switch (register_src) {
          case "b": registers[0] = registers[1] + value; break;
          case "c":registers[0] = registers[2] + value; break;
        }
        break;
      case "B":
        switch (register_src) {
          case "a": registers[1] = registers[0] + value; break;
          case "c":registers[1] = registers[2] + value; break;
        }
        break;
      case "C":
        switch (register_src) {
          case "a": registers[2] = registers[0] + value; break;
          case "b":registers[2] = registers[1] + value; break;
        }
        break;
    }
  // レジスタに格納されている値を初期化する機能
  } else if(init_m.matches()) {
    String register= init_m.group(1);
    switch (register) {
      case "A": registers[0] = 0; break;
      case "B": registers[1] = 0; break;
      case "C": registers[2] = 0; break;
    }
  // レジスタA、B、Cに格納されている値を半角スペース区切りですべて出力する機能
  } else if(printAll_m.matches()) {
    System.out.println(registers[0] + " " + registers[1] + " " + registers[2]);
  }
}

// ちなみにスキャナのクローズ処理は省略。

あーしんどかった。まるで縛りプレーみたい。
これだけの実装(これでも小規模かもしれませんが)を手続き型で書くほうがきついですよ。
Pattern、Matcher、分岐処理が同一メソッド内に羅列され、挙句の果てにはif-else文の中で溢れんばかりに主張を繰り返すswitch文(ネストswitch文まである始末)など、誰も読もうとは思ってもらえなさそうなきったねぇ美しいコードに仕上がりました。
メソッドや関数型インターフェースすら使ってませんので、こうなるのは仕方のないことかもしれませんが。
もし誤字脱字等ありましたら、恐れ入りますがご指摘願います(まずこんなクソコードを読んでくれるかどうか・・・)。

リファクタリング

オブジェクトに何らかの加工を施さないアクセサについては、説明を省略しています。

クラス

  • Interpreterクラス:メインクラス。インタプリタの機能を提供する。
    • メソッド
      • run:インタプリタを実行する。コンソールからの入力を受け取り、コマンド列挙体を使って入力の解析を行う。解析が成功した場合は、コマンドを実行する。
class Interpreter {
  void run(String str) {
    for (CommandConstants cst : CommandConstants.values()) {
      Matcher m = cst.command().matcher(str);
      if (m.matches()) { cst.command().consumer().accept(m); break; }
    }
  }
}
  • Commandクラス:コマンドの正規表現とそのコマンドにより実行される処理の機能を提供する。
    • インスタンス変数
      • p:コマンドの正規表現を示すオブジェクト
      • consumer:コマンドにより実行される処理を示すオブジェクト
    • メソッド
      • matcher:コンソールからの入力とコマンドの正規表現によるマッチャを返す。
class Command {
  private Pattern p;
  private Consumer<Matcher> consumer;

  Command(String regex, Consumer<Matcher> consumer) {
    p = Pattern.compile(regex);
    this.consumer = consumer;
  }

  Matcher matcher(String input) { return p.matcher(input); }
  Consumer<Matcher> consumer() { return consumer; }
}
  • Registerクラス:要中の要。レジスタの機能を提供する。
    • クラス定数
      • OPERATORS:演算処理を示すオブジェクトを格納するマップ
    • インスタンス変数
      • value:レジスタの値を示すオブジェクト
    • メソッド
      • set:レジスタに値を格納する。
      • calculate:レジスタの値に対し加算又は減算する。
      • print:レジスタの値を出力する。
      • load:レジスタの値を別のレジスタに上書きする。
      • calculate(Register, int):レジスタの値に対し加算又は減算してから、別のレジスタに上書きする。
      • reset:レジスタの値を初期化する。
      • value:レジスタの値を返す。
class Register {
  private static final Map<String, IntBinaryOperator> OPERATORS = new HashMap<>() {{
    put("AD", (l, r) -> l + r);
    put("SB", (l, r) -> l - r);
  }};

  private int value;

  void set(int value) {
    this.value = value;
  }
  void calculate(String operation, int operand) {
    value = OPERATORS.get(operation).applyAsInt(this.value, operand);
  }
  void print() {
    System.out.println(value);
  }
  void load(Register register_src) {
    value = register_src.value();
  }
  void calculate(Register register_src, int operand) {
    value = register_src.value() + operand;
  }
  void reset() { value = 0; }
  int value() { return value; }
}

やろうと思えば正規表現文字列もクラス化できそうですが、くどくなりそうな気がしたのでやめました。

列挙体

  • レジスタ列挙体(RegisterConstants)
    • 列挙子
      • A:レジスタA
      • B:レジスタB
      • C:レジスタC
enum RegisterConstants {
  A(new Register()),
  B(new Register()),
  C(new Register()),;

  private Register register;

  private RegisterConstants(Register register) { this.register = register; }
  int value() { return register.value(); }
  static Register get(String register) { return valueOf(register).register; }
}

各列挙子に包まれているオブジェクトがそれぞれレジスタA、B、Cと対応しています。

  • コマンド列挙体(CommandConstants)
    • 列挙子
      • SETTER
      • CALCULATOR
      • PRINTER
      • LOADER
      • CALCULATABLE_LOADER
      • INITIALIZER
      • ALL_PRINTER
enum CommandConstants {
  SETTER(new Command("ST([ABC]) (-?\\d{1,3})",
    m -> {
      String register = m.group(1);
      int value = Integer.parseInt(m.group(2));
      RegisterConstants.get(register).set(value);
    })),
  CALCULATOR(new Command("(AD|SB)([ABC]) (-?\\d{1,3})",
    m -> {
      String operation = m.group(1);
      String register = m.group(2);
      int operand = Integer.parseInt(m.group(3));
      RegisterConstants.get(register).calculate(operation, operand);
    })),
  PRINTER(new Command("PR([ABC])",
    m -> {
      String register = m.group(1);
      RegisterConstants.get(register).print();
    })),
  LOADER(new Command("LD([ABC]) ([ABC])",
    m -> {
      String register_tgt = m.group(1);
      Register register_src = RegisterConstants.get(m.group(2));
      RegisterConstants.get(register_tgt).load(register_src);
    })),
  CALCULATABLE_LOADER(new Command("LD([ABC]) (-?\\d{1,3}),([abc])",
    m -> {
      String register_tgt = m.group(1);
      int operand = Integer.parseInt(m.group(2));
      Register register_src = RegisterConstants.get(m.group(3).toUpperCase());
      RegisterConstants.get(register_tgt).calculate(register_src, operand);
    })),
  INITIALIZER(new Command("IT([ABC])",
    m -> {
      String register= m.group(1);
      RegisterConstants.get(register).reset();
    })),
  ALL_PRINTER(new Command("APR",
    m -> {
      String registers = Stream.of(RegisterConstants.values())
        .map(r -> String.valueOf(r.value()))
        .collect(Collectors.joining(" "));
      System.out.println(registers);
    })),;

  private Command command;

  private CommandConstants(Command command) { this.command = command; }
  Command command() { return command; }
}

今回使用するクラス・列挙体の中で最も長いコードをもちます。
コマンドを解析してレジスタに命令を下す処理を列挙しているからしょうがない。
各列挙子は、Commandクラスのオブジェクトをもつことで構成されています。
インタプリタのrunメソッドにより各列挙子が走査され、コンソールからの入力の解析が行われます。解析が成功した場合は、当該列挙子に含まれるCommandクラスのオブジェクトがもつ処理が実行される仕組みです。

個人的にはCALCULATABLE_LOADERやALL_PRINTERというネーミングが何とも・・・。
他に思い浮かばなかったです、すみません。

実行コード

あれだけ賑やかだったソースコードも、たった3行となりました。
クラスだの列挙体だのと導入したので全体としては記述量は増えたかもしれませんが、デバッグのしやすさや拡張性などで比べればオブジェクト指向による設計のほうが遥かに好きですし、後が楽だと思います。

Scanner sc = new Scanner(System.in);
Interpreter interpreter = new Interpreter();
while (true) interpreter.run(sc.nextLine());

/* 入力:
 * STA 10
 * STB -5
 * STC 3
 * APR
 * ADA 5
 * SBB 10
 * SBC -30
 * APR
 * PRA
 * PRC
 * LDC B
 * LDC -10,b
 * ITA
 * APR
 */ 

/* 出力:
 * 10 -5 3
 * 15 -15 33
 * 15
 * 33
 * 0 -15 -25
 */ 

もくじに戻る

https://qiita.com/k73i55no5/items/9e0825cee4cc1cb078a6

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