分类 Java 相关 下的文章

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

单例模式 -> ThreadLocal -> new

Java 是多线程, 面向对象的编程语言. 多线程有时候也需要 share 一个实例对象. 一个 JVM 中的多线程可能会产生如下的 share 模式:

  1. 所有线程使用同一个实例对象: 单例模式;
  2. 每个线程使用一个实例对象: ThreadLocal;
  3. 最普遍的, 一个实例对象就是内存堆中的一个实例对象: new

如何做到一个 JVM 中的 单例模式:

  1. 构造函数全都是 private
  2. 因为构造函数是 private, 所以只能该 class 提供一个唯一内部的 static instance. 该 static instance 可以通过 public 暴露, 或者通过一个 public static 方法暴露. 通过方法暴露, 可以 lazy init;

其实, 如上并不能保证一个 JVM 中只有一个 instance, 比如2个 ClassLoader 在同一级, 分别 load 该 class, 或者反序列化该类;

ThreadLocal

前面要加 static final 修饰符. 不加 static, 不能确保一个线程只有一个实例. 不加 final, 可能会被改变的

How to create a java object?

  1.    new Object();
    
  2.    Class.forName(“com.txhcqy.A”).newInstance();
    
  3.    反序列化
    
  4.    反射机制中的Constructor
    

java monitor lock

每个 Java 对象都关联一个 monitor, 运行的线程可以对 monitor 进行 lock 或者 unlock. 同一时刻, 只能有一个线程获得一个对象的锁, 其它尝试获得此锁的线程都被 block 住, 直到当前线程释放此锁.

要使用 java.lang.Object 的 wait, notify 方法, 必须获得此对象的 monitor 的 lock, 所以 wait, notify, notifyAll 必须在获得此锁的 synchronized 的代码块中.

最基本的线程等待, 是使用 while(true) { //break 条件 或启动新线程/进程去做事;}, 但是这种是一直占用 CPU, 称之为 busy waiting. 如果想暂时不占 CPU 可以让线程 inactive, 等到一定条件唤醒线程. java 让线程 inactive 的方法是 wait(), wait(时间); 唤醒的方式是 notify, notifyAll,(必须是同一个对象), 或者 发出interupt 信号.

另外一个让线程暂时休眠的方法是 Thread.currentThread().sleep(时间). 让线程暂时休眠固定的时间, 倒是自动醒来, 不需要唤醒.

参考: Chapter 17. Threads and Locks

Struts2 学习笔记 2.3.x

All config files for struts2


Struts2 配置文件
web.xml -> filter dispatcher -> init framework
struts-default.xml -> struts.xml
struts-default.property -> struts.property

Interceptor -> Action -> Result
request(url) -> action class -> method -> return string -> result type
predefined result names[token] from com.opensymphony.xwork2.ActionSupport -> Action (Interface):
String SUCCESS = "success";
String NONE = "none";
String ERROR = "error";
String INPUT = "input";
String LOGIN = "login";

参考: http://struts.apache.org/release/2.3.x/docs/guides.html