Vector类 简介 Vecrtor类实现了一个动态数组。和 ArrayList 很相似,但是两者是不同的:
Vector 是同步访问的。
Vector 包含了许多传统的方法,这些方法不属于集合框架。
Vector 主要用在事先不知道数组的大小,或者只是需要一个可以改变大小的数组的情况。
构造方法 1 2 3 4 5 6 7 8 9 10 11 new Vector ();new Vector (int size);new Vector (int size,int incr);new Vector (Collection c);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 import java.util.*;public class VectorDemo { public static void main (String args[]) { Vector v = new Vector (3 , 2 ); System.out.println("Initial size: " + v.size()); System.out.println("Initial capacity: " + v.capacity()); v.addElement(new Integer (1 )); v.addElement(new Integer (2 )); v.addElement(new Integer (3 )); v.addElement(new Integer (4 )); System.out.println("Capacity after four additions: " + v.capacity()); v.addElement(new Double (5.45 )); System.out.println("Current capacity: " + v.capacity()); v.addElement(new Double (6.08 )); v.addElement(new Integer (7 )); System.out.println("Current capacity: " + v.capacity()); v.addElement(new Float (9.4 )); v.addElement(new Integer (10 )); System.out.println("Current capacity: " + v.capacity()); v.addElement(new Integer (11 )); v.addElement(new Integer (12 )); System.out.println("First element: " + (Integer)v.firstElement()); System.out.println("Last element: " + (Integer)v.lastElement()); if (v.contains(new Integer (3 ))) System.out.println("Vector contains 3." ); Enumeration vEnum = v.elements(); System.out.println("\nElements in vector:" ); while (vEnum.hasMoreElements()) System.out.print(vEnum.nextElement() + " " ); System.out.println(); } }
执行结果为:
1 2 3 4 5 6 7 8 9 10 11 12 13 Initial size: 0 Initial capacity: 3 Capacity after four additions: 5 Current capacity: 5 Current capacity: 7 Current capacity: 9 First element: 1 Last element: 12 Vector contains 3. Elements in vector: 1 2 3 4 5.45 6.08 7 9.4 10 11 12
String split()方法 split()方法根据匹配给定的正则表达式来拆分字符串
注意:
.
、 $
、 |
和 *
等转义字符,必须得加 \\
。
多个分隔符,可以用 |
作为连字符。
语法 1 2 3 4 5 6 public String[] split(String regex, int limit)
例子 1 2 3 4 5 6 7 8 9 10 11 12 String str2 = new String ("www.runoob.com" );System.out.println("转义字符返回值 :" ); for (String retval: str2.split("\\." , 3 )){ System.out.println(retval); } String str3 = new String ("acount=? and uu =? or n=?" );System.out.println("多个分隔符返回值 :" ); for (String retval: str3.split("and|or" )){ System.out.println(retval); }
上述例子的结果为
1 2 3 4 5 6 7 8 9 10 转义字符返回值 : www runoob com 多个分隔符返回值 : acount=? uu =? n=?
HashMap computeIfAbsent()
方法 computeIfAbsent()
方法对 hashMap 中指定 key 的值进行重新计算,如果不存在这个 key,则添加到 hashMap 中。
语法 1 2 3 4 5 6 hashmap.computeIfAbsent(K key, Function remappingFunction)
实例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public static void main (String[] args) { HashMap<String, Integer> prices = new HashMap <>(); prices.put("Shoes" , 200 ); prices.put("Bag" , 300 ); prices.put("Pant" , 150 ); System.out.println("HashMap: " + prices); int shirtPrice = prices.computeIfAbsent("Shirt" , key -> 280 ); System.out.println("Price of Shirt: " + shirtPrice); int bagPrice = prices.computeIfAbsent("Bag" , key -> 200 ); System.out.println("Price of Bag: " + bagPrice); System.out.println("Updated HashMap: " + prices); }
上述实例的输出结果为
1 2 3 4 HashMap: { Pant=150 , Bag=300 , Shoes=200 } Price of Shirt: 280 Price of Bag: 300 Updated HashMap: { Pant=150 , Shirt=280 , Bag=300 , Shoes=200 }
Shirt的映射关系不存在,所以调用计算函数key -> 280
,将key值的value设为280并存储在map中;Bag的映射关系已经存在,所以直接返回200。这里的计算函数是一个Lambda表达式
String trim()方法 本文参考自5分钟了解一下,String.trim()到底做了什么事
前言 印象中trim()
函数就是用作去除字符串首尾空格,如下
1 2 3 4 5 6 7 String str = " Hello World " ;System.out.println("trim()操作前字符串长度:" + str.length()); System.out.println("trim()操作后字符串长度:" + str.trim().length()); trim()操作前字符串长度:13 trim()操作后字符串长度:11
这里进行一个小插曲:
Java 语言规范规定,Java 的 char 类型是 UTF-16 的 code unit,也就是一定是16位(2字节)。
char(字符)的范围是:0-65535 or(\u0000
~\uFFFF
)
其中空格键在Ascii表中对应的是32也就是\u0020
进入源码
其大致意思是
删除任何前置和后置空格(其实是小于\u0020
的字符);
如果String对象表示一个空字符串,则返回对这个String对象的引用(返回一个新对象);
如果String对象表示的字符的首和尾字符的编码都大于\u0020
(空格字符),则返回对这个String对象的引用;
如果String字符串中没有编码大于\u0020
的字符,则返回一个表示空字符串的string对象;
假设 k 是大于\u0020
的字符串中第一个字符的索引,假设 m 是大于\u0020
的字符串中最后一个字符的索引。返回一个表示该字符串的子字符串,该子字符串以下标 k 处的字符开始,以下标 m 处的字符结束。即 substring(k, m + 1)。
如果使用trim()
后的字符串长度不等于使用前的长度,就返回一个新String对象给你;如果等于,就还给你原String对象.
下面是对应规则的例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 @Test public void str1 () { String str = " Hello World " ; System.out.println(str.length()); System.out.println("trim():" + str.trim().length()); } @Test public void str2 () { String str1 = " " ; System.out.println(str1.length()); String str2 = str1.trim(); System.out.println("trim()->" + str2.length()); System.out.println(str1 == str2); } @Test public void str3 () { String str1 = "aaa bbb ccc" ; System.out.println(str1.length()); String str2 = str1.trim(); System.out.println(str2.length()); } @Test public void str4 () { char [] chars = new char [32 ]; for (int i = 0 ; i < 32 ; i++) { chars[i] = (char ) i; } String oldStr = new String (chars); System.out.println(oldStr.length()); String newStr = oldStr.trim(); System.out.println(newStr.trim().length()); System.out.println(oldStr == newStr); } @Test public void str5 () { char [] chars = new char [8 ]; for (int i = 0 ; i < 3 ; i++) { chars[i] = (char ) i; } chars[3 ] = 65 ; chars[4 ] = 66 ; chars[5 ] = 31 ; chars[6 ] = 68 ; chars[7 ] = 21 ; String oldStr = new String (chars); System.out.println("oldStr.length():" + oldStr.length()); System.out.println("oldStr:" + oldStr); String newStr = oldStr.trim(); System.out.println("newStr.length():" + newStr.length()); System.out.println("newStr:" + newStr); } @Test public void str6 () { char [] chars = new char [5 ]; for (int i = 0 ; i < 3 ; i++) { chars[i] = (char ) i; } chars[3 ] = 65 ; chars[4 ] = 66 ; String str1 = new String (chars); String str2 = "ABCDE" ; String newStr1 = str1.trim(); String newStr2 = str2.trim(); System.out.println("str1.length():" + str1.length()); System.out.println("newStr1.length():" + newStr1.length()); System.out.println(str1 == newStr1); System.out.println("=========================" ); System.out.println("str2.length():" + str2.length()); System.out.println("newStr2.length():" + newStr2.length()); System.out.println(str2 == newStr2); }
所以trim()
到底干了啥
去除 String
中的首尾空格;
无法去除字符串中间含有空格的;
准确说实际去除的是小于十进制32(32就是空格,可以去看Ascii表)的所有字符。
当 String
中全是小于32的字符时,返回一个新的字符给你。
String.trim()
长度变化就是新对象,无变化就还是自己。
AtomicInteger 参考自原子操作类AtomicInteger详解
Interger的原子操作类
为什么要使用原子操作类 对于Java中的运算操作,例如自增或自减,若没有进行额外的同步操作,在多线程 环境下就是线程不安全的。num++解析为num=num+1,明显,这个操作不具备原子性,多线程并发共享这个变量时必然会出现问题。测试代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class AtomicIntegerTest { private static final int THREADS_CONUT = 20 ; public static int count = 0 ; public static void increase () { count++; } public static void main (String[] args) { Thread[] threads = new Thread [THREADS_CONUT]; for (int i = 0 ; i < THREADS_CONUT; i++) { threads[i] = new Thread (new Runnable () { @Override public void run () { for (int i = 0 ; i < 1000 ; i++) { increase(); } } }); threads[i].start(); } while (Thread.activeCount() > 1 ) { Thread.yield(); } System.out.println(count); } }
这里运行了20个线程,每个线程对count变量进行1000此自增操作,如果上面这段代码能够正常并发的话,最后的结果应该是20000才对,但实际结果却发现每次运行的结果都不相同,都是一个小于20000的数字。这是为什么呢?
如果换成Volatile修饰count变量呢 顺带说下volatile关键字很重要的两个特性:
保证变量在线程间可见,对volatile变量所有的写操作都能立即反应到其他线程中,换句话说,volatile变量在各个线程中是一致的(得益于java内存模型—“先行发生原则”);
禁止指令的重排序优化;
那么换成volatile修饰count变量后,会有什么效果呢?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class AtomicIntegerTest { private static final int THREADS_CONUT = 20 ; public static volatile int count = 0 ; public static void increase () { count++; } public static void main (String[] args) { Thread[] threads = new Thread [THREADS_CONUT]; for (int i = 0 ; i < THREADS_CONUT; i++) { threads[i] = new Thread (new Runnable () { @Override public void run () { for (int i = 0 ; i < 1000 ; i++) { increase(); } } }); threads[i].start(); } while (Thread.activeCount() > 1 ) { Thread.yield(); } System.out.println(count); } }
结果似乎又失望了,测试结果和上面的一致,每次都是输出小于20000的数字。这又是为什么么? 上面的论据是正确的,也就是上面标红的内容,但是这个论据并不能得出”基于volatile变量的运算在并发下是安全的”这个结论,因为核心点在于java里的运算(比如自增)并不是原子性的。
用了AtomicInteger类后会变成什么样子呢? 把上面的代码改造成AtomicInteger原子类型,先看看效果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 import java.util.concurrent.atomic.AtomicInteger; public class AtomicIntegerTest { private static final int THREADS_CONUT = 20 ; public static AtomicInteger count = new AtomicInteger (0 ); public static void increase () { count.incrementAndGet(); } public static void main (String[] args) { Thread[] threads = new Thread [THREADS_CONUT]; for (int i = 0 ; i < THREADS_CONUT; i++) { threads[i] = new Thread (new Runnable () { @Override public void run () { for (int i = 0 ; i < 1000 ; i++) { increase(); } } }); threads[i].start(); } while (Thread.activeCount() > 1 ) { Thread.yield(); } System.out.println(count); } }
结果每次都输出20000,程序输出了正确的结果,这都归功于AtomicInteger.incrementAndGet()方法的原子性。
暂时先了解到这里,后续可以在开头引用链接处更加深入了解
chain.doFilter(request,response) 过滤器的生命周期一般要经过以下三个阶段
初始化: 当容器第一次加载该过滤器时,init()方法将被调用。该类在这个方法中包含了一个指向Filter Config
对象的引用
过滤: 过滤器的大多时间都消耗在这里,doFilter方法被容器调用,同时传入分别指向这个请求/响应链中的Servlet Request、Servlet Response和Filter Chain对象的引用,然后过滤器就有机会处理请求,将处理任务传递给链中的下一个资源(通过调用Filter Chain对象引用上的doFilter方法),之后在处理控制权返回该过滤器时处理响应
析构 容器紧跟着在垃圾收集之前调用destroy()方法,以便能够执行任何必须的清理代码
关于chain.doFilter(request, response)
他的作用是请求转发发给过滤器链上的下一个对象。这里的下一个指的是下一个Filter,如果没有filter那他就是你请求的资源。一般filter都是一个链,web.xml里面配置了几个就有几个。一个一个的连在一起request -> filter1 -> filter2 -> filter3... -> request resource