System.out.println("またJavaの季節がやってきた!" + 2);
■ このスレッドは過去ログ倉庫に格納されています
去年の今頃Java学習開始するも挫折
しかし不屈の闘志をめらめらと燃やしながら
そびえ立つ岩壁にいどむため、再びこの地にやってきたのだ!
プログラミング歴は独学Cチョビッツ+独学VBA少々
きょうかしょ
https://www.amazon.co.jp/dp/484433638X
スッキリわかるJava入門 第2版 (スッキリシリーズ) public class Book {
public boolean equals(Object o) {
if (o == this) return true;
if (o == null) return false;
if (!(o instanceof this)) return false;//←ここダメ
}
}
A instanceof B
は
「参照型変数a が bクラス/インターフェース/配列のインスタンスかどうか」
を調べるものなので
Bにインスタンスを持ってきてはダメ
Bに来るのはこの場合だとクラス名のBook
if (!(o instanceof Book)) return false;
が正解 >>219
正規表現で\sという文字列を表すにはエスケープして\\sとなる
だがこれをそのまま引数に渡すとJVMが最初の\を文字エスケープと認識して\sという文字列に変換し、結果的に正規表現の空白文字にマッチするか検証することになる
\\sという文字列を正規表現として渡すには文字エスケープが2つ付けて、\\\\sとする必要がある >>227
なるほどねぇ
言われてみればそうだな
String s = "\\s";
System.out.println(s);
if (s.matches("\\\\s")) {
System.out.println("ok");
}
ちなみにだけど、>>227の前半部分の説明を \n についてすると? ラムダ式とかの6章クリア
練習問題とstream()の基本的な使い方ぐらいだけど、まぁいいか
ぐぐるとラムダ式使ってるコードってたまに出てくるから
参考にしたいときに使える知識かなとは思う ProcessBuilder pb = new ProcessBuilder(
"c:\\windows\\system32\\notepad.exe", "calcreport.txt");
ProcessBuilder pb = new ProcessBuilder("java", clazz.getName() );
こいつら、上が第7章198ページ、下が同じく第7章217ページ練習問題の答
上が本文内で出てきたときは、まぁこんな感じで外部のexe起動できるんだな
ああそうですか、で終わった
練習問題で下のが出てきて???????????????ですわ
一応練習問題はできるようにするという目標を立てているので、しゃーないから調べてみた
意外と簡単だった
つまりだ、
●CMDでなんかプログラムを起動するときに
>xxx yy zz
みたいに打ちこんでEnterパーン!てやるとする
ちなみにxxxはexeだったりいろいろ
●これをJavaから同じように起動したいと思うなら
ProcessBuilder pb = new ProcessBuilder("xxx", "yy", "zz");
pb.start();
具体的に書くと
●CMD
>notepad /W test.txt
●Java
ProcessBuilder pb = new ProcessBuilder("notepad", "/W", "test.txt");
pb.start();
CMDでnotepadのかわりにnotepad.exeとしてもいいのだが
これはJavaのほうでも同じで "notepad" のかわりに "notepad.exe" としてもよい
ちなみにメモ帳はパスが通ってるからCMDにおけるカレントフォルダがどこであっても
notepad.exeへの完全なパスなしで起動できる
ProcessBuilderの第一引数においても同様に絶対パスを書く必要はない
とにかくCMDでどう書くのかを参考にして書けばいいだけ
よって上に書いた1個目のProcessBuilderの宣言で
ProcessBuilder pb = new ProcessBuilder("notepad.exe", "calcreport.txt");
と書いてもいける
ただし、違いが一つある
CMDだとcalcreport.txtがカレントフォルダになければ新しく作りますか?
とのウィンドウがでる
Javaではcalcreport.txtが存在しないとエラーが生じる
2つ目の
ProcessBuilder pb = new ProcessBuilder("java", clazz.getName() );
も同様
CMDでFQCNを使ってclassファイルを実行する場合に
>java jp.co.aaa.Calc
としてEnterパーン!とするなら
Javaでは
ProcessBuilder pb = new ProcessBuilder("java", "jp.co.aaa.Calc");
pb.start();
と書く
第二引数が clazz.getName() となっているのはFQCNを取得するためだ 👀
Rock54: Caution(BBR-MD5:1341adc37120578f18dba9451e6c8c3b) >>230の2つ目を考えるにあたって注意しなければならないこと
あくまでも ProcessBuilder は「外部」プログラムの実行に使われる
よって、
Javaのクラスファイルを実行するといっても、
外部に存在しているコンパイル済のクラスファイルの実行に使うであって
今現在組んでいるソースコードに存在する他のクラスを指定してもダメ
コードが正常に動くか実験したい時に勘違いしないようにする Eclipseで楽してたらコマンドラインから実行する方法忘れてしまった
例:
Main.class
-----------------------
package aaa;
public class Main {
public static void main(String[] args) {
System.out.println("test");
}
}
-----------------------
(パスを通さないことを前提に説明・カレントフォルダ名はtestとする)
これをコマンドラインから起動するときは
フォルダtestの中にフォルダaaaを作る
その中にMain.classを入れておく
propertiesファイルとか使うなら
フォルダtestに入れておく
CMDでフォルダtestに移ってから
>java aaa.Main
で起動
eclipseのワークスペースからクラスファイルを拾ってくる時は
binフォルダの中をみればいい
ただ、この中にMain.classとは異なる見慣れないものが入ってたりする
Main$1.class
Main$2.class
Main$3.class
eclipseがバックアップ用に用意したものかと思ってフォルダaaaにコピペしなかったらエラー
表示をみるとどうやらこいつらも必要なようだ
この3つもaaaに放り込んだらうまく起動した ProcessBuilderのテストはまた今度にしよう ここつまんねぇなぁ
覚えても意味なさそうだぁ
とか思っててもいざ練習問題ちゃんと出来るようにしようとすると
派生的にいろんな所の復習することになる
この 「いろんな所」 が結構大事な分野だったりするんで
結局がんばってやったほうがいいんだろうな よし、ProcessBuilderによるclassファイル実行でけた
eclipseの今扱っているプロジェクトのプロジェクトフォルダの直下に
フォルダaaaをおいてこの中にMain.classを入れる
ProcessBuilder pb = new ProcessBuilder("java", "aaa.Main");
pb.start();
で起動確認済 >>235の状況下で
Class<?> c = Class.forName("aaa.Main");
System.out.println(c.getName());
はできなかった
ProcessBuilderではいけるのになぜだ
もしかしてと思いながらbinフォルダの中にaaaフォルダをぶちこんだら行けてしまった
手法がどうであれ、ClassクラスもProcessBuilderと同様に外部のクラスファイルに
アクセスできるようだ eclipseでコマンドライン引数を渡して実行する方法
実行の構成→「引数」タブ→プログラムの引数
ここにコマンドライン引数を並べればいいだけ >>236はちと違う感じがする
クラスファイルへのアクセスってのは内部も外部もないのでは。
この辺は学習が進めばハッキリしてくるだろう 7章の練習問題は解答が間違えてるようだ
https://teratail.com/questions/153338
問題の指示によると、
文字列配列を引数とするmainメソッドの存在を確認しなければならない
存在する場合のみ、第二引数による条件分岐に入る
にもかかわらず、
@条件分岐に入ってから存在確認処理をしているのが第二引数が I のケース
Aそもそも存在確認を行ってさえいないのが第二引数が E のケース
@の存在確認とは、
getMethod()によって 文字列配列が引数であるmainメソッドを指定している
この条件に当てはまるメソッドがない場合に例外が投げられるようになってる
(throws Exception)
例外はメソッドを呼び出したmainメソッドで処理される
という部分を指している >>239の間違いを正したコードを書いてた
これでいいだろと思って実行してみるんだけど
ProcessBuilder による起動がうまくいかない
起動するクラスのmainメソッドには
System.out.println("eating memory.......");
と書いてあるのだが、これが表示されない
ProcessBuilderによるクラス実行は実験済で間違いないはずなのだが
いろいろやっても上コメントが表示されない
まさかな、と思ってこれを実行するクラスのmainメソッドに追加
JFrame jf = new JFrame();
jf.setSize(100, 100);
jf.setVisible(true);
そしたらなんとフレームが出現するじゃないか
ProcessBuilderによる実行は、「外部プログラム」の実行なので、printlnがあっても
内部的な処理結果を表示するコンソール画面には出ないということか
ちなみに実行するクラスファイルはbinフォルダに置いたままではだめ
プロジェクトのフォルダ直下に置く
ProcessBuilderによる実行は、やはり「外部のプログラム」を動かすものなので
eclipse上、カレントフォルダはプロジェクトのフォルダ直下(この辺は不確実) いやはや
やたら時間を食う章だ
今日はこの辺で終わり ちなみにリフレクションによる実行では
ちゃんとコンソールにprintlnの内容が表示される
これが
External Launch と
Internal Launch の違いってことかな >>238の続きなんだけど、リフレクションによる実行は「内部」だね
>>236で、binフォルダにaaaをぶち込むと実行できたのは
まさにbinフォルダが内部的なものだからだ
普通にクラスのソースコードを書いて実行するとbinフォルダにクラスファイルが生成される
つまり、binフォルダにクラスファイルを置くということは、
ソースコードに書いたのと結果的に同じ
外部のクラスファイルを持ってきたという考えはしない方がいい >>239の問題をクリア
@で使っている例外を利用してmainメソッドの存在確認をする方法は
秀逸だと思うので、これはちゃんと利用する
ただし、
launchInternalメソッドの中に書くのではなく
mainメソッドに書く
---------------------------------------------
try {
m = c.getDeclaredMethod("main", String[].class);
} catch (NoSuchMethodException e) {
System.out.println("指定されたメソッドが存在しません。");
System.exit(1);
}
-----------------------------------------------
m は static なクラス変数として宣言したMethodクラスのインスタンス変数
クラス変数としたのは launchInternalメソッドにおいて invoke するのに流用するため
あと、launchExternal メソッドで起動した場合に起動確認のためJFrameを表示させたい
そこでMemoryEaterクラスの main メソッドの中にJFrame表示のコードを入れた
さらにフレームタイトルに launchInternal、 launchExternal どちらから起動されたか
わかるように I か E の文字をいれることにする
そのため、これらのメソッドを起動する際に、I か E の引数を渡すことにする
内部起動か外部起動かによって引数の渡し方が違ってくるところがポイント
-------------------------------------------------------------
public static void launchExternal(Class<?> clazz) throws Exception {
ProcessBuilder pb = new ProcessBuilder("java", clazz.getName(), "E");
Process proc = pb.start();
proc.waitFor();
}
public static void launchInternal(Class<?> clazz) throws Exception {
String[] args = {"I"};
m.invoke(null, (Object)args);
}
-------------------------------------------------------------- この問題は例外処理の復習になる
●例外インスタンスを自分で投げるケース
throw new IllegalArgumentException("起動方法の指定が不正です");
IllegalArgumentExceptionはメソッドの引数が不正
●例外を伝播させる
public static void launchExternal(Class<?> c) throws Exception { }
throws と複数になってるところがポイント
●例外処理中の e.getMessage() とは
これは e.printStackTrace() を使った場合に表示されるメッセージが冗長なため、
これらのメッセージのうち一部分だけを表示させたいときに使うようだ
具体的には、今取り組んでるコードにおいて、実行対象となるクラスにmainメソッドがない場合
もし e.printStackTrace() なら
-----------------------------
java.lang.NoSuchMethodException: MemoryEater.main([Ljava.lang.String;)
at java.lang.Class.getMethod(Class.java:1786)
at Main.main(Main.java:19)
------------------------------
もし System.out.println(e.getMessage()); なら
------------------------------
MemoryEater.main([Ljava.lang.String;)
------------------------------
調べた結果このようになったのだが、疑問に感じたのは実践編7章解答で
catchの中にこのような記述がある
System.out.println(e.getMessage());
e.printStackTrace();
包含関係にあるこの2つを並べることに何の意味があるのか分からない
今のところは自分が調べた結果を信じることにしておこう
e.getMessage()はエラーメッセージを簡潔に書きたいときに使うもの、とする あとこれ
Method m = clazz.getMethod("main", String[].class);
getMethodメソッドの第二引数 String[].class
この class は何なんだ!
調べまくって何となく分かったんだけど、要はこの class は実践編209ページの
Class インスタンスの基本的な取得方法の一つ
Class<?> cinfo = クラス名.class
の class と同じものだということ。
String[].class は文字列型配列に関するClassクラスのインスタンスである
リフレクションと呼ばれる分野について学習してるわけなんだけど
特徴的なのはあるクラスを対象とするとき、
そのクラスを対象とするClass クラスのインスタンスを生成する点
この先はざっくりとした説明になる。
場合によるのだろうが、この分野において、
メソッドに渡す引数の(クラス)型を指定するときも
同様の配慮をしなければならないようだ
つまり、メソッドの仮引数が
int i となっていたら、実引数は
int.class のように表現する場合があるということ
getMethod のレファランスを見てみると
public Method getMethod(String name,
Class<?>... parameterTypes)
Class<?> はまさにClassクラスのインスタンスをここにもってこいという事 clazz の宣言文を補足する
例えばこんな風になる
Class<?> clazz = MemoryEater.class;
Method m = clazz.getMethod("main", String[].class);
これは、下のように書いてもよいということになる
Class<?> clazz = MemoryEater.class;
Class<?> stClazz = String[].class;
Method m = clazz.getMethod("main", stClazz);
分析の対象となるクラス(MemoryEater)もClassクラスのインスタンスを生成し
分析の対象となるクラスで使われる引数のクラス型(String[])についても
Classクラスのインスタンスを生成して使いなさい!ということらしい クラス名.class
クラスリテラルとかなんとか
タイプリテラルとか
リテラル記法とか
なにやらかなり特殊な書き方のようだ
今日はこれで終わり 自作Classに含まれるメソッドリスト
main
wait
wait
wait
equals
toString
hashCode
getClass
notify
notifyAll
これまで間違えてコードを書いてたみたいで
main以外表示されてなかったんだけど、さっき間違いに気づいて修正
こんなにでてきた
Objectクラスから引き継いだものも表示されるのな
複数のwaitはオーバーロードか コマンドライン引数によって受けとったclassファイルを
ProcessBuilderによって起動するテストをeclipse上でやろうとすると失敗することが多い
というかclassファイルのソースコードを修正しては起動するみたいなことをしていると起動しなくなったりする
eclipse上ではなくてちゃんとコマンドラインから起動すれば正常に動くので
eclipseの問題なのか
まぁこれ以上ここに時間を費やすのもどうかと思うから追究するのはやめるか 今日はずっと前にやってたところの復習してた
せっかく覚えたのに忘れるのもったいないからたまにやらないとね 9章269ページあたりを読んでるんだけど
System.out.println() とは結局何なのだろうかと。
System はクラス名で
out はそのフィールドで、型は PrintStream
つまり System クラスでは
PrintStream out;
みたいな宣言があるわけだ
(実際には public final static PrintStream out = null;)
んで、PrintStream クラスのメソッドの一つに
println() がある
out はクラス型をフィールドに用いたもの
すっきり入門340ページの Hero クラスのフィールドとして宣言されている
Sword sword;
と同じようなものか
341ページの下に
hsword.name
というのがあるが、もし Sword クラスの name フィールドが private で
getter が置かれているとしたら
@ h.sword.getName()
となっていたはず
これと
A System.out.println()
は結構似てると考えていいのか
違いは、@では Hero クラスの中で宣言されている sword は static ではないため
アクセスするには Hero クラスのインスタンス h を生成したが
Aでは、System クラスの中で宣言されている out が static 宣言されているため
インスタンス生成が不要だった点 こういった構造を、フェイクを使いながら書くと、こんな感じになるのか
これでいいのかな
警告はでてるけど実行可
public class Main {
public static void main(String[] args) {
Systemm.outt.printlnn("aaa");
}
}
class Systemm {
static PrintStreamm outt;
}
class PrintStreamm {
public static void printlnn(String st) {
System.out.println(st);
}
} >>253の PrintStreamm#Printlnn から static を抜いたら警告が消えた
理由はあとで考えることにする
public class Main {
public static void main(String[] args) {
Systemm.outt.printlnn("aaa");
}
}
class Systemm {
public static PrintStreamm outt;
}
class PrintStreamm {
public void printlnn(String st) {
System.out.println(st);
}
} 例えばこのスレを 「2ch.txt」 に全コピペして保存
(例外は投げるとする)
FileReader fr = new FileReader("2ch.txt");
BufferedReader br = new BufferedReader(fr);
String line = br.readLine();
while (line != null) {
System.out.println(line);
br.readLine();
}
これだと文字化けしてしまう
そこで文字コードを指定したい
実践編260ページの記述によると、
FileReaderのコンストラクタで文字コード指定ができるかのように思われるが
実際はできない。いや出来るのかもしれないが調べた限りでは分からなかった ぞ
文字コードの指定には
FileInputStream
InputStreamReader
を使う
(この辺はHTML取得の時に使ったコードに似てる
URL、InputStream、InputStreamReader を使った)
FileInputStream fis = new FileInputStream("2ch.txt");
InputStreamReader isr = new InputStreamReader(fis, "SJIS");
BufferedReader br = new BufferedReader(isr);
String line = br.readLine();
while (line != null) {
System.out.println(line);
br.readLine();
}
これで文字化け回避できた
SJIS はググってでてきたものを適当にいれたらいけたってだけ TeraPad というテキストエディタを昔から使っているのだが、
下の方に文字コードが表示される
試しにこのスレやgoogleの検索結果のページやらをコピペしてみたり
パソコン内にあるいろんなファイルをTeraPadで開いてみたりしたが
全て SJIS と表示されていた
というか SJIS と指定して開いているからそう表示されるのかもしれないが
少なくとも、TeraPad でみたときに文字化けしていない状態で、SJIS と表示されているなら
SJIS がこの場合の正しい文字コードなんだなと
ちなみにeclipse上で、デフォルト文字コードを取得するこれ
System.out.println(System.getProperty("file.encoding"));
を確認してみると UTF-8 と表示される
この違いが文字化けの原因だ この辺はstream関連のクラスがたくさん出てきて何がなんだか分からなくなる
整理する
-------------------------------基本用語
●文字ストリーム系
Writer、Reader がクラス名に入る
●バイトストリーム系
OutputStream、InputStream がクラス名に入る
--------------------------------
・基本用語の頭に File がつくと
ストリームの終端がファイルであるクラスになる
・基本用語の頭に Buffered がつくと
バッファリングされた出力または入力ストリームをつくるクラスになる
・特殊なものとしてバイトストリームと文字ストリームの橋渡しをするクラス
OutputStreamWriter : 文字をバイトにエンコード
InputStreamReader : バイトを文字にエンコード
どちらも指定された文字セットを用いて変換することになるが
指定がなければシステムのデフォルトの文字セットを用いることになる
この文字セット指定がまさしく >>255でやった "SJIS" である
ここでは文字セットとは文字コードと同義か >>255を再考
FileInputStream fis = new FileInputStream("2ch.txt");//@
InputStreamReader isr = new InputStreamReader(fis, "SJIS");//A
BufferedReader br = new BufferedReader(isr);//B
String line = br.readLine();
while (line != null) {
System.out.println(line);
br.readLine();
}
>>257の「基本用語」に注目しながら分析
@一旦バイトストリームによってファイルを読み込んでいく (バイトだからInputStream)
A吸い上げたバイトを文字にエンコードするが、その際文字セットを SJIS に指定 (橋渡し役)
B変換された文字をバッファリングする (文字だからReader) InputStreamReaderのせいで頭が混乱してた
常に文字セットを指定してれば橋渡し変換役だってことが理解できてたんだけど
文字セット指定がないデフォルトでこれまで使ってたんで
役割が頭ん中で明確になってなかった public class Main {
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
BufferedOutputStream bos = null;
GZIPOutputStream gos = null;
try {
fis = new FileInputStream("test.txt");
fos = new FileOutputStream("test.txt.gz");
bos = new BufferedOutputStream(fos);
gos = new GZIPOutputStream(bos);
int i = fis.read();
while (i != -1) {
gos.write(i);
i = fis.read();
}
} catch(IOException e) {
e.printStackTrace();
} finally {
try {
if (fis != null) fis.close();
if (gos != null) gos.close();
} catch(IOException e) {
}
}
}
}
実践編9章の練習問題
コマンドライン引数はテストが面倒なので内部指定した
test.txt を読み込んで、同じ内容を test.txt.gz にかき込むんだけど、
書込みの際のフィルタリングとして
バッファリング+圧縮
が指示されている
文字ストリームは一切使わず
バイトストリームのみで処理するため
Reader、Writer がついたクラスは出てきていないのがポイント FileOutputStream
↓
BufferedOutputStream
↓
GZIPOutputStream
の順でフィルタにかけてるんだけど
FileOutputStream
↓
GZIPOutputStream
↓
BufferedOutputStream
でやったらどうなるかテストしてみた
作成されるgzファイルが壊れてた
GZIPOutputStream が最後じゃないとだめみたいだ >>260修正
gos.flush();
を忘れてた
while ブロックの直後に挿入するとする
ふらぁぁぁぁぁぁぁっしゅ! >>261
逆でもいけるやろ
どっちもOutputStreamのサブクラスなんやから
gzip形式で圧縮してるんだから直で開いても見えへんで
解凍するかGZIPInputStream使わんと
public class Main {
public static void main(String[] args) {
try (BufferedInputStream fis = new BufferedInputStream(new FileInputStream("test.txt"));
BufferedOutputStream gos = new BufferedOutputStream(new GZIPOutputStream(new FileOutputStream("test.txt.gz")));) {
int i;
while ((i = fis.read()) != -1) {
gos.write(i);
}
} catch (IOException e) {
e.printStackTrace();
}
try (BufferedReader gis = new BufferedReader(new InputStreamReader(new GZIPInputStream(new FileInputStream("test.txt.gz"))));) {
String str;
while ((str = gis.readLine()) != null) {
System.out.print(str);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
} >>263
ほんとだ
たぶんコードをどこかで間違えてたな
しかしわかりにくいので勝手に改変
GZIP→Buffer (test_gos-bos.txt.gz)
Buffer→GZIP (test_bos-gos.txt.gz)
フィルタ順を変えた2つ圧縮ファイルが作られるがどちらも正常
public class Main {
public static void main(String[] args) {
try (BufferedInputStream fis = new BufferedInputStream(new FileInputStream("test.txt"));
BufferedOutputStream bos = new BufferedOutputStream(new GZIPOutputStream(new FileOutputStream("test_gos-bos.txt.gz")));) {
int i;
while ((i = fis.read()) != -1) {
bos.write(i);
}
} catch (IOException e) {
e.printStackTrace();
}
try (BufferedInputStream fis = new BufferedInputStream(new FileInputStream("test.txt"));
GZIPOutputStream gos = new GZIPOutputStream(new BufferedOutputStream(new FileOutputStream("test_bos-gos.txt.gz")));) {
int i;
while ((i = fis.read()) != -1) {
gos.write(i);
}
} catch (IOException e) {
e.printStackTrace();
}
}
} 自分のコードでも成功
public class Main {
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
BufferedOutputStream bos = null;
GZIPOutputStream gos = null;
//bos→gosの順
try {
fis = new FileInputStream("test.txt");
fos = new FileOutputStream("test_bos-gos.txt.gz");
bos = new BufferedOutputStream(fos);
gos = new GZIPOutputStream(bos);
int i = fis.read();
while (i != -1) {
gos.write(i);
i = fis.read();
}
} catch(IOException e) {
e.printStackTrace();
} finally {
try {
if (fis != null) fis.close();
if (gos != null) gos.close();
} catch(IOException e) {}
}
//gos→bosの順でもOK
try {
fis = new FileInputStream("test.txt");
fos = new FileOutputStream("test_gos-bos.txt.gz");
gos = new GZIPOutputStream(fos);
bos = new BufferedOutputStream(gos);
int i = fis.read();
while (i != -1) {
bos.write(i);
i = fis.read();
}
} catch(IOException e) {
e.printStackTrace();
} finally {
try {
if (fis != null) fis.close();
if (bos != null) bos.close();
} catch(IOException e) {}
}
}
} fos = new FileOutputStream("test_bos-gos.txt.gz");
を
fos = new FileOutputStream("test.txt_bos-gos.gz");
と指定すると
中身のファイルが、拡張子なしの
test.txt_bos-gos
になるという事に気づいた
こういう仕様なのか
ちなみに作成された圧縮ファイルが正常化どうかのチェックは
WinRARを使って適当にやってる そして flush() がまた抜けているという件
ふらぁぁぁぁっぁぁぁぁぁっしゅ!!! finally使わないでいい書き方だけど
try () のカッコの中に複数文書いてもいいんだな
おれはこういう風に書きたい
public class Main {
public static void main(String[] args) {
try (
BufferedInputStream fis = new BufferedInputStream(new FileInputStream("test.txt"));
BufferedOutputStream bos = new BufferedOutputStream(new GZIPOutputStream(new FileOutputStream("test_gos-bos.txt.gz")));
) {
int i;
while ((i = fis.read()) != -1) {
bos.write(i);
}
} catch (IOException e) {
e.printStackTrace();
}
}
} 12章のデータベースアクセスを読んでいるのだけど
実践編の次の位置にあるテキストとして
スッキリわかるSQL入門がある
これはJavaのテキストかと思っていたのだが
そういうわけではなさそうだ
「スッキリわかるサーブレット&JSP入門」 はJavaのテキスト
この2冊に踏み込むべきか、迷うところだ ん〜いろいろぐぐってみたがSQL入門は買っておいたほうがよさそうだな
どうせだからサーブレットの方も買うか? それはともあれ、データベースは実践編12章で触ることになるため
DBMSの導入が必要となる
ここでは実践編が勧める HS Database を導入することにする
インストールまでは簡単だ
適当にぐぐれば出てくる
次に・・
実践編335ページ
>以後、この章のプログラムの実行時には、このJARファイルにクラスパス
>(eclipseの場合はビルドパス)を通して実行する必要があります。
eclipseを使っているのでビルドパスとやらを通さなければならない
調べた結果
ビルドパスはプロジェクトごとに通していくことになる
ここでいうJARファイルとは、バージョンごとにファイル名は違うだろうが
おそらくH2 Databaseをインストールしたフォルダにあるこれ
H2\bin\h2-1.4.197.jar
であろうと推測できる
このjarファイルを外部のライブラリとして追加していくことを意味するのだろう
まずプロジェクトのプロパティーを開く
方法はいろいろあるが、パスを通したいプロジェクトをパッケージエクスプローラで選択した状態で
プロジェクト→プロパティー
次に
→「ライブラリー」タブ→外部JARの追加
ここで上記のjarファイルを選択する
こうすることで、パッケージエクスプローラ上で、当該プロジェクトを開いた場合に
「参照ライブラリー」 が追加されており、この中に h2-1.4.197.jar が配置されることになる
不正確なら以後修正していく public class Main {
public static void main(String[] args) {
try {
Class.forName("org.h2.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Connection con = null;
try {
con = DriverManager.getConnection("jdbc:h2:G:\\DB\\H2_Database\\test01");
} catch(SQLException e) {
e.printStackTrace();
} finally {
if (con != null) {
try {
con.close();
} catch(SQLException e) {
e.printStackTrace();
}
}
}
}
}
ファイルが作成されたので、これでとりあえずいいのか
Class.forName("org.h2.Driver");
の org.h2 については、パッケージエクスプローラから h2-1.4.197.jar を開くと
直下に同じ名前のパッケージがあるので、これだろう ん〜ん〜
実践編361ページのコード
これおかしくないか?
いろいろとまだ知識が固まってないので自信あるわけではないが
con.close();
の位置
finally ブロックに書かれているのは、どんなときでも必ず実行されなければならないから。
(もちろん if 文で示す通り null の時は除くけど)
しかしだ、この finally ブロックが置かれている位置、catch ブロックの「中」だぞ?
ということは例外が catch されなければ実行されないんじゃないのか?
おかしいのであれば誰かネット上で指摘してるはずだと思って
ぐぐってみたけどヒットしない
おれがおかしいのですか〜 public class Main {
public static void main(String[] args) {
//finallyが※の内側のケース
try {
Class.forName("org.h2.Driver");
} catch (ClassNotFoundException e) {//※
System.out.println("@");
try {
Class.forName("org.h2.Driver");
} catch(ClassNotFoundException ee) {
System.out.println("A");
} finally {
System.out.println("finally内側");
}
}
//finallyが※の外側のケース
try {
Class.forName("org.h2.Driver");
} catch (ClassNotFoundException e) {//※
System.out.println("A");
try {
Class.forName("org.h2.Driver");
} catch(ClassNotFoundException ee) {
System.out.println("B");
}
} finally {
System.out.println("finally外側");
}
}
}
結果は 「finally外側」
「finally内側」 が表示されるのは、一つ目の※で存在しないクラスを指定した時
この時例外をキャッチして catch ブロックに入る
そこで初めて finally は実行される
ん〜おかしいよね? いや、話はもう少し複雑なのか?
con が catch 文の中でも使われているから内側、外側両方で finally がいるということか?
つまり上の例で言えば
public class Main {
public static void main(String[] args) {
try {
Class.forName("org.h2.Driver");
} catch (ClassNotFoundException e) {//※
System.out.println("@");
try {
Class.forName("org.h2.Driver");
} catch(ClassNotFoundException ee) {
System.out.println("A");
} finally {
System.out.println("finally内側");
}
} finally {
System.out.println("finally外側");
}
}
} いやいや、やっぱり違う
内側で使った con は結局、外側の finally で close されるからいいんだ
やっぱ内側の finally は必要ないはずだ
にも関わらず実践編361ページでは内側のみに finally があるのでおかしいなぁ
というのが疑問点 ま、とりあえず12章まで読むだけ読んだ
ちょい飛ばしたから、今週は先へは進まずに復習のみでもおkか とか言いながら、斜め読みしながら先へ進むおれ
「リファクタリング」
これな
以前VBAの10,000行ぐらいのプログラム書いたんだけど
おれが組んだもので一番でかいやつ
今も他人によって使われてて、自分でいうのもなんだけど役に立っている
しかし中のコードはひどいもので
その原因の一つは、VBAを一から勉強しながら書いていたから、
勉強初期の頃のコードと、それなりに理解できてきた頃のコードが絡まり合って、それはもう。
もう一つは、計画性がなく気ままに機能を追加してきた結果、ネストの階層がとんでもなく深い
滅多に表層にでないバグを潰したりして、最終的に完成するまでに2年はかかっている
たぶんもう一度組み直せばすっきりとして実行速度もあがると思うのだが
あの苦労をもう一度・・・と思うと。
コードをいじらないでも設定を柔軟に変えられるよう、
各種設定値をワークシート上に記述できるようになってはいるのだが
実は全て正常に動くかは全部チェックしてない
この辺も組み直す過程でチェックできるだろう
今はおれが触れる場所にいるのでなんとかなるのだが
いずれ離れる予定なので、それまでにはなんとかしないといけないのだが。
めんどい 初心者あるあるやね
ワイも昔は一つのクラスの中にズラーっと書いて保守性も拡張性も考えとらんかった
といってもプログラミング始めてまだ半年の素人やけども
最近は機能別にクラス分けするようにしとるけど、今度はどう設計するか考えんといかんからこれはこれで大変
>>272
finallyでcloseするとネストが深くなって可読性が落ちるし、し忘れることもあるからauto_closeにしたほうがええで try {
} catch() {
} finally {
if () {
try {
} catch() {
}
}
}
これはもうルーチンワークだわ
closeまで書いてから対象となるインスタンス生成してるぐらいだ
try(){} をベースにしようか迷ったけど
めんどくさい方を先に覚えて間違えずに書けるようにしたほうがいい
簡略化が導入されるまでみんな書いてたものだしね スッキリわかるSQL入門 第2版 ドリル222問付き! (スッキリシリーズ)2018/11/30
中山清喬、 飯田理恵子
新しい版がでるそうなのであと3週間ほど待つ事にしよう 実践編どくはああああああああああああああああ
寄り道したくなってきたぞ 「独学プログラマー」
という本をテキストとして使う
IDLEというPython付属のIDEをテキストでは使っているのだが
PyCharmで普通にpyファイルを新規作成してコード書いて実行した場合と微妙に違うようだ
もしかしてーと思いつつ、左下のほうの「Pythonコンソール」とやらのタブを押してみたら
それっぽいのが出てきたので、コードを打ち込んでみたら正解だ
IDLEをここで使えるようだ
なかなか便利である
ちなみにプロジェクトの削除はPyCharm上でやるのではなく
作成されているプロジェクトフォルダをエクスプローラ上から削除してから
PyCharmを再起動すれば消えている print(3 ** 300)
136891479058588375991326027382088315966463695625337436471480190078368997177499076593800206155688941388250484440597994042813512732765695774566001
プロセスは終了コード 0 で完了しました
おお・・・・ こういうでかい数字はjavaだと扱ったことないからわからんのだけど
難しいんではないのか
すごいとおもたぞ この対話シェルとやらは、簡単なチェックのために使うのはよさそうだが
いろいろと学習上誤解を招きそうな機能だな
多言語やってきたおれは、2と打ち込んで実行すると2が表示されることに違和感を感じることができるが
全くの初心者はそれが当たり前だと思っちゃうよな
いや、ある意味学習が捗る部分もあるのだけれども 論理演算子はVBAと同じか
and
or
not
if 文は条件はカッコなしで文末にコロン :
ヘッダーとスイート 対話シェルじゃなくてpyの方に書いていくことにしているのだが
def ppp(a, b):
return a + b
print(ppp(2, 5))
こういうの書くと関数のあとは2行は空けろとか言ってくる
Pythonは空行とかタブとか五月蠅いのな うわ、行空けすぎるとおこられるw
あと、関数に渡す引数のデフォルト値設定で
def ppp(n = 1):
ってやったらスペースいれるなって怒られる
def ppp(n=1)
にしろだと なるほどねー
1/3ぐらい読んでみたけど、
Pythonはわかりやすい、悪く言えばいい加減な感じ
今日は終わり! 今日はhtmlの基礎
テキストは
「これからWebをはじめる人のHTML&CSS、JavaScriptのきほんのきほん」
ここに書いてあるHTMLやらCSSの簡単なコードをとりあえず
ぱぱぱぱぱぱっと書けるようにしていく
やったことないわけではないんだけど、
JavaScriptやその先のJavaにつなげるために
もう少し記憶を堅いものにしておく ふぁ〜い
HTMLもCSSも、「覚える」ってことをしたことがなかったので新鮮
ぴっちぴちです
今日は用事あるのでここまで >>290
pythonはインデントでスコープを決めるからね
でも文中の空白は問題なかったはずやが
個人的にpythonはあんま好きやないな
科学技術計算や深層学習の分野では強いけどアプリ作るとなるとピンとこん
ワイはjavaでデータベース使ってウェブサイト制作なんかは一通りできるようになったっから、Androidアプリ作るためKotlin勉強しとる
でもワイのノーパソでAndroidStadioのエミュレータ動かすと重すぎて作業できん
新しいPC欲しいで マルチモニタのデスクトップでシコシコ書いてるわ
ブラウザでググりながらが基本なんで
ノーパンは厳しいな
モニタもっとでかいのに取り替えようかとも思ってるぐらいだ
web系のプログラミング始めると
レンタル鯖とか興味湧いてくる
無料もあるけど@500円/月でよさそうなの借りられるし HTML・CSSのテキスト
テキスト通りの流れでVSCodeにカキカキ
しっかり覚えたわけじゃないけど、難易度は低いので
大体なにができるのかざっくり理解出来ていれば
あとはググったりして再現できそう
正直いうとこれつまんねぇのな
HTML/CSSの部分は一通り流したので
JavaScriptの部分をこれまた流し読みをしてみた
Javaで基本やってると大した事ないのな
匿名クラスのような使い方も出てきてるし
JFrameでやってたEvent処理の知識が生きそう
JavaScriptは一時期Javaと近い所にいたようで、似た部分が多くて勉強しやすそうだ Javaの将来性があれなんで、C#の本も買ってある
どちらかに限定しないで両方やればいいじゃんってゆる〜く考えてる
C#はwidowsアプリに強そうなんで、軽く何か作れるレベルまでやってみたい
んでJavaと比べてみたい C#はVSCodeでも開発できるんだけど
この際Visula Studio 2017 Communityを入れる事にしよう
オプションでインスコできるものがいくつかあるんだけど
全部チェック付けたら20GB越えるみたいだ
SSDの容量食いそうだけどまぁいいか 「独習C#新版」
ちょいと読んでるんだけど
Javaとやたら似てるな
namespaceというのは初めてだけど
packageみたいなもんかこれ
●Java
System.out.println("hello," + name);
●C#
Console.WriteLine("hello, {0}", name);
プレースホルダー使うところがC系っぽい感じする
Cでもそんなことやってたような(忘れたけど
でもJavaでも位置揃えのために実践編でやったな オブジェクト指向を勉強するのにJavaは適当で
特にスッキリシリーズは初学者にぴったりと聞いたんで使ってたんだけど
その通りだな
このC#のテキストは初学者にとっては厳しいんじゃないか
少なくともスッキリの系統だった教え方と比べると難易度高そう
最初から詰め込みすぎてる
逆に基本がわかってる多言語経験者にはよさそう C#が初心者にとって向いてる点は、
ざっとみた限りではどの参考書もVisualStudio Communityの導入と
使い方を紹介して、これを使って学習を進めてるところだな
スッキリでは統合環境の説明が薄いせいで自分でeclipseの使い方を調べないといけなかった
初心者であっても統合環境がないと、試行錯誤するのに不便すぎる
VisualStudioはビルドすると勝手にexeが実行されてコマンドプロンプトが立ち上がる
プログラミングは最終的な実行ファイルを目にしないとやった感じがしない
そういう点でもいい
windowsユーザーにとってはやはりマイクロソフト製品は親和性が高く感じる C#はJavaとCを足して二で割ったような言語だそうだ
三項演算子とか出てくると、はるか昔にすこしだけCをいじった時の記憶が戻ってくる
Javaっぽいんだけど、Cの話がちょくちょく入ってくる
どちらも多少やったことがあるおれにはぴったりなのかもしれない
独習の3章まで読んだ
全くの初心者ではないんだけど、内容が重めだから復習しないとすぐに知識が抜けそう
スッキリでいえば入門編と実践編が合体してるような感じだ C#はメインメソッドは
Main
と書かないとダメなんだな
Javaみたいな
main
だとダメ
あと、文字列比較では
Javaと違って
==
を使う public static void main(String[] args)
public static void Main(string[] args)
微妙に違うのはやめて欲しいわ 👀
Rock54: Caution(BBR-MD5:1341adc37120578f18dba9451e6c8c3b) 独習C#、1/4ぐらい読んだ
読んだとか言っても頭に入ってなかったら意味ないんで
今の5章終わったらもう一度最初から読み直すか
忘れちゃってる部分が多すぎると行き詰まる >>53の最短一致のことも書かれてるな
網羅性が高いな、このテキストは。
しかし文字列操作分野は重い
Javaでも重かったが独習C#はさらに重い
Javaやってなかったら挫折コースまっしぐらだ
コレクションまだやってないのに出てくるし
まさかのラムダ式まで出てくるし ふむむ
VisualStudio で Ctrl+F5 で実行したあと、
コマンドプロンプトを閉じると、フォーカスが出力ウィンドウに移ってしまう
コードエディタに戻ってコードの編集を続けたいのだが
マウスを使って戻すのがめんどくさい
ctrl+tab でコードエディタに戻る事ができる 机の上にキーボードおいてカチャカチャやってると深夜だと結構うるさい
タオルを下に置いたら劇的に音が小さくなった
これはいい Javaでファイルやらstream系のクローズを自動化する書き方があったが
C#も同様の方法がある
独習C#では最初からこの方法で教えている
●C#
using () {}
●Java
try () {} using (var writer = new StreamWriter(@"../../data.log")) {}
で2つ上のフォルダにファイル作成
ドット2つ+/ で上のフォルダ
ドット1つ+/ で現在のフォルダ
ファイル操作の練習するわけだけど
exeが作られているフォルダの階層が深いから
exeよりちょい上の方にテスト用のファイルを作る事にする 文字コードはほんとやっかいだ
ぐぐるとHTMLではUTF-8を使えと書いてある
これが主流だと。
でもPC上のファイルを開くとSJISしかない
この差は一体なんなんだ
これはJavaでも遭遇した問題だ
ちなみにSJISと判断したのは自分が使っているエディタで開くとそう表示されてるからだ
さらにぐぐってwindowsのメモ帳での文字コードの扱いを調べる
メモ帳では 「名前を付けて保存」 で文字コードを選択して保存ができるようになっている
選択肢にはSJISなどというものはない
ANSIとやらで保存するのがデフォルトのようだ
ANSI
日本語 Windows で ANSI と呼ばれているのは CP932 であり、
これは Shift_JIS が拡張されたもの
https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1490895514
SJIS
シフトJISコードは、SJISとも呼び、Microsoft社が決めたコードで
Windows95やMS-DOSやMacなどで使用されています。
http://ash.jp/code/code.htm
ざっくり捉えると、ANSIもSJISもShift-JISということか
ウェブ上ではUTF-8を使えといいつつローカルではShift-JISがデフォルトとは。
でもって、C#でもJavaでもUTF-8が標準的な扱いとなっている
そのためローカルのテキストファイルを実験台として開くと、文字化けの問題が生じる
文字化け回避手段はこんなところか
メモ帳の別名保存によりUTF-8を選択すると
自分の使っているエディタで開いた時にりUTF-8と表示されている
このテキストに日本語を書き込んでから、C#のStreamReaderで開いてみると文字化けしない
もしくは、StreamReaderのインスタンス生成時コンストラクタに
Encording.GetEndording("SJIS")
を渡すと文字化けしない StreamWriter に Encording.GetEndording("UTF-8") を渡して作ったファイルを使ってもおk
その他
https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q11160634546
日本語 Windows 9x 系列は、システム内部、DOS プロンプト、
ファイルシステム(FAT16/FAT32)などがほぼ CP932 で統一されていました。
対して、Windows 10/8/8.1/7/Vista/XP/2000 などの
現在主流になっている Windows NT 系列は、ちょっと話が複雑になります。
まず、OS のシステム内部は Unicode UTF-16 に統一されました。
DOS プロンプトは廃されましたが、代わりに搭載されたコマンドプロンプトは、
未だ CP932 を標準で使います(切り替えは可能)。
ファイルシステム(NTFS)も Unicode UTF-16 を使うようになりましたが、
FAT32 は使用可能であり(この場合ファイル名は CP932 になる)、
またファイル内容は CP932 だったり Unicode UTF-8 BOM有りだったり
Unicode UTF-16 だったりします。
https://laboradian.com/char-encoding/
Shift_JIS
Windows の「メモ帳」で何か文章を書いてそのまま保存すると、
文字エンコーディングは「Shift_JIS」になり(厳密には CP932)、
改行コードは「CR + LF」になります。
UTF-8
Unicodeという文字コードを使って、文字を表現する方式の1つです。
現在(2017年)、ウェブサイトの多くは「UTF-8」を使っています。
Shift_JIS では、英語・日本語以外の文字を使うことができませんが、
UTF-8 であれば様々な言語の文字を一緒に使うことができます。 × encording
○ encoding
コードの補完機能であるインテリセンス(マイクロソフトの造語か)
頼りっきりになっているとスペル間違えて覚えてたりするんでよくない
eclipseにも補完機能あったけど、わざと手打ちしてた
C#でもそうした方がよさそうだわ
英単語思い出すきっかけにもなるし ファイル操作で、テキストファイルの読み込みやってるんだけど
Javaみたいに
FileReader fr = new FileReader("test.txt", FileMode.Open);
StreamReader sr = new StreamReader(fr);
でもいけるし
StreamReader sr = new StreamReader("test.txt");
でもいけちゃう
Encoding.GetEncoding("SJIS")
はどちらのケースも StreamReader に渡す
C# は、こういう方法もOKだし、ああいう方法もOKだよってのが多いような >>315
間違えた
修正
FileReader fr = new FileReader("test.txt", FileMode.Open);
↓
FileStream fs = new FileStream("test.txt", FileMode.Open);
>>257と同じで、Writer/Reader が入ると文字ストリームかな
FileStream はバイトストリーム
NetworkStream
MemoryStream
もバイトストリーム Console.WriteLineに渡す文字列だけど
変数混じりの場合、Javaと同じような記述方法でもいけるんだな
string st = "あああ";
Console.WriteLine(st + "と叫んだ");
みたいな感じ
こんな風↓しかダメと思ってた
Console.WriteLine(@"{st}と叫んだ"); Console.WriteLine(Math.Pow(3, 300));
結果
1.36891479058588E+143
>>285と比較すると、しょぼ! 1/3読んだけど
このまま先に進んでもスッカスカな知識になるんで
復習に入るか
覚えないといけない量はスッキリ1冊分ぐらいありそう >>318
そりゃMath.powの戻り値はdouble型やからな
javaだとlong型の最大値を超える計算はBigInteger型使ってnew BigInteger("3").pow(300)で可能やけど、C#でも似た感じでできるんとちゃう?
一見するとPythonの方が便利に思えるけど、どのくらいメモリを食うかわからんちゅうことやから、システム開発なんかには不向きなんやな テキストのちょい先でBigIntegerはやったけどね
そもそも目的というか得意としてる分野がハッキリしてるというのがいい
言語ごとに特徴が明確なら選択しやすい intの範囲ぐらい正確に覚えても罰は当たらないだろう
まいなすにじゅういちおくよんせんななひゃくよんじゅうはちまんさんぜんろっぴゃくよんじゅうはち〜(絶対値1つ小さいプラス値)
-21 4748 3648 +21 4748 3647 テキストにいろいろ書込みながら
きちんと復習してる
今日はおしまい int i = 128;
Console.WriteLine((sbyte)i);
結果:-128
これの説明で 「残りのビットを反転させる」 なんていう説明が出てくる
この辺を数学的にしっかり学んだ人はなんてことはないんだけど、
そうでないと不思議な感じがする
突然おもちゃを扱うような雑な操作が唐突にあらわれたような印象を受ける
127 (10)
01111111 (2)
127 (sbyte)
128 (10)
10000000 (2)
-128 (sbyte)
8bitで表した2進数の最初のビットは符号を表現するために使われる
これが 1 になったら、つまり10進数で言えば 127 から 128 になった時、
残りのビットを反転させてから、10進数にして 1 を加えてマイナス記号つければ
sbyte にキャストした値になるというものだ
10000000 の最初の 1 を除いた7つの 0 、0000000 を反転させると 1111111 となる
これは10進数でいうと 127 で 1 加えてマイナスを付けると -128
10000000
↓
0000000
↓
1111111
↓
127
↓
-128 この気持ち悪い唐突感を取り除くためにぼけぇと考えてたんだけど
これは2進数を持ち出さないでも10進数の範疇で自然なイメージを持てるのではないかと
そういう結論に至った
つまり、10進数で桁が変る瞬間、例えば 99 100 のような場合
上と同じような変遷を書くことができる
100
↓
00
↓ ←ここが「反転」の操作を10進数で表現したもの
99
↓
99
↓
-100
反転とは補数の関係を使った変換なのでこれでいいだろう
数直線で考えたとき、0 から順にたどっていって 100 になった瞬間に、
ぽ〜んと 0 を挟んで真反対の側に飛ばされる感じがわかる
101 を同じように考えると
101
↓
01
↓
98
↓
98
↓
-99
なるほどと ■ このスレッドは過去ログ倉庫に格納されています