ざる魂

真似ぶ魂、学ぶの本質。知られざる我が魂

javaまとめ

メッセージのUS化

  • 日本語だとコンパイルエラーメッセージが化けるので
 -Duser.language=en

メモリー・リークの予防

http://www.ibm.com/developerworks/jp/java/library/j-leaks/ メモリー・リークは、いくつかの一般的な問題に注意することにより防ぐことができます。 しばしばメモリー・リークの原因となるのは、ハッシュ・テーブルやベクトルなどのコレクション・クラスです。 そのクラスが static と宣言されていて、アプリケーションの存続期間全体にわたって存在する場合、その可能性が特に大きくなります。 よくある別の問題は、あるクラスをイベント・リスナーとして登録しておきながら、そのクラスがもう使用されなくなった時点で登録削除するのを忘れている場合です。 また、クラスのメンバー変数が別のクラスを指す場合、適当なタイミングでその変数をヌルにセットする必要があります。

自作CRUDアプリ

createメソッド実装時に下記の例外でハマる

java.lang.reflect.InvocationTargetException

commons-configurationではまる。

JavaDB

javaDBのスタンドアロン版では、ijを起動中、サーブレットアプリからアクセスできないので注意。

connect 'jdbc:derby:c:\Temp\dbname;create=true';
create table articles (
	id integer primary key generated by default as identity,
	title varchar(256),
    body long varchar,
	 updated_at timestamp
);
insert into articles values (default, 'title1', 'body1', current_timestamp);

tomcat

context.xml

<Context reloadable="true">
	<Resurce name="jdbc/crud" auth="container" type="javax.sql.DataSource"
	    driverClassName="org.apache.derby.jdbc.EmbeddedDriver"
		url="jdbc:derby:c:\Temp\dbname"/>
</Context>

web.xml

<resource-ref>
	<res-ref-name>jdbc/crud</res-ref-name>
	<res-type>javax.sql.DataSource</res-type>
	<res-auth>Container</res-auth>
</resource-ref>

Servlet

private DataSource ds;

@Override
public void init() throws ServletException {
	try {
		ds = (DataSource) (new InitialContext()).lookup("java:comp/env/jdbc/crud");
    } catch (NamingException e) {
    	throw new ServletException(e);
    }
}
Connection conn = ds.getConnection();
Statement stmt = conn.createStatement();
String sql = "SELECT title, body FROM articles ORDER BY updated_at DESC";
ResultSet rs = stmt.executeQuery(sql);
while (rs.next()) {
	String title = rs.getString("title");
	String body = rs.getString("body");
}

JSTL

http://tomcat.apache.org/taglibs/index.html

Version JSTL version Requirements Tomcat
Standard 1.2 JSTL 1.2 (not yet JCP approved) Servlet 2.5, JavaServer Pages 2.1
Standard 1.1 JSTL 1.1 Servlet 2.4, JavaServer Pages 2.0 Tomcat 5.x(JSP 2.0)
Standard 1.0 JSTL 1.0 Servlet 2.3, JavaServer Pages 1.2 Tomcat 4.x(JSP 1.2)

タグライブラリ

タグハンドラ形式 Jsp1.1から
タグファイル形式 Jsp 2.0から

Resin

Resin3.0 JavaServlet2.4 Jsp2.0 JSTL 1.01
Resin3.1 JavaServlet2.5 Jsp2.1 JSTL 1.01
Resin4.0 JavaServlet3.0 Jsp2.2 JSTL 1.2 EL1.2

jsp-configは、jsp2.0から使用できる。

.tagファイルでは、pageContextではなく、jspContextでアクセスする。 jspContextは、JSP2.0から導入されている模様

外部プロセス起動

1.4まではRuntimeクラスだったが、1.5以降はProcessBuilderを使用する。

  /**
    * ファイルのグループと属性を変更する。
    */
   private void changGroup(String file)
   {
       ProcessBuilder pb = new ProcessBuilder();
       try {
           pb.command("chgrp", "-R", "hoge", file);
           Process p = pb.start();
       } catch (Exception ex) {
           Logger.error("can't execute chgrp:"+file);
       }
       try {
           pb.command("chmod", "-R", "664", file);
           Process p = pb.start();
       } catch (Exception ex) {
           Logger.error("can't execute chmod:"+file);
       }
   }

タグファイルについて

tagディレクティブ

タグファイルでは、pageディレティブの代わりに tagディレクティブを使用する。

<%@ tag
  language="java"
  pageEncoding="UTF-8"
  body-content="scriptless"
%><%@ attribute name="href"
%><%@ attribute name="id"
%>perfect.java

javaのクラスをインポートする場合

<%@ tag
  language="java"
  pageEncoding="UTF-8"
  body-content="scriptless"
  import="java.util.Map"
%><%@ attribute name="href"
%><%@ attribute name="id"
%>perfect.java

pageディレクティブと同様に複数指定することもできる。

<%@ tag
  language="java"
  pageEncoding="UTF-8"
  body-content="scriptless"
  import="java.util.Map"
  import="java.util.List"
