このページは、学部2年生向け授業である、「マルチメディアプログラミング実習」 のために用意しました。
(Wikiの仕様で大文字小文字が混在した英単語に疑問符?が追加されるところがありますが、無視してください。)
C言語では、エラーが出そうな処理をする場合は、エラーが発生するかどうかをステップごとにif文でチェックして、対処していました。プログラムが読みにくく煩雑になりがちです。
現代的な言語では、プログラムの処理をブロックでまとめて、その部分から発生したエラーを別の部分で受け取って処理をする書き方ができます。
Javaの多くのメソッドが標準的なエラー処理をサポートしています。また、自分でエラー処理を設計することも可能です。ただ、この授業の範囲では、自分でエラー処理を設計することはないと思います。標準的な機能の利用を練習しておきます。
次のプログラムを作って試してください。 引数が2個あることを前提としています。 なので、引数が少ないとエラーが出ます。確認してください。
public class TestException { public static void main(String argv[]){ System.out.println(argv[0]+" "+argv[1]); System.out.println("Nice to meet you."); } }
エラーが出る可能性のある場所をtryでくくっておき、 エラーが出たらそれを捕捉する処置をcatchで指定します。
public class TestException { public static void main(String argv[]){ try{ System.out.println(argv[0]+" "+argv[1]); System.out.println("Nice to meet you."); } catch (Exception e) { System.out.println("please input 2 words."); } } }
以下のリンクからStringクラスを選択して、何ができるかざっと見ておきましょう。
https://docs.oracle.com/javase/jp/8/docs/api/index.html
public class TestString { public static void main (String argue[]) { String str = "Hello Java World"; //このstrを表示してください(System out.printlnを使う) //strの長さを表示してください(.lengthを使う)) //strの3要素目の文字を表示してください //最初にaが現れる位置を表示してください //最後の文字aが現れる位置を表示してください //辞書式で比較してstrと次のstr2をcompareToを使って比較してください。順番を変えるとcompareToが返す値はどうなるでしょう? String str2="Have World"; //strの6要素目から始まる部分文字列を作り表示して表示してください。 //int型をString型に変換してください。 int v2020=2020; String s2020 = String.valueOf(v2020); } }
解答例:
public class TestString{ public static void main(String args[]){ String str = "Hello Java World"; System.out.println(str); System.out.println(str.length()); System.out.println(str.charAt(3)); System.out.println(str.indexOf('a')); String str2 = "Hello World"; System.out.println(str.compareTo(str2)); System.out.println(str2.compareTo(str)); System.out.println(str.substring(6)); int v2020=2020; String s2020 = String.valueOf(v2020); System.out.println(s2020); } }
最初の引数(文字列)を表示するプログラムは、以下です。クラス名はTestStringにしました。
public class TestString { public static void main(String argv[]) { System.out.println(argv[0]); } }
これを元に、最初の引数(文字列)を逆に出力するプログラムを作ってください。例えば、ochanomizuと入力すると、以下のように表示されるプログラムを作ります。
[e100:?/Documents/java] siio% java TestString ochanomizu ochanomizu uzimonahco [e100:?/Documents/java] siio%
さらには、引数がない場合は引数入力を促すことを表示してみよう。
[e100:?/Documents/java] siio% java TestString please input a word [e100:?/Documents/java] siio%
解答例:
public class TestString { public static void main (String argv[]) { try{ System.out.println(argv[0]); int len = argv[0].length(); for(int i = len - 1; i>=0; i--) { System.out.print(argv[0].charAt(i)); } System.out.println(); } catch (Exception e) { System.out.println("please input a word"); } } }
https://docs.oracle.com/javase/jp/8/docs/api/index.html
要素があって、次の要素へのポインターを持っているような、リスト構造です。
(element 1) ---> (element 2) ---> (element 3) ---> ... ---> (element n)
次のプログラムを作ってLinked Listのメソッドを使ってみましょう。 定義とコンストラクタで<String>と書くのは、要素がStringのインスタンスだという宣言です。 昔のJavaでは不要だったのですが、今のバージョンではこのような形式で明示的に書かないといけないようです。
import java.util.*; public class LinkedListTest{ public static void main(String[] args) { LinkedList<String> list = new LinkedList<String>(); String name1="ALICE"; String name2="BOB"; //listにname1をaddしてください //listにname2をaddしてください //listの要素数を取得して表示してください //listから最初の要素をgetFirstで取り出して表示してください //listからget(1)してその結果を表示してください String name3="CINDY"; String name4="DAVE"; //listにname3をaddしてください。 //listからname1を削除してください(remove) //listにname4をaddFirstしてください。 //この結果、"DAVE" --> "BOB" --> "CINDY"となると思います。 //listの全要素にアクセスするには、Iteratorインスタンスを作ると便利です。 //以下のようにして全要素を表示してください。 Iterator it = list.iterator(); while(it.hasNext()) { String st = (String)it.next(); System.out.println(st); } //toArrayメソッドで配列を作ることもできます //以下のようにして全要素を表示してください。 Object[] names = list.toArray(); for(Object s: names) System.out.println(s); } }
解答例:
Import java.util.*; public class LinkedListTest{ public static void main(String args[]){ LinkedList<String> list = new LinkedList<String>(); String name1 = "ALICE"; String name2 = "BOB"; list.add(name1); list.add(name2); System.out.println(list.size()); System.out.println(list.getFirst()); System.out.println(list.get(1)); String name3 = "CINDY"; String name4 = "DAVE"; list.add(name3); list.remove(name1); list.addFirst(name4); Iterator it = list.iterator(); while(it.hasNext()) System.out.println(it.next()); Object[] names = list.toArray(); for(Object s: names) System.out.println(s); } }
解答例(丁寧版):
import java.util.*; public class LinkedListTest{ public static void main(String[] args) { LinkedList<String> list = new LinkedList<String>(); String name1="ALICE"; String name2="BOB"; list.add(name1); list.add(name2); String firstname=list.getFirst(); String secondname=list.get(1); System.out.println("listの要素数は" + list.size()); System.out.println("listの最初の要素は" + firstname + "2番目の要素は" + secondname); String name3="CINDY"; String name4="DAVE"; list.add(name3); list.remove(name1); list.addFirst(name4); Iterator it = list.iterator(); System.out.println("要素の走査"); while(it.hasNext()){ String st = (String)it.next(); System.out.println(st); } System.out.println("要素の走査 by toArray()"); Object[] names = list.toArray(); for(Object s: names) System.out.println(s); } }
https://docs.oracle.com/javase/jp/8/docs/api/index.html
Linked Listと同様にインスタンスの集まりを保持するデータ構造です。
(element 1) ---> (element 2) ---> (element 3) ---> ... (element n)
だだし、同一要素を重複して保持しません。
import java.util.*; public class HashSetTest{ public static void main(String args[]){ HashSet<String> set = new HashSet<String>(); String name1="Alice"; String name2="Bob"; String name3="Cindy"; //setにname1をaddしてください //setにname2をaddしてください //setにname3をaddしてください //setに再びname1をaddしてみてください。その時の戻り値 (booleanです)の状態を表示してください。 //setの内容をIteratorを使って全部表示してください。 } }
解答例:
import java.util.*; public class HashSetTest{ public static void main(String args[]){ HashSet<String> set = new HashSet<String>(); String name1="Alice"; String name2="Bob"; String name3="Cindy"; //name1,2,3を追加 set.add(name1); set.add(name2); set.add(name3); //name1の再度追加を試みる。失敗 System.out.println(set.add(name1)); Iterator it = set.iterator(); while(it.hasNext()) System.out.println(it.next()); } }
https://docs.oracle.com/javase/jp/8/docs/api/index.html
2つのインスタンスのマッッピング(対応付け)の集まりを保持するクラスです。2つのインスタンスをキー(key)と値(value)と言います。例えば、keyもvalueもどちらもStringインスタンスの場合、以下のようにして要素を追加していきます。
import java.util.*; public class EtoJ{ public static void main(String args[]) { HashMap<String,String> map = new HashMap<String,String>(); map.put("apple","りんご"); map.put("banana","バナナ"); ... } }
このプログラムで、mapインスタンスからkeyに対応するvalueを取り出すためには、
map.get("apple");
などとします。
このプログラムを拡張して、以下のように動作する英語ー日本語単語変換プログラムを作ってください。
[e100:?/Documents/java] siio% java EtoJ banana バナナ [e100:?/Documents/java] siio% java EtoJ apple りんご [e100:?/Documents/java] siio% java EtoJ Please input an English word
解答例:
import java.util.*; public class EtoJ{ public static void main(String args[]) { HashMap<String,String> map = new HashMap<String,String>(); map.put("apple","りんご"); map.put("banana","バナナ"); map.put("orange","みかん"); map.put("pineapple","パイナップル"); map.put("grape","ぶどう"); map.put("peach","もも"); map.put("melon","メロン"); map.put("lemon","レモン"); try { System.out.println(map.get(args[0])); } catch(Exception e) { System.out.println("Please input an English word"); } } }
Javaの入出力は、ファイル、ネットワーク、キーボード、ディスプレイを対象としています。C言語に比べて、高機能な上に、ネットワークへの入出力も標準装備されているところが便利です。
(ファイル、ネットワーク、キーボード) | | 入力ストリーム | V (Javaプログラム) | | 出力ストリーム | V (ファイル、ネットワーク、ディスプレイ)
データを入出力するのがバイトストリームです。 ここでは、
を使ってみます。
こちらで機能を確認しましょう。
https://docs.oracle.com/javase/jp/8/docs/api/index.html
基本的なインスタンスメソッドは、writeとcloseです。writeには1バイトの書き込み、バイト配列の書き込みがあります。IOExceptionを投げるので、キャッチします。
write(int b)
は、int型の引数の下位1バイトを書き出します。以下のプログラムでファイルに1バイト書き出すことができます。
import java.io.*; public class FoutTest { public static void main(String[] args) { try { FileOutputStream fout = new FileOutputStream("fout.dat"); fout.write(1234); fout.close(); } catch (IOException e) { System.out.println(e); } } }
これでfout.datという名前のファイルができあがるはずです。 作ったファイルを
hexdump fout.dat
してみてください
$ hexdump fout.dat 0000000 d2 0000001
1234は0x4d2だったのでその下1バイトが書き込まれました。
こちらで機能を確認しましょう。
https://docs.oracle.com/javase/jp/8/docs/api/index.html
Javaのいろいろなデータ型を書き出すことができます。 int, long, short, float, double, booleanなどのデータを書き出します。 以下では、int型データを書き出しています。 なお、Data Output StreamはFile Output Streamの機能を利用しています。 Data Output Streamのコンストラクトには、File Output Streamのインスタンスが必要です。 なので2段階のコンストラクト作業になります。
import java.io.*; public class DoutTest { public static void main (String[] args) { try { FileOutputStream fout = new FileOutputStream("dout.dat"); DataOutputStream dout = new DataOutputStream(fout); dout.writeInt(100); dout.close(); }catch (Exception e) { System.out.println(e); } } }
これでdout.datという名前のファイルができあがるはずです。 作ったファイルを
hexdump dout.dat
してみてください
e100:java siio$ hexdump dout.dat 0000000 00 00 00 64 0000004
int型は4バイトなので4バイトのファイルが出来上がっています。100は0x000064なので、その内容のファイルです。
File/Data Output Streamにはそれぞれ対応したFile/Data Input Streamがあります。 こちらで機能を確認しましょう。
https://docs.oracle.com/javase/jp/8/docs/api/index.html
Javaのint型のデータで100をファイルに書いて、これを読み込む例です。
import java.io.*; public class DoutTest { public static void main (String[] args) { try { FileOutputStream fout = new FileOutputStream("dout.dat"); DataOutputStream dout = new DataOutputStream(fout); dout.writeInt(100); dout.close(); FileInputStream finput = new FileInputStream("dout.dat"); DataInputStream dinput = new DataInputStream(finput); System.out.println(dinput.readInt()); dinput.close(); }catch (Exception e) { System.out.println(e); } } }
1から100までのint型の数値をwirteIntメソッドでファイルに書き出すプログラムRW100を書いてください。また、そのファイルをreadIntメソッドで読み込み、表示してください。
作ったファイルを
hexdump dout.dat
してみてください
解答例
import java.io.*; public class RW100 { public static void main (String[] args) { int i; try { FileOutputStream fout = new FileOutputStream ("dout.dat"); DataOutputStream dout = new DataOutputStream(fout); for(i=1;i<101;i++) dout.writeInt(i); dout.close(); FileInputStream fin = new FileInputStream ("dout.dat"); DataInputStream din = new DataInputStream(fin); for(i=1;i<101;i++) System.out.println(din.readInt()); din.close(); } catch (FileNotFoundException e) { System.out.println(e); } catch (IOException e) { System.out.println(e); } } }
文字を読み書きするのが文字ストリームです。文字に適した処理が用意されています。 ReaderとWriterというクラスのグループがあります。
File Writerを使うと文字列を書き出すことができます。 close, flush, writeなどのメソッドがあります。 こちらで機能を確認しましょう。
https://docs.oracle.com/javase/jp/8/docs/api/index.html
また、Print Writerというクラスでは、System Out Printlnのようにprintlnに相当する機能が使えます。 Javaのいろいろなデータを書き出すのに便利です。
writer.txtというファイルに、
int x = 2006; String s = "Java 教科書";
というJavaの変数を、printlnで書き出すプログラムを作ってください。
Print Writerをコンストラクトするためには、File Writerのインスタンスが必要です。なので、これも2段階のコンストラクションを行います。
import java.io.*; public class PrintWriterTest{ public static void main(String[] args) { try { //writer.txtというファイルを作って文字を書き込む FileWriter fwriter = new FileWriter("writer.txt"); PrintWriter pwriter = new PrintWriter(fwriter); pwriter.println(2006); pwriter.println("Java教科書"); pwriter.close(); } catch (IOException e) { System.out.println(e); } } }
作ったファイルを
od -h
または
hexdump
してみてください
2006という数値は、int型なのですが、ASCII文字列に変換されて文字として書き出されていることがわかります。 「Java教科書」は、もともとが文字列なので、そのまま文字列として書き出されています。0x0Aは改行コードです。
なので、文字列を書き出している部分は、File Writerの機能を使っても同様に書き出すことが可能です。
import java.io.*; public class PrintWriterTest{ public static void main(String[] args) { try { //writer.txtというファイルを作って文字を書き込む FileWriter fwriter = new FileWriter("writer.txt"); PrintWriter pwriter = new PrintWriter(fwriter); pwriter.println(2006); //pwriter.println("Java教科書"); fwriter.write("Java教科書"); pwriter.close(); } catch (IOException e) { System.out.println(e); } } }
File ReaderはFile Writerと同様に文字列を読み込みます。 読み込む文字数を指定して読み込むことも可能です。 さらに便利なクラスがBuffered Readerで、こちらは改行文字までを読み込んでくれます。 こちらで機能を確認しましょう。
https://docs.oracle.com/javase/jp/8/docs/api/index.html
Buffered ReaderもFile Readerのインスタンスから作りますので、2段階のコンストラクションになります。
writer.txtというテキストファイルがあるとして、これから1行ずつ読み込んで画面表示するプログラムは以下のようになります。
public class BufferedReaderTest{ public static void main(String[] args) { try { FileReader freader = new FileReader("writer.txt"); BufferedReader breader = new BufferedReader(freader); String tmp; while( (tmp=breader.readLine() ) != null) { System.out.println(tmp); } breader.close(); } catch (IOException e) { System.out.println(e); } } }
このプログラムを参考にして、 先のPrint Writer Testに書き足して、 書き込んだデータを読み出して画面に表示するプログラムを作ってください。
ヒント:
import java.io.*; public class PrintWriterTest{ public static void main(String[] args) { try { //writer.txtというファイルを作って文字を書き込む FileWriter fwriter = new FileWriter("writer.txt"); PrintWriter pwriter = new PrintWriter(fwriter); pwriter.println(2006); pwriter.println("Java教科書"); //fwriter.write("Java教科書"); pwriter.close(); ここに書き足す } catch (IOException e) { System.out.println(e); } } }
解答例:
import java.io.*; public class PrintWriterTest{ public static void main(String[] args) { try { //writer.txtというファイルを作って文字を書き込む FileWriter fwriter = new FileWriter("writer.txt"); PrintWriter pwriter = new PrintWriter(fwriter); pwriter.println("java 教科書" + 2001 ); pwriter.close(); //writer.txtのファイルの中身をSystem.out.printlnで表示する FileReader freader = new FileReader("writer.txt"); BufferedReader breader = new BufferedReader(freader); String tmp; while( (tmp=breader.readLine() ) != null) { System.out.println(tmp); } breader.close(); } catch (IOException e) { System.out.println(e); } } }
標準入出力には、
の3種類があります。これらはJavaのクラス変数として定義されています。
それぞれの型は、
です。使えるメソッドはこちらで確認できます。
https://docs.oracle.com/javase/jp/8/docs/api/index.html
import java.io.*; public class StandardIOTest { public static void main(String[] args) { try { //System.inからInputStreamReaderを作り、それからBufferedReaderを作る InputStreamReader ireader = new InputStreamReader (System.in); BufferedReader breaderK = new BufferedReader(ireader); System.out.println("文字列を入力してリターンを押してください"); String line = breaderK.readLine(); System.out.println("あなたが入力した文字列" + line);
} catch(IOException e) { System.out.println(e); } } }
キーボードから1行入力された文字列からテキストファイルを作るプログラムを作ってください。
e100:java siio$ java KeyToFile Hello, これはテストです。 Hello, これはテストです。 e100:java siio$ cat writer.txt Hello, これはテストです。
ヒント
import java.io.*; public class KeyToFile { public static void main(String[] args) { try { ここにプログラムを書く } catch(IOException e) { System.out.println(e); } } }
解答例
import java.io.*; public class KeyToFile { public static void main(String[] args) { try { InputStreamReader ireader = new InputStreamReader (System.in); BufferedReader breaderK = new BufferedReader(ireader); String line = breaderK.readLine(); FileWriter fwriter = new FileWriter("writer.txt"); PrintWriter pwriter = new PrintWriter(fwriter); pwriter.println(line); pwriter.close(); FileReader freader = new FileReader("writer.txt"); BufferedReader breaderF = new BufferedReader(freader); String tmp=null; while( (tmp=breaderF.readLine()) != null) System.out.println(tmp); breaderF.close(); } catch(IOException e) { System.out.println(e); } } }
ヒント1
import java.net.*;
が必要です。
URL targetURL = new URL("http://www.ocha.ac.jp/");
でURLクラスのインスタンスが得られる。
InputStream istream = targetURL.openStream();
でこれからInputStreamのインスタンスが得られる。
InputStreamReader isreader = new InputStreamReader(istream);
でこれからInputStreamReaderのインスタンスが得られる。
BufferedReader breader = new BufferedReader( isreader );
でこれからBufferedReader のインスタンスが得られる。
ヒント2
import java.io.*; import java.net.*; public class URLTest { public static void main (String argv[]) { try { ここにプログラムを書く } catch (IOException e) { System.out.println("error..."); } } }
ヒント3:
import java.io.*; import java.net.*; public class URLTest { public static void main (String argv[]) { try { URL targetURL = new URL("http://www.ocha.ac.jp/"); InputStream istream = targetURL.openStream(); InputStreamReader isreader = new InputStreamReader(istream); BufferedReader breader = new BufferedReader( isreader ); ここで一行ずつ読み込む } catch (IOException e) { System.out.println("error..."); } } }
解答例:
import java.io.*; import java.net.*; public class URLTest { public static void main (String argv[]) { try { URL targetURL = new URL("http://www.ocha.ac.jp/"); InputStream istream = targetURL.openStream(); InputStreamReader isreader = new InputStreamReader(istream); BufferedReader breader = new BufferedReader( isreader ); String line; while((line=breader.readLine()) != null) System.out.println(line); } catch (IOException e) { System.out.println("error..."); } } }
http://siio.jp/cat.jpg
をダウンロードして、cat.jpgというファイルを作るプログラムを作ってください。 データはテキストじゃなくて、バイナリーです。
ヒント1:
InputStreamのインスタンスに対してread()メソッドを使うと1バイトのデータが得られます。読み終わると-1になります。 1バイトのデータを書き出すなら、FileOutputStreamだけで可能です。
ヒント2:
import java.io.*; import java.net.*; public class URLJpeg { public static void main (String argv[]) { try { URL targetURL = new URL("http://siio.jp/cat.jpg"); InputStream istream = targetURL.openStream(); FileOutputStream fout = new FileOutputStream("cat.jpg");
というインスタンスを作って、
istream.read()
で読んで、
fout.write(1バイト)
で書き出します。
解答例
import java.io.*; import java.net.*; //http://siio.jp/cat.jpg //をダウンロードして、cat.jpgというファイルを作るプログラム public class URLJpeg { public static void main (String argv[]) { try { URL targetURL = new URL("http://siio.jp/cat.jpg"); InputStream istream = targetURL.openStream(); FileOutputStream fout = new FileOutputStream("cat.jpg"); int aData; while((aData = istream.read()) != -1) fout.write(aData); istream.close(); fout.close(); } catch (IOException e) { System.out.println("error..."); } } }
上記のプログラム(URLJpeg.java, URLJpeg.class) を、出席番号+名前のフォルダにいれて、ZIP圧縮して提出してください。`
上記の例では写真データを1バイトずつ読み書きしていました。 InputStreamのメソッドを調べると、複数バイト単位で読み込むメソッドがあります。 たとえば、1024バイトずつ読み書きすることで、処理速度が向上すると期待できます。 そこで、複数バイト読み書きするよう、上記のプログラムを変更して、 実際にどの程度(実行速度にして何倍くらい)性能向上するか確認してみましょう。
read public int read(byte[] b) throws IOException 入力ストリームから配列長さだけのバイト数を読み込もうとし、それをバッファ配列 b に格納します。 実際に読み込まれたバイト数は整数として返されます。 戻り値は、バッファに読み込まれたバイトの合計数。ストリームの終わりに達してデータがない場合は -1
を使って読みこみ、
write public void write(byte[] b, int off, int len) throws IOException 指定された byte 配列の、オフセット位置 off から始まる len バイトを出力ストリームに書き込みます。
を使ってください。
byte[] data = new byte[1024];
という配列を用意して、
int datalength; while(( datalength=istream.read(data)) != -1) fout.write(data, 0, datalength);
とします。
import java.io.*; import java.net.*; //http://siio.jp/cat.jpg //をダウンロードして、cat.jpgというファイルを作るプログラムを作ってください。 //データはテキストじゃなくて、バイナリーです。 public class URLJpeg2 { public static void main (String argv[]) { byte[] data = new byte[1024]; try { URL targetURL = new URL("http://siio.jp/cat.jpg"); InputStream istream = targetURL.openStream(); FileOutputStream fout = new FileOutputStream("cat.jpg"); int datalength; while(( datalength=istream.read(data)) != -1) fout.write(data, 0, datalength); istream.close(); fout.close(); } catch (IOException e) { System.out.println("error..."); } } }
ここでは1024バイトを読み込むことにしました。でも、InputStreamのメソッドを見ると、available()というのがあります。
available() この入力ストリームのメソッドの次の呼出しによって、ブロックせずにこの入力ストリームから読み込むことができる(またはスキップできる)推定バイト数を返します。
これを使えば、適切な長さを見積もれるかもしれません。
curlというコマンドがあります。
curl http://ocha.ac.jp/
などとすると、htmlが見られますし、
curl http://siio.jp/cat.jpg > cat.jpg
などとすると、ファイルとして保存できます。これに近いプログラムを作ってみましょう。
上記の引数のURLをファイルにするプログラムを作ってください。 また、cat.jpgのファイル取得でまとめて読むことでどれくらい速度が改善したかを、 レポートにしてください。レポートの書式は任意です。(テキストファイルでかまいません)
これらのjava, class, レポートのファイルをまとめて、出席番号+名前のフォルダに入れて、圧縮して、12月10日の授業の開始時間に提出してください。