- 投稿日:2021-06-03T23:44:17+09:00
【Java】「なんでここequalsなの?」と聞かれた話
上司に「なんでここequalsなの?」と聞かれてなんぞなんぞって思ったことがあったので記事にしてみました。 言われたときは「文字列の比較だからだよナ…」という気持ち… javaに触れ始めてからは(というか今この瞬間)これで合ってるのかなと思っています。 ・intは「==」 ・Stringは「equals」 この理解度のままで良いのか自分!!と思ったのでまとめてみます。 そもそもいつ使ってる? 初歩の初歩とは分かっていますが焦らずここから 使用頻度の高い場面はやはりif文ですかね… String loveAnimal = "dog"; boolean isdogPerson = false; if (loveAnimal.equals("dog")) { isdogPerson=true; } //true System.out.println(isdogPerson); どうやら筆者は犬派であるということが分かりました。 何のひねりもないif文ですが、なんだかんだ使用頻度が高いなと思います。 switchもうまく使えるようになりたい… 何を比べているの? いざSEになったからというもの値の比較を目にすることが多いですが、少し初心に帰ってみます。 Javaにはプリミティブ型と参照型があります。 プリミティブ型について表にしてみました。 型 値 byte -128 ~ 127 の整数 short -32768 ~ 32767 の整数 int 整数 long 整数 char \u0000 ~ \uFFFF のUnicode文字列 float 実数(単精度不動小数点数) double 実数(倍精度不動小数点数) boolean true, false こんなにあったなんて… shortなんかは今回調べるまで知りませんでした… 参照型はStringが代表的で覚え方がよいかは分かりませんが、ざっくりと値を詰める箱!!と覚えています。 ==っていつ使うの? 脱線しましたが、本題へ! ==演算子はどうやら参照先が同じかどうかを比較するものです。 プリミティブ型(int)を比較してみます。 同じ住所の太郎さんか違う住所の太郎さんかくらいの認識で今は書き進めています。 // プリミティブ型(int)の比較 int intA = 1; int intB = 1; // true System.out.println(intA == intB); 上記の例では1と1の値同士を比較した結果がtrueになります。 次に参照型の比較をしてみます。 // 参照型(Integer)の比較 Integer integerC = new Integer(1); Integer integerD = new Integer(1); // false System.out.println(integerC == integerD); こちらの結果はfalseになります。 どうやら値の比較を行っていないことが分かります。 参照型における==は変数が保持するインスタンス(箱)が同じであるかを比較しています。 equalsはいつ使うの? ここで我らのequalsに迫ります。 私の必殺技はjava.util.Objects.equals 先ほどのIntegerの比較をequalsでリベンジしてみましょう。 // 参照型(Integer)の比較 Integer integerC = new Integer(1); Integer integerD = new Integer(1); // true System.out.println(integerC.equals(integerD)); equalsを使用することによってインスタンスが持っている値の比較をしていることが分かります。 私は感覚的にequalsは上記のような役割を果たしていると思っていましたが、Integer.Classの中ではこのような処理が走っているようでした。 Integer.class public boolean equals(Object obj) { if (obj instanceof Integer) { return value == ((Integer)obj).intValue(); } return false; } 中で==しているのネ… 今回書き始めようと思ったモヤモヤがかなり解消された気がしました。 せっかくなのでString型の中ものぞいてみましょう String.class public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String aString = (String)anObject; if (!COMPACT_STRINGS || this.coder == aString.coder) { return StringLatin1.equals(value, aString.value); } } return false; } こいつも==しとるやんけ… 面倒くさがらずに参照型の定義を覗いてみようと心に誓い、この辺で締めたいと思います。 まとめ Javaにはプリミティブ型と参照型があり、それぞれの比較に==とequalsが使用されています。 ・プリミティブ型は==で比較 ・参照型はequalsで比較 ∟中では==してる プリなんたら型と記憶にうっすらでした。 ・上司のささやかな優しさを感じました… ∟日々精進ですね 今回の内容を書きたくなったきっかけの記事様 【Java】==とequalsの違い 最近は美容師さんに勧められたDEARBOYSを読んでいます。(バスケの漫画はアチチチ) 森高麻衣ちゃん可愛すぎるな?? 余談はこの辺にして、また日々の業務での疑問や理解が甘いことをピックアップしてまとめてみようと思います。
- 投稿日:2021-06-03T18:29:42+09:00
Selenide(Java)で新規に開くwindowにフォーカスを切り替える
はじめに E2Eテスト自動化をした際に、新規windowが開くようなサイトで新規windowにフォーカスが移らずエラーになる事が何度かあったので、その際に安定化させるためにやった事を備忘録として残しておく。 java : 8以上 新規に開くwindowにフォーカスを切り替える SwitchWindowSample.java public HogePage openWindow(){ Set<String> beforeHandles = WebDriverRunner.getWebDriver().getHandles(); Selenide.$("#btn").click(); Selenide.sleep(500); // 安定させるためにどうしても明示的にsleepを入れたりしないとダメな事もある Set<String> afterHandles = WebDriverRunner.getWebDriver().getHandles(); afterHandles.removeAll(beforeHandles); // Setの中身から新規windowのhandleを取得するために被っているhandleは削除 String handle = afterHandles.stream().findFirst().get(); Selenide.switchTo().window(handle); // ここで明示的にwindowを切り替える return Selenide.open(HogePage.class); } ※上記ではわざとSelenide.としているが普通はimportで書いてきれいにするのがいいと思われる。 参考文献
- 投稿日:2021-06-03T17:03:23+09:00
Azure Cosmos DB の部分更新をJava SDKから試す
Cosmos DB の部分更新(いわゆるPatch)が Private Preview ですがサポートされました。 Partial document update for Azure Cosmos DB in private preview | Azure updates | Microsoft Azure 申し込んでは見ましたが、使える気配がないので、エミュレータでサポートされていると聞いて試してみました。とはいえデフォルトのままでは機能が有効になっていないので、/EnablePreview オプションを付けて起動します。 .\CosmosDB.Emulator.exe /EnablePreview 対応SDK GitHubのソースをみると、数ヶ月前からIssueがたっていたり、色々と動きがあったようです。執筆時点で最新の 4.15.0 は 更新操作をサポートしています。 <dependency> <groupId>com.azure</groupId> <artifactId>azure-cosmos</artifactId> <version>4.15.0</version> </dependency> いまのところ Java以外では、.NET SDK が対応しているのみです。 サポートする操作 サポートする操作は以下の通りで、 追加 (Add) 削除 (Remove) 置換 (Replace) 設定 (Set) プラスマイナスのインクリメント (Increment) 単一アイテムの更新はもちろんできますが、、条件付や、複数アイテムなどもできます。 操作について少し補足すると 追加は、Upsert のように機能する 更新は、更新しようとする要素が存在しない場合は失敗する 追加と設定は配列以外の時は、同じように機能するが、配列の時はちょっと違う(後述) ざっくり言うと、Json Patch RFCのセマンティクスに従っているようです。 使ってみる 適当なJSONをエミュレータに設定しておき、 { "id": "b1dd9d5e-f334-4b2b-9165-4ff9e508e469", "name": "statemachine", "age": 20, } 以下のコードで更新します CosmosPatchOperations ops = CosmosPatchOperations.create(); ops.add("/new_element", "パッチで追加"); ops.replace("/name", "patched statemachine"); ops.increment("/age", 1); ops.set("/ikemen", true); CosmosItemResponse<JsonNode> response = container.patchItem( id, partitionKey, ops, JsonNode.class) .block(); System.out.println(response.getItem().toPrettyString()); CosmosPatchOperations インスタンスを作成して、add , replace, increment などの更新操作を追加していきます。最後に、patchItemメソッドで更新操作します。JsonNode.classを指定しておくと、POJO定義しなくても適当にレスポンスのインスタンスが取得できて楽ちんです。が、後で説明する設定が必要です。 { "name": "patched statemachine", "age": 21, "id": "b1dd9d5e-f334-4b2b-9165-4ff9e508e469", "new_element": "パッチで追加", "ikemen": true, } Set と Replaceの違い 前述したとおり Set と Replace は、配列の時に違う動きをするようです。このような配列に対して、 "array": [ 1, 2, 3 ], add を行うと ops.add("/array/0", 0); 先頭(指定したインデックス)に追加されます。 "array": [ 0, 1, 2, 3 ], 上の入力にたいして、ops.set("/array/0", 99)を行うと指定したインデックスが設定されます。 "array": [ 99, 1, 2, 3 ], 予測通りの挙動でしょうか。単一要素の場合はあまり気にしなくてもよいとは思いますが、配列の場合は注意して操作する必要がありそうです。もうちょっと複雑な配列とスキーマをもっていると、更新操作をするのも楽じゃない気がします。 補足 Java SDK の場合、書き込み系の操作のとき、デフォルトでコンテンツのレスポンスを返してくれません。久しく忘れていてはまりました。 クライアントをビルドするときにcontentResponseOnWriteEnabled で設定するか、個々の操作でもオプションを指定可能ですので、ご注意を。 var client = new CosmosClientBuilder() .endpoint(endpoint) .key(key) .gatewayMode(new GatewayConnectionConfig()) .contentResponseOnWriteEnabled(true) .buildAsyncClient(); まとめ 更新操作はJSONのパスを指定する方法なので、POJOクラスを活用できないのは残念です。更新の性質上しょうがないのかもしれませんが、なにか方法があれば便利そうな気もするし、メンドウな気もします(あまり深くは考えてません) とはいえ、いままで出来なかった更新操作がようやくできるようになったので、活用方法は色々あるかとは思います。 以下のGithubにフィードバックグループがあるので、一言言いたい人は是非。
- 投稿日:2021-06-03T15:39:37+09:00
Android の Spinner を簡単に使う
はじめに 数年ぶりに Android のアプリを書こうとしたら、Android Studio は(以前は Eclipse でしたが)随分高機能化したようでしたが、UI 開発周りの IDE での補助が 25 年以上前の MFC にも劣るように感じられました(個人の感想です)。 Android2.x 時代から私が(作って)使っているユーティリティクラスのようなコードのデザインパターンを検索しても見かけなかったので(よく探せばあるかもしれませんが)、ここでは Spinner のユーティリティクラスを紹介します。 Spinnerとは? Win32 のコンボボックス(ドロップダウンリスト)に相当するUIです。 https://developer.android.com/guide/topics/ui/controls/spinner?hl=ja 使い方 クラスのソースコードは最後に付加しておきますので、まずは使い方を説明します。 まずは以下のような準備をします。 private UIDialog.SimpleSpinner m_smplSpin ; // 表示項目 String[] spinNameArray = { "リスト1", "リスト2", "リスト3", ... } ; // 対象のスピナー Spinner spinner = view.findViewById( R.id.対象のスピナー) ; // 準備 int numSpinner = 1 ; // ← "リスト2" を初めに選択する m_smplSpin = new UIDialog.SimpleSpinner ( spinner, numSpinner, spinNameArray , null) ; spinner は findViewById でも、binding でも、何か好きな方法で取得してください。 そして、値を取得したいタイミングで int indexSelected = m_smplSpin.getSelectionIndex() ; を呼び出すと indexSelected に選択された番号(0~)が取得できます。 選択されていないときは -1 になります。 もし、番号が 0 からの連番でない場合には int[] spinNumArray = { 0, -1, 1, ... } ; int numSpinner = 1 ; // ← "リスト3" を初めに選択する m_smplSpin = new UIDialog.SimpleSpinner ( spinner, numSpinner, spinNameArray, spinNumArray ) ; のように、int[] を渡しておくといい感じにやってくれて、結果は同様に getSelectionIndex 又は、 int numSelected = m_smplSpin.getSelectionNum( -2 ) ; で取得します。引数は選択されていないときに返却する値を指定します。 getSelectionIndex は 0~ の連番、getSelectionNum は対応する任意の値を返します。 選択が変更されたときに処理をしたい場合には結局リスナを派生することになりますが、以下のようにします。 m_smplSpin = new UIDialog.SimpleSpinner ( spinner, numSpinner, spinNameArray, spinNumArray new UIDialog.SimpleSpinnerListener() { @Override public void onSelected( SimpleSpinner spinner, int index ) { // 何かの処理... } } } ; これでも一応、値が連番でないときや、選択されていない状態を index に -1 で受け取れるなど、コードの簡略化が出来るなどの利点は一応あります。 大抵の UI 要素はシンプルなデフォルトの挙動で十分なことが多いと思いますのでコードを簡略化できます。 ソース 以下がソースです。 UIDialog と言うクラスの中に入っていますが外に出しても問題無いと思います。 (実際には他にもいろいろ入っていますが、ここでは省略して Spinner 部分だけ記載します) public class UIDialog { // スピナー通知 public interface SimpleSpinnerListener { public abstract void onSelected( SimpleSpinner spinner, int index ) ; } // スピナーアイテム・ユーティリティ public static class SimpleSpinner implements AdapterView.OnItemSelectedListener { private Spinner m_spinner = null ; private int m_selection = 0 ; private String[] m_aTextArray = null ; private int[] m_aNumArray = null ; private SimpleSpinnerListener m_listener = null ; public SimpleSpinner ( Spinner spinner, int iFirstNum, String[] aTextArray, int[] aNumArray ) { m_aTextArray = aTextArray ; m_aNumArray = aNumArray ; setupSpinner ( spinner, iFirstNum, android.R.layout.simple_spinner_item, android.R.layout.simple_spinner_dropdown_item ) ; } public SimpleSpinner ( Spinner spinner, int iFirstNum, String[] aTextArray, int[] aNumArray, SimpleSpinnerListener listener ) { m_aTextArray = aTextArray ; m_aNumArray = aNumArray ; m_listener = listener ; setupSpinner ( spinner, iFirstNum, android.R.layout.simple_spinner_item, android.R.layout.simple_spinner_dropdown_item ) ; } public SimpleSpinner ( Spinner spinner, int iFirstNum, String[] aTextArray, int[] aNumArray, int resSpinnerItem, SimpleSpinnerListener listener ) { m_aTextArray = aTextArray ; m_aNumArray = aNumArray ; m_listener = listener ; setupSpinner ( spinner, iFirstNum, resSpinnerItem, android.R.layout.simple_spinner_dropdown_item ) ; } public SimpleSpinner ( Spinner spinner, int iFirstNum, String[] aTextArray, int[] aNumArray, int resSpinnerItem, int resDropdownItem, SimpleSpinnerListener listener ) { m_aTextArray = aTextArray ; m_aNumArray = aNumArray ; m_listener = listener ; setupSpinner( spinner, iFirstNum, resSpinnerItem, resDropdownItem ) ; } public void setupSpinner ( Spinner spinner, int iFirstNum, int resSpinnerItem, int resDropdownItem ) { m_spinner = spinner ; m_selection = numToSelection( iFirstNum ) ; ArrayAdapter<String> adpStyleList = new ArrayAdapter ( EntisGLS.getMainActivity(), resSpinnerItem, m_aTextArray ) ; adpStyleList.setDropDownViewResource( resDropdownItem ) ; spinner.setAdapter( adpStyleList ) ; if ( (m_selection >= 0) && (m_selection < m_aTextArray.length) ) { spinner.setSelection( m_selection ) ; } spinner.setOnItemSelectedListener( this ) ; } protected int numToSelection( int num ) { if ( m_aNumArray == null ) { return num ; } for ( int i = 0; i < m_aNumArray.length; i ++ ) { if ( m_aNumArray[i] == num ) { return i ; } } return -1 ; } public Spinner getSpinner() { return m_spinner ; } public int getSelectionIndex() { return m_selection ; } public int getSelectionNum( int ifNonSelected ) { if ( m_aNumArray == null ) { return m_selection ; } if ( m_selection >= 0 ) { return m_aNumArray[m_selection] ; } return ifNonSelected ; } @Override public void onItemSelected ( AdapterView<?> parent, View view, int position, long id ) { if ( (position >= 0) && (position < m_aTextArray.length) ) { m_selection = position ; if ( m_listener != null ) { m_listener.onSelected( this, m_selection ) ; } } } @Override public void onNothingSelected (AdapterView<?> parent) { m_selection = -1 ; if ( m_listener != null ) { m_listener.onSelected( this, m_selection ) ; } } } }
- 投稿日:2021-06-03T14:22:34+09:00
【JAVA】 superとは
【JAVA】superとは superとは 継承元を呼び出す ルール superは、コンストラクタの最初に書かないといけない superの使い方 super() main public class Main { public static void main(String[] args) { SubRabbit sub = new SubRabbit(); } } // サブクラス class SubRabbit extends Rabbit { public SubRabbit() { super(); } } // スーパークラス class Rabbit { public Rabbit(){ System.out.println("うさぎ"); } } 実行結果 うさぎ super(引数) main public class Main { public static void main(String[] args) { SubRabbit sub = new SubRabbit(); } } class SubRabbit extends Rabbit { public SubRabbit() { super("むぎ"); } } class Rabbit { public Rabbit(){ System.out.println("うさぎ"); } public Rabbit(String rabbitName) { System.out.println("うさぎの名前:" + rabbitName); } } 実行結果 うさぎの名前:むぎ super.変数 main public class Main { public static void main(String[] args) { SubRabbit sub = new SubRabbit(); } } class SubRabbit extends Rabbit { public SubRabbit() { System.out.println(super.usagi); } } class Rabbit { String usagi = "うさぎ"; } 実行結果 うさぎ super.関数 main public class Main { public static void main(String[] args) { SubRabbit sub = new SubRabbit(); } } class SubRabbit extends Rabbit { public SubRabbit() { super.RabbitInfo(); } } class Rabbit { public Rabbit() { } public void RabbitInfo() { System.out.println("うさぎはかわいい"); } } 実行結果 うさぎはかわいい
- 投稿日:2021-06-03T11:24:19+09:00
累積和の計算
愚直にでも解けないことはないが計算量が増えるのは愚策、みたいな問題なので「そうそうこれこれそれっぽい」とnoob丸出しなことを言う。 まず愚直版 Main.java import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int score = 0; for(int i=0; i<n; i++){ score += sc.nextInt(); System.out.println(score); } } } 0.63秒……かかってるなあ。(チケットないので入力は見られてない) というかお手本でもこの方法なので「これでいいんじゃね?」感はある。 (計算式だけを見て)累積和でやってみた。 Main.java import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int[] a, b; a = new int[n]; b = new int[n+1]; b[0] = 0; for(int i=0; i<n; i++){ a[i] = sc.nextInt(); } for(int i=1; i<=n; i++){ b[i] = b[i-1] + a[i-1]; } for(int i=1; i<b.length; i++){ System.out.println(b[i]); } } } 変わってねえ。 実装の仕方を間違えているのかもしれないが、ひとまず次の問題へ行こう。 ぶち当たってから考える。
- 投稿日:2021-06-03T09:56:22+09:00
[競プロ]ダイクストラ実装、優先度付きキュー【Java】
概要 前回のダイクストラ法の記事の続編です。 優先度付きキューを用いて、計算量を減らします。 前回、愚直にダイクストラ法を実装した際の計算量は、O(V^2)でした(Vは頂点数)。 今回はダイクストラ法で毎回求める「確定していない頂点のうち最小の値(ある頂点からの最短距離)を持つ頂点」の探索に優先度付きキューを用いることで、計算量をO((E+V)logV)まで落とします。 優先度付きキューとは wikipediaより。 優先度付きキュー(ゆうせんどつき -、英: priority queue)は、以下の4つの操作をサポートする抽象データ型である。 キューに対して要素を優先度付きで追加する。 最も高い優先度を持つ要素をキューから取り除き、それを返す。 (オプション) 最も高い優先度を持つ要素を取り除くことなく参照する。 (オプション) 指定した要素を取り除くことなく優先度を変更する ここで、Javaの優先度付きキューのクラスでは、要素の挿入と取り出しをO(logN)で行うことができます(Nはキューのサイズ)。線形時間より早いので単純に探索するより早いというわけです。 Javaのドキュメントを参照してPriorityQueueの実装 PriorityQueueのドキュメントを参照し、ちょっと試してみましょう。 よく使いそうなのが、addやpeek、pollメソッドです。 通常のQueueクラスと同じようなものですね。 addは要素の追加、peekは参照、pollは参照して削除です。 昇順 import java.util.PriorityQueue; public class Main { public static void main(String[] args) { PriorityQueue<Integer> q = new PriorityQueue<>(); q.add(1); q.add(2); q.add(3); q.add(4); System.out.println(q.poll()); System.out.println(q.poll()); System.out.println(q.poll()); } } 1 2 3 昇順(2) import java.util.PriorityQueue; public class Main { public static void main(String[] args) { PriorityQueue<Integer> q = new PriorityQueue<>(); q.add(4); q.add(3); q.add(2); q.add(1); System.out.println(q.poll()); System.out.println(q.poll()); System.out.println(q.poll()); } } 1 2 3 確かに整数の昇順で優先度がついていそうです。 降順 降順にするには以下のように書きます。 import java.util.Collections; import java.util.PriorityQueue; public class Main { public static void main(String[] args) { PriorityQueue<Integer> q = new PriorityQueue<>(Collections.reverseOrder()); q.add(1); q.add(2); q.add(3); q.add(4); System.out.println(q.poll()); System.out.println(q.poll()); System.out.println(q.poll()); } } 4 3 2 自定義のクラス 自分で定義したクラスを優先度付きキューで管理したい場合は以下のように書きますね。 Comparableを実装してみました。 import java.util.PriorityQueue; public class Main { public static void main(String[] args) { PriorityQueue<MyStr> q = new PriorityQueue<>(); q.add(new MyStr("d")); q.add(new MyStr("c")); q.add(new MyStr("b")); q.add(new MyStr("a")); System.out.println(q.poll().str); System.out.println(q.poll().str); System.out.println(q.poll().str); } } class MyStr implements Comparable<MyStr> { String str; public MyStr(String s) { this.str = s; } @Override public int compareTo(MyStr myStr) { return str.compareTo(myStr.str); } } a b c ダイクストラ法の実装 ちょっと遠回りしましたが、ダイクストラ法の実装をします。 例題は前回のダイクストラ法の記事と同じものを使用します。 問題はこちらのリンクです。 ちなみに前回の提出コードはこちらです。 これに優先度付きキューを用いて、より早くします。 ACコードは以下のとおりです。 import java.util.ArrayList; import java.util.PriorityQueue; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); ArrayList<ArrayList<Integer>> edge = new ArrayList<>(); // 頂点と接続している点 for (int i = 0; i < n; i++) { edge.add(new ArrayList<>()); // 初期化 } long[][] cost = new long[n][n]; // 2点間の距離 boolean[] used = new boolean[n]; // 確定したかどうか long ans[] = new long[n]; // 頂点0からの最短距離 // 入力の受け取り for (int i = 0; i < n; i++) { int u = sc.nextInt(); // 頂点 int k = sc.nextInt(); // 頂点uからの出自数 for (int j = 0; j < k; j++) { int v = sc.nextInt(); // uと隣接する頂点 long c = sc.nextInt(); // uとvの距離(重み) edge.get(u).add(v); // uとvが隣接しているという情報を格納 cost[u][v] = c; // uからvへの距離(重み)を更新 } } // ここからダイクストラ PriorityQueue<Node> q = new PriorityQueue<>(); // 優先度付きキューの宣言 /* * 始点に0を設定する。(未確定。その他のノードには便宜的にINFなどを入れておくことが多い) */ for (int i = 0; i < n; i++) { ans[i] = Long.MAX_VALUE; } ans[0] = 0; q.add(new Node(0, 0)); // 優先度付きキューに未確定のキュー格納 for (;;) { // 以下コメントアウト // /* // * 未確定のノードから、最短のものを一つ選択し、そこを確定させる。 // */ // long minDistance = Long.MAX_VALUE; // int minTyoten = -1; // for (int i = 0; i < n; i++) { // if (!used[i]) { // if (minDistance > ans[i]) { // minDistance = ans[i]; // minTyoten = i; // } // } // } // // /* // * すべてのノードが確定していれば、終了。確定していなければ、最初に戻る // */ // if (minDistance == Long.MAX_VALUE) { // break; // } // // // 頂点を確定させる。 // used[minTyoten] = true; /* * すべてのノードが確定していれば、終了。確定していなければ、最初に戻る */ if (q.size() == 0) { break; } /* * 未確定のノードから、最短のものを一つ選択し、そこを確定させる。 */ Node node = q.poll(); // 現状最短のNode int minTyoten = node.tyoten; if (used[minTyoten]) { continue; } used[minTyoten] = true; /* * 直前で確定したノードから直接つながっているノードに対して、かかる時間を計算する。 * そのノードが現状持っている最短経路より短ければ、その値で更新する。 */ for (int next : edge.get(minTyoten)) { if (ans[next] > ans[minTyoten] + cost[minTyoten][next]) { ans[next] = ans[minTyoten] + cost[minTyoten][next]; q.add(new Node(next, ans[next])); } } } // 答えの出力 int i = 0; for (long h : ans) { System.out.println(i++ + " " + h); } } } class Node implements Comparable<Node> { int tyoten; long minDistance; public Node(int t, long m) { tyoten = t; minDistance = m; } @Override public int compareTo(Node o) { int res = -1; if (this.minDistance - o.minDistance >= 0) { res = 1; } return res; } } なにげにcompareToなどの実装が手間取りましたが、これでACしました。 計算量も減ったと思うので、またの機会にもうちょっと制約の厳しそうな問題にも挑戦してみたいと思います。 #追記 costを行列で表している分まだ無駄なメモリを使ってしまっているようです。。 「隣接リスト」を用いると良いそうなのでまたの機会に実装してみます。 ※「競技プログラミング研究月間 - みんなでさらなる高みを目指そう」が開催中のようです。
- 投稿日:2021-06-03T06:07:13+09:00
apache-tomcat起動時のannotation scanning (アノテーション検索)、高速化
調べる元となったトラブル apache-tomcat-8.0.20で起動時に org.apache.tomcat.util.bcel.classfile.ClassFormatException: Invalid byte tag in constant pool となる。 However, if annotation scanning is enabled (metadata-complete="true" in web.xml) there are some issues due to BCEL (not able to process the new Java 8 byte codes). You will get exceptions like (at least with Tomcat 7.0.28): ただし、annotation scanning が有効な場合(web.xmlでmetadata-complete="true")、BCELによる問題が発生します(新しいJava 8バイトコードを処理できません)。以下のような例外が発生します(少なくともTomcat 7.0.28の場合)。 例: SEVERE: Unable to process Jar entry [jdk/nashorn/internal/objects/NativeString.class] from Jar [jar:file:/usr/lib/jvm/jdk1.8.0_5/jre/lib/ext/nashorn.jar!/] for annotations org.apache.tomcat.util.bcel.classfile.ClassFormatException: Invalid byte tag in constant pool: 15 at org.apache.tomcat.util.bcel.classfile.Constant.readConstant(Constant.java:131) これについてtomcatの起動時に annotation scanning を利用しないでよい場合は、catalina.properties の以下にjar名を加えることで回避できる。 catalina.properties # Default list of JAR files that should not be scanned using the JarScanner # functionality. This is typically used to scan JARs for configuration # information. JARs that do not contain such information may be excluded from # the scan to speed up the scanning process. This is the default list. JARs on # this list are excluded from all scans. The list must be a comma separated list # of JAR file names. # The list of JARs to skip may be over-ridden at a Context level for individual # scan types by configuring a JarScanner with a nested JarScanFilter. # The JARs listed below include: # - Tomcat Bootstrap JARs # - Tomcat API JARs # - Catalina JARs # - Jasper JARs # - Tomcat JARs # - Common non-Tomcat JARs # - Test JARs (JUnit, Cobertura and dependencies) tomcat.util.scan.StandardJarScanFilter.jarsToSkip=\ bootstrap.jar,commons-daemon.jar,tomcat-juli.jar,\ annotations-api.jar,el-api.jar,jsp-api.jar,servlet-api.jar,websocket-api.jar,\ catalina.jar,catalina-ant.jar,catalina-ha.jar,catalina-storeconfig.jar,\ catalina-tribes.jar,\ jasper.jar,jasper-el.jar,ecj-*.jar,\ tomcat-api.jar,tomcat-util.jar,tomcat-util-scan.jar,tomcat-coyote.jar,\ tomcat-dbcp.jar,tomcat-jni.jar,tomcat-spdy.jar,tomcat-websocket.jar,\ tomcat-i18n-en.jar,tomcat-i18n-es.jar,tomcat-i18n-fr.jar,tomcat-i18n-ja.jar,\ tomcat-juli-adapters.jar,catalina-jmx-remote.jar,catalina-ws.jar,\ tomcat-jdbc.jar,\ tools.jar,\ commons-beanutils*.jar,commons-codec*.jar,commons-collections*.jar,\ commons-dbcp*.jar,commons-digester*.jar,commons-fileupload*.jar,\ commons-httpclient*.jar,commons-io*.jar,commons-lang*.jar,commons-logging*.jar,\ commons-math*.jar,commons-pool*.jar,\ jstl.jar,\ geronimo-spec-jaxrpc*.jar,wsdl4j*.jar,\ ant.jar,ant-junit*.jar,aspectj*.jar,jmx.jar,h2*.jar,hibernate*.jar,httpclient*.jar,\ jmx-tools.jar,jta*.jar,log4j*.jar,mail*.jar,slf4j*.jar,\ xercesImpl.jar,xmlParserAPIs.jar,xml-apis.jar,\ junit.jar,junit-*.jar,ant-launcher.jar,\ cobertura-*.jar,asm-*.jar,dom4j-*.jar,icu4j-*.jar,jaxen-*.jar,jdom-*.jar,\ jetty-*.jar,oro-*.jar,servlet-api-*.jar,tagsoup-*.jar,xmlParserAPIs-*.jar,\ xom-*.jar,jackson-databind-2.10.3.jar,jackson-core-2.10.3.jar など。 調べた結果の副産物 この annotation scanning は起動時間にもかかわるもの。以下参考。 (アノテーション検索 などで情報が出てくるようだ。) web.xml <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4" metadata-complete="true"> 簡単に以上です。
- 投稿日:2021-06-03T03:34:56+09:00
同一性と同値性についてよくわからないのでわかりやすく考える。
同一性と同値性について なんだか様々なサイトで同一性と同値性について語られているがよくわからない。 String型の変数は==で比較したらだめとかよく言われますがなぜダメなんでしょうか?次のサンプルコードを見てみます。 Prac.java public class Prac { public static void main(String[] args) { String code = new String("+"); String code1 = new String("+"); System.out.println(code == code1); } } 上記のコードは実行すると false ん? trueが出力されるはずのコードです。 しかし System.out.println(code == code1); ここで==の比較を行うとfalseになります。全く同じもののはずなのに。 ==で行う比較は同一性を判断します。これらは同一ではないようです。 同一性とはなんでしょうか。 同一性 おそらくこのあたりでインスタンスの概念がでてくるので飲み込むのが難しい。 左辺と右辺でオブジェクト(インスタンス)が同じならば、同一であると言えるのだが、どういうことかよくわからん。 System.out.println(code == code1) 初学者がこれをみているとcodeに+がはいっているならばcode1も+で同じだからtrue返しそうだと思ってしまう。 しかしfalseになるのはなぜなのか。 オブジェクト(モノ)について考えてみると答えが見えるかも。 同一性について辞書に次のような記述があった。 異なる事物が、その性質から見ると区別できないこと。 双子は異なる人間だが、型は同じ人間、みたいな話ですかね。 でも両方String型で型は同じやし。。。 String code = new String("+"); String code1 = new String("+"); こいつらが同一では無い意味がまじでわからない。。 どうやらJavaでは異なるオブジェクト(インスタンス)変数(型は関係ない)では同じ値でも同一ではない。 二つの値を見ているというよりかは出どころが違う(格納されているメモリ)が違うので同一ではないと判断されている。 同値性 同値性とは次の比較である。同値性は先ほどとは違い、単純な値同士の比較。つまり意味的に同じならばtrueになる。 System.out.println(code.equals(code1)); true 最後に おそらくJavaを学ぶにあたっての結構はじめにつまづくと思うトピックについてまとめた。 Java難しい。。
- 投稿日:2021-06-03T01:14:02+09:00
javaでコーディング中にちょっとした確認したいときにifの代わりにassertを使う
例えば以下のようなケースです。 入門書とかにはしっかり書いてありますが、意外と忘れてたり使ってなかったりします Main.java public static void main(String[] args) throws Exception { // 構文 assert テスト対象 : 失敗したときのメッセージ assert sum(2 ,4) == 6 : "method \"sum\" result is Unexpected. arg[0]: 2, arg[1]: 4"; assert sum(2 ,5) == 6 : "method \"sum\" result is Unexpected. arg[0]: 2, arg[1]: 5"; } static int sum(int a, int b){ return a + b; } assertが成功した場合何も起こりません。失敗すると以下のように教えてくれます。 Exception in thread "main" java.lang.AssertionError: method "sum" result is Unexpected. arg[0]: 2, arg[1]: 5 at Main.main(Main.java:8) アサーションを有効にするには、実行時のオプションに-enableassertionsを付けてやる必要があります。