%><%@ attribute name="href"
%><%@ attribute name="id"
%>perfect.java

body-content属性

tagディレクティブにある body-content 属性の意味は下記のとおり body-contentは、タグを利用したときの本体部分のことである。

<hoge>本体</hoge>

scriptless

タグ本体に、スクリプト式、スクリプトレットを使用できない。

<%-- 下記はng --%>
<hoge>
<%= test %>
<% out.print("test"); %>
</hoge>

<%-- 下記はok --%>
<hoge>
${test}
test
</hoge>

empty

タグ本体そのものを記述できない

<%-- 下記はNG --%>
<hoge>test</hoge>

<%-- 下記はok --%>
<hoge></hoge>
<hoge />

tagdependet

よくわかってない。

多分、本体で記述した内容は 評価されずにそのまま表示される?

<hoge>${1 + 1}</hoge>

<%-- 下記のように評価されず表示される --%>
<hoge>${1 + 1}</hoge>

スクリプティング要素は使用できない。

動的属性

動的属性を指定すると、属性の定義を省略できる。 属性の種類が多い場合に有効。 たとえば、a.tagというオリジナルのタグを用意し、 以下のようにアクセスした場合、

jsp側

//hoge.jsp
<my:a href="hoge.com" />hoge</my:a>

属性がMap形式で格納されるで、以下のようにアクセスできる。

// a.tag
<%@ tag pageEncoding="UTF-8"
  body-content="scriptless"
  dynamic-attributes="attrs"
%>
<a href="${attrs.href}"><jsp:doBody/></a>

jspと改行について

jspは、= %> = が出現するとそこに「改行」が入ってしまうので注意が必要である。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="pj" tagdir="/WEB-INF/tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<body>
test
</body>
</html>

この場合、 = %> = が3回登場しているので「改行」も3回入る。

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<body>
test
</body>
</html>

これを回避するには、下記のように = %> = を行頭に置き、 かつ次行を繋げることである。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"
%><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"
%><%@ taglib prefix="pj" tagdir="/WEB-INF/tags"
%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<body>
test
</body>
</html>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<body>
test
</body>
</html>

java5以降で環境変数の取得

こんな感じ System.getenv().get("LANG");

javaの拡張for文   java

map

Mapの場合、Map#keySet()でkeyだけ、Map#values()でvalueだけ、 は簡単に取れるけど拡張for文(for-each)でループさせてkey/valueのペアを取得する方法。

for(Map.Entry<String, String> e : map.entrySet()) { System.out.println(e.getKey() + " : " + e.getValue()); }

なるほど、Map.Entryというinterfaceが定義されてて、そのSetが返ってくるんですな。

コレクション(List, Set)を配列化する。

Collection#toArray

配列の中身を表示する。

java.util.Arrays.deepToString(array)

テキストファイルの読込

   public String loadData(String filename) {
       BufferedReader br = null;
       StringBuilder out = new StringBuilder();
       try{
           InputStream is = getClass().getClassLoader().getResourceAsStream(filename);
           br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
           String buf = null;
           while((buf = br.readLine()) != null){
               out.append(buf.trim());
           }
       } catch (IOException e){
           e.printStackTrace();
       } finally {
           try {
               if (br == null) br.close();
           } catch (IOException e) {
               e.printStackTrace();
           }
       }
       return out.toString();
   }

日付書式文字列

当日の日付を(YYYY/MM/DD)で取得したいとき。

String today = String.format("%1$tY/%1$tm/%1$td", new Date());
もしくは
Date date = new Date();
String today = String.format("%tY/$tm/$td", date, date, date);

この場合「%1$,3d」が書式になる。 %1$tY

  • %は書式の開始を示す。
  • 1$は引数のインデックスを示す。ひとつの引数を使い回すときなどに必要。今回の場合はひとつなので無くても良い。
  • tは日付変換を指定する。
  • t以降の文字は、APIマニュアル参照(Ymd)

Thread

wait,notify,notifyAll

ウェイトセット

  • インスタンスごとに用意されているスレッドの待合室

javaの継承時のアクセス制御

パッケージプライベートなアクセスクラスでインターフェイスを使いたい

  • インタフェイスを使っているが、パッケージプライベートなので

実装クラスの各メソッドのアクセスもパッケージプライベートにしたいという要件

  • まずクラスのアクセス指定子とクラスメンバーの指定子は別物らしい(パーフェクトJava:P143)

    • publicとパッケージプライベートの2種類しかない
  • 継承時のクラスはスーパクラスにあるメッソドよりアクセス指定子のスコープを広めることはできても緩めることはできない。

    • これはコンパイルの挙動で確認。言語仕様などの裏どりはとれていない。
  • インタフェイスはpublicしか指定できないので、上記の仕様により常にパブリックメソッドになる。

現時点でわかってないのは、クラスのアクセススコープがパッケージプライベートのときに メソッドをパブリックにしたときの実質的なアクセススコープはどうなるかということ。