分类 Java 相关 下的文章

Java 语言的 Exception

定义:
An exception is an event, which occurs during the execution of a program, that disrupts the normal flow of the program's instructions.

类继承关系:
Object
--Throwable .............................. 鼻祖, 所有 exception 的祖先
----Error .................................... 程序外部问题, 无法预期, 不可恢复
----Exception ............................. 除 RuntimeException 外, 都可预期, 可恢复
------RuntimeException ............. 程序内部问题, 无法预期, 不可恢复

不可预期的 Error 和 RuntimeException 都是不强制需要 try 或 throws 声明捕获的.
除了 Error 和 RuntimeException, 及其之类之外, 都需要 try 或 throws 声明捕获, 包括 throw 的 Throwable.

Error 和 RuntimeException, 及其子类被认为是 unchecked exception, 其他被认为是 checked exception, checked exception 都必须被声明捕获.

除了 try-catch-finally 块之外, Java SE 7 引入了 try-with-resources 语句, 这种新的语句特别使用于可以 Closeable 的 resources. 凡是实现 java.io.Closeable 接口的对象, 都可以通过这种语句来自动 close resource;

try (BufferedReader br = new BufferedReader(new FileReader("a.txt"))) {
    br.readLine();
}

当然 try 后面的括号中可以 声明多个 resource, 用;分开就行.
同时, 它仍然还可以跟 catch, finally 块.

Java SE 7 还引入了下面的语句:

catch (IOException|SQLException ex) {
    logger.log(ex);
    throw ex;
}

一般的try语句, 必须有 catch 或者 finally 跟随, 但是 try-with-resource 语句之后, 就不必了.

Java 正则表达式

正则表达式除了查看是否匹配之外, 还可以获取匹配的内容, 甚至修改, 替换匹配的内容.

Java 的正则表达式只有3个类, 都在 java.util.regex 包下面: Pattern, Matcher, 和 PatternSyntaxException.

  1. Pattern 是一个正则表达式的编译后表示, 只能通过它的 compile 静态方法获得;
  2. Matcher 就是一个执行正则表达式的引擎, 可以不断的查询, 检索输入的字符串. 它只能通过 pattern 的 matcher 方法获得;
  3. PatternSyntaxException 不同于一般的 exception, 它能提供更过与表达式匹配相关的错误信息;

字符类的例子

  • [abc]................a, b, or c (simple class)
  • [^abc]..............Any character except a, b, or c (negation)
  • [a-zA-Z]...........a through z, or A through Z, inclusive (range)
  • [a-d[m-p]]........a through d, or m through p: [a-dm-p] (union)
  • [a-z&&[def]].....d, e, or f (intersection)
  • [a-z&&[^bc]]....a through z, except for b and c: [ad-z] (subtraction)
  • [a-z&&[^m-p]]..a through z, and not m through p: [a-lq-z]

预先定义的字符类:

  • .------Any character (may or may not match line terminators)
  • \d----A digit: [0-9]
  • \D----A non-digit: [^0-9]
  • \s----A whitespace character: [ \t\n\x0B\f\r]
  • \S---A non-whitespace character: [^\s]
  • \w---A word character: [a-zA-Z_0-9]
  • \W---A non-word character: [^\w]

数量限定:

  • X?.................once or not at all
  • X*..................zero or more times
  • X+.................one or more times
  • X{n}...............exactly n times
  • X{n,}..............at least n times
  • X{n,m}...........at least n but not more than m times

要注意 0长度匹配 问题

边界匹配:

  • ^...........The beginning of a line
  • $...........The end of a line
  • \b..........A word boundary
  • \B..........A non-word boundary
  • \A..........The beginning of the input
  • \G..........The end of the previous match
  • \Z..........The end of the input but for the final terminator, if any
  • \z...........The end of the input

((A)(B(C))) 前面这个表达式有4 个分组.

Java 语言的正则表达式和 Perl 语言的最相近.

java.lang.String 的这4个方法都支持正则表达式: matches, split, replaceAll, replaceFirst. replace 方法不支持;

BackReference: 在后面要引用前面提到的分组:

在正则表达式中用 \ 后面跟数字, 代表引用表达式中第一个分组, 比如下面例子中的 \1 代表要再次出现前面的第一个一样的分组.
Pattern pattern2 = Pattern.compile("(\\d\\d)(\\w)\\1");
Matcher matcher2 = pattern2.matcher("12a12");
System.out.println(matcher2.find());
matcher2 = pattern2.matcher("12b13");
System.out.println(matcher2.find());

在 String 的 replaceAll replaceFirst 中可以使用 $后面跟数字代表正则表达式前面提到的分组, 下面例子中使用第1,3个分组替换原来
System.out.println("22:12".matches("(\\d\\d)(:)(\\d\\d)"));
System.out.println("22:12".replaceAll("(\\d\\d)(:)(\\d\\d)", "$1$3"));

参考:
Oracle Java2e Trail
Java Regex - Tutorial

Java String.intern() 方法

是什么? 为什么?

看到有个统计说, 在 JVM 的内存中, String 大概占到20% ~ 50% 的内存区, 那么这么多的 String 必定有很多重复的, 既然是重复的, 那就可以只在内存放一份, 所有使用这个 String 的 reference 都指向同一块内存. 那么 JVM 就在 permanet generation 放置了一个 StringSet(也有称 StringTable, StringCache), 当一个 String instance 调用 intern 方法的时候, 它先检查这个 String 在 StringSet 中是否存在, 如存在, 就返回这个存在的 String, 否则, 在 StringSet 中添加这个 String, 并且返回新加的这个 String.
这前提是基于: Java 的 String 是 immutable 的: 如果你改变了 String 的一部分, 原来的 reference 就指向了一个新的String. 如果都在原来的 String 的内存区修改, 那么就不能放到 StringSet 了.
另外, 编译器自动把你程序中的类名, 方法名, String 常量值, 字面值 等都事先放入了 StringSet. 这个 StringSet 是有 String 这个 class 所管理的.
类似的机制, 在整数类型 (Byte, Short, Integer, Long) 的 valueOf 方法中都有体现, 默认 -128 ~ 127 都放入了 cache.

优缺点?

如果你有大量的重复的 String 值要在程序中使用, 并且是运行时生成的 String, 通过 intern 方法, 会大大节省内存, 并且减少 GC 的量. 但是, 带来是效果是需要能多的时间. 时间 VS 内存. 关于时间和内存的比较, 详细可以看 refer 2.

如果是仅仅使用 intern 的值来用 == 对比, 完全没有必要, 时间上算起来, 差不多.


摘抄:
String interning takes a String instance (so it already exists in the Heap) and checks if an identical copy exists already in a StringTable.
That StringTable is basically a HashSet that stores the String in the Permanent Generation. The only purpose of that Table is to keep a single instance of the String alive. If it is in there, the instance is returned. If its not, its added to the String Table
Note that ALL Strings which are hardcoded (as constant or anywhere in code) are automatically interned by the compiler.

参考:

  1. Save Memory by Using String Intern in Java
  2. String spec