【java提高】---细则(1)

异常

 

一.异常与错误的区别

     再讲异常之前我们就应该要知道异常和错误的区别

     Error类和Exception类的父类都是throwable类,他们的区别是:

     Error类一般是指与虚拟机相关的问题,如系统崩溃,虚拟机错误,内存空间不足,方法调用栈溢等。对于这类错误的导致的应用程序中断,

仅靠程序本身无法恢复和和预防,遇到这样的错误,建议让程序终止。

    Exception类表示程序可以处理的异常,可以捕获且可能恢复。遇到这类异常,应该尽可能处理异常,使程序恢复运行,而不应该随意终止异常。

 

二.异常的体现分类

   1.checked 异常检查期异常 java.lang.Excetion 在编译期需要人工处理否则编译失败:Exception的子类除了运行期异常都是检查期异常

   2.非Checked异常运行时异常 java.lang.RuntimeException 不需要处理的直接能编译通过:所有的RuntimeException以及其子类都是运行异常

   举例:运行期异常

    结果:运行期异常,当你敲好代码时不会报错,而当你运行时才会报除数不能为0的错误

   举例:检查期异常:

   结果:检查期异常,当你编译的时候就会报错,一定要抛出异常编译才能通过

 三.异常的处理机制

      Java语言主要依赖于 try  catch  finally  和throws  throw  五个关键字来描述异常

 1) 在发生异常的地方直接处理

    使用try catch finally  直接处理异常

     a)  try-catch-finally结构中try块是必须有的,catch和finally块为可选,但两者至少必须出现其中之一。

     b) catch  可以同时出现多个,但一个异常最多捕获一个catch,而且catch的顺序是从上往下

     c) finally  无论是否捕获异常都会执行的一行代码

演示1:try异常

复制代码
 1 public class TestException {
 2         public static void main(String[] args) {
 3              int c = 0;
 4                 try
 5                 {
 6                     int a = 3;
 7                     int b = 0;
 8                     // 这块代码出现了异常
 9                      c = a / b;
10                     // 那么异常之后的代码都不会被执行
11                     System.out.println("Hello World");
12                 }
13                 catch (ArithmeticException e)
14                 {
15                     System.out.println("除数不能为零");
16                 }
17                 finally
18                 {
19                     //不管有没有发生异常,finally语句块都会被执行
20                     System.out.println("Welcome");
21                 }
22                 System.out.println(c);
23                 // 当b为0时,有异常,输出为c的初始值0
24         }
25     }
26    //输出结果:除数不能为零  Welcome   0
复制代码

演示2:带有return的异常

复制代码
 1 import java.io.FileInputStream;
 2 import java.io.FileNotFoundException;
 3  public class DemoException {
 4      public static void main(String[] args) {
 5             int a=test3();
 6             System.out.println(a);    
 7   }
 8      @SuppressWarnings("finally")
 9      public static int  test3(){
10              try {
11              System.out.println(9 / 0);
12              return 1;
13              } catch (Exception e) {
14                System.out.println("呵呵");
15                 return 2;
16             }finally{  
17              System.out.println("哈哈");
18              return 3;
19        }
20     }
21  }
22  //输出结果 "呵呵""哈哈" 3
复制代码

 

得出结论:作用范围   return  终止整个方法体,但在finally出现之前  return是老大  finally 作用范围> return

2)将异常抛给调用者让调用者处理 

1   //throws在方法体头部通过声明  抛出异常...
2     public void dealFile() throws FileNotFoundException{
3         FileInputStream fis =new FileInputStream("C:/name.txt");
4      }
5    //那么那么上面调用这个方法可以选择是继续抛出,还是捕获异常

案例一:通过throws抛出异常,调用者直接捕获抛出的异常

 throws异常

运行结果:

   非数据类型不能转换。

注意使用Throws是的限制

两小原则

 使用throws 声明抛出异常一个限制

 子类继承父类重写父类的方法

 子类抛出的异常必须比父类少

 子类抛出的异常必须比父类小

 两小原则是针对检查期异常的,运行期异常不遵循这个规则(RuntimeException 以及子类)

案例二:通过throw抛出异常

 throw异常

运行结果如下:

面试题:Throw 和Throws有什么区别?

 Throw语句是用在方法体内表示抛出的异常由方法体内的语句处理

 Throws  语句是在方法声明之后抛出异常表示在抛出的异常交给调用者处理

 Throws 要么使用try –catch –finally 处理要么继续抛出

 四.自定义异常 

   所谓自定义异常,通常就是定义一个类,去继承Exception类或者它的子类。因为异常必须直接或者间接地继承自Exception类。

  通常情况下,会直接继承自Exception类,一般不会继承某个运行时的异常类。

  自定义异常可以用于处理用户登录错误,用户输入错误提示等。

   自定义异常需要遵循以下步骤

  1. 继承RuntimeExcetion  或者Exception
  2. 写一个无参的构造函数
  3. 写一个String类型的构造函数

 举例:自定义异常:

复制代码
public class MyException extends Exception
{
    public MyException()
    {
        super();
    }    
    public MyException(String message)
    {
        super(message);
    }
}
复制代码

一种处理异常方式

复制代码
public class ExceptionTest4
{

    public void method(String str) throws MyException
    {
        if(null == str)
        {
            throw new MyException("传入的字符串参数不能为null!");
        }
        else
        {
            System.out.println(str);
        }
    }
    public static void main(String[] args) throws MyException //异常处理方式1,不断向外抛出
    {
        ExceptionTest4 test = new ExceptionTest4();
        test.method(null);
    }
}
复制代码

另一种异常处理方式:

复制代码
 1 public class ExceptionTest4
 2 {
 3 
 4     public void method(String str) throws MyException
 5     {
 6         if (null == str)
 7         {
 8             throw new MyException("传入的字符串参数不能为null!");
 9         }
10         else
11         {
12             System.out.println(str);
13         }
14     }
15 
16     public static void main(String[] args)
17     {
18         //异常处理方式2,采用try...catch语句
19         try
20         {
21             ExceptionTest4 test = new ExceptionTest4();
22             test.method(null);
23 
24         }
25         catch (MyException e)
26         {
27             e.printStackTrace();
28         }    
29         finally
30         {
31             System.out.println("程序处理完毕");
32         }
33 
34     }
35 }
复制代码

最后说一句,try-catch-finally虽好用,但是如果是滥用,这样只是会让程序的可读性变的很糟糕,当程序报错,就无法快速准确的定位了。

如果有个别地方写的不到位或者不够完善希望大家多多指点,看了有不明白的地方也可以留言,我也会尽快帮助解答。

正则表达式---常用符号

  首先声明,我这里列表的是经常使用的一些符号,如果你想得到全部,那建议你通过API中,搜索Pattern类,会得到所有符号。

 

字符类
[abc] ab 或 c(简单类)
[^abc] 任何字符,除了 ab 或 c(否定)
[a-zA-Z] a 到 z 或 A 到 Z,两头的字母包括在内(范围)
[a-d[m-p]] a 到 d 或 m 到 p[a-dm-p](并集)
[a-z&&[def]] de 或 f(交集)
[a-z&&[^bc]] a 到 z,除了 b 和 c[ad-z](减去)
[a-z&&[^m-p]] a 到 z,而非 m 到 p[a-lq-z](减去)

 

 

 

 

 

 

 

预定义字符类
. 任何字符(与行结束符可能匹配也可能不匹配)
\d 数字:[0-9]
\D   非数字: [^0-9]
\s 空白字符:[ \t\n\x0B\f\r]
\S 非空白字符:[^\s]
\w 单词字符:[a-zA-Z_0-9]
\W 非单词字符:[^\w]

 

 

 

 

 

 

 

边界匹配器
^ 行的开头
$ 行的结尾
\b 单词边界
\B 非单词边界

 

 

 

 

 

Greedy 数量词
X? X,一次或一次也没有
X* X,零次或多次
X+ X,一次或多次
X{n} X,恰好 n 次
X{n,} X,至少 n 次
X{n,m} X,至少 n 次,但是不超过 m 次

 

 

 

 

 

 

为了让大家更加明白,对上面的进行部分解释

元字   符 举例
.点  例如正则表达式r.t匹配这些字符串:rat、rut、r t,但是不匹配root。
$ 例如正则表达式weasel$ 能够匹配字符串"He's a weasel"的末尾 
但是不能匹配字符串"They are a bunch of weasels."
^ 匹配一行的开始。例如正则表达式^When in能够匹配字符串"When in the"的开始,但是不能匹配"What and When in the"
* 匹配0或多个正好在它之前的那个字符。例如正则表达式。*意味着能够匹配任意数量的任何字符。
\ 这个是用来转义用的。例如正则表达式\$被用来匹配美元符号,而不是行尾,类似的,正则表达式\.用来匹配点字符,而不是任何字符的通配符。
| 将两个匹配条件进行逻辑“或”(Or)运算。例如正则表达式(him|her) 匹配" to him"和"i to her",但是不能匹配" to them."。
+ 匹配1或多个正好在它之前的那个字符。例如正则表达式9+匹配9、99、999等。
? 匹配0或1个正好在它之前的那个字符。
{i}
{i,j}

例如正则表达式A[0-9]{3} 能够匹配字符"A"后面跟着正好3个数字字符的串,例如A123、A348等,但是不匹配A1234。

而正则表达式[0-9]{4,6} 匹配连续的任意4个、5个或者6个数字字符。

 

 

 最后讲一个初学者很容易搞混的知识点

正则表达式的() [] {}的区别

() 是为了提取匹配的字符串。表达式中有几个()就有几个相应的匹配字符串。圆括号中的字符视为一个整体。

[]是定义匹配的字符范围。比如 [a-zA-Z0-9] 表示相应位置的字符要匹配英文字符和数字。

{}一般用来表示匹配的长度,比如 \s{3} 表示匹配三个空格,\s[1,3]表示匹配一到三个空格。

(0-9) 匹配 '0-9′ 本身。 [0-9]* 匹配数字(注意后面有 *,可以为空)[0-9]+ 匹配数字(注意后面有 +,不可以为空){1-9} 写法错误。

[0-9]{0,9} 表示长度为 0 到 9 的数字字符串。

注意:关于() [] {}区别,如果你还没用明白的话,也没有关系,这两天我还会写正则表达式类文章,到时候我会用列子说明。

正则表达式

      说真的正则表达式真不好写,当我收集资料准备开始写的时候,发现收集的东西越来越多范围也越来越广,我文章的前提就是文章要清晰,

在缕清自己思路之后,我从先简后难的方式来写有关正表达式,你们如果觉得这篇写的还可以的话,可以先关注我,接下来我会陆续更新。

  一.什么是正则表达式

      正则表达式(regular expressions)是一种描述字符串集的方法,它是以字符串集中各字符串的共有特征为依据的。

正则表达式可以用于搜索、编辑或者是操作文本和数据。这是官方表达听的有点绕口,用通俗的话来说就是:正则表达式主要用来处理和文本有关的内容

常见的处理方式有四种:1.匹配  2.切割   3.替换  4.获取    在下面我也会一一举例说明。

二.正则表达式常见的符号含义

    这个我在正则表达式(1)中,有关常用的也大概做个介绍,大家可以往前翻阅。

三.常见的处理方式有四种

(1)匹配   我这里使用的是字符串对象的方法  match(String regex),

复制代码
1 import java.util.regex.*;
2 public class TestException{
3       public static void main(String[] args) throws Exception {
4           String tel="18600000111";
5           String reg="1[3578]\\d{9}";  //首字母1,第二字母3,5,7,8,后面都是数字共有9位
6             boolean b1 =tel.matches(reg);
7         System.out.println(b1);//输出结果true
8       }
9 }
复制代码

 

(2)切割       我这里使用的是字符串中的split方法

案例一:切割一个或多个空格

复制代码
 1 //切割一个或者多个空格
 2 import java.util.regex.*;
 3 public class TestException{
 4       public static void main(String[] args) throws Exception {
 5           String str ="aaa bbb  ccc ddd    eee";
 6           String [] arr =str.split(" +");//“ +”表示至少有一个空格
 7           for(String s:arr){
 8               System.out.print(s);
 9           }
10       }
11 }
复制代码

运行结果;

aaabbbcccdddeee

案例二:通过.来切割字符串

复制代码
 1 //通过.来切割字符串
 2 import java.util.regex.*;
 3 public class TestException{
 4       public static void main(String[] args) {
 5           String str2="zhangsan.lisi.wangwu";
 6           /* \\是代表转义字符,如果你直接放split("."),是无法切割的,因为.在正则表达式中.有它特有的含义
 7              当你用转义之后\\.那么它就只代表一个点,而不具有特殊意义*/
 8           String [] arr2 =str2.split("\\.");
 9           for(String s:arr2){
10               System.out.println(s);
11           }
12       }
13 }
14 /* 补充:在java中需要转义的除了.外,还有需要先转义不能直接切割的:
15  *     $  ( )  *  +  [ ]   ?    \  ^  { }  |  
16  *     这么几个大家用它来切割的时候,转义后就可以了
17  */
复制代码

运行结果:

zhangsan
lisi
wangwu

案例三:用重复项来切割

复制代码
 1 //用重复项来切割
 2 import java.util.regex.*;
 3 public class TestException{
 4       public static void main(String[] args) {
 5           String str3 ="wer#######tayuio****asdfg";
 6           String reg ="(..)"; //(.)代表第一个任意字符    \\1代表回去第一组数据  +代表1个或者多个      
 7           String [] arr3=str3.split(reg);
 8           for(String s:arr3){
 9               System.out.println(s);
10           }
11       }
12 }
13 /* 补充:我怕初学者对"(.)\\1+",还没有搞懂,我这里在单独解释一下:(.)的字符视为一个整体。 \\1代表回去第一组数据
14  * 那它其实在这里也就代表(.),所以就相当于(.)(.)+,这里仅仅是相当于,也是为了好理解,其实他们还是有本质区别的
15  * 因为(.)==\\1,就是说如果.代表a,那么\\1也就代表a,而(.)≠(.),前面代表a后面可以代表b,因为前后两个点不是同一个点
16  * 我也不知道这样比较是否恰当, 反正意思就是这个意思
17  */
复制代码

运行结果:

wer
tayuio
asdfg

(3)替换  使用String字符串汇总的方法

案例一:把重复的数据 替换为#

复制代码
 1 //把重复的数据 替换为#
 2 import java.util.regex.*;
 3 public class TestException{
 4       public static void main(String[] args) {
 5           String str="wer#####yw****fghj"; 
 6           //把重复的数据 替换为#    
 7           str=str.replaceAll("(.)\\1+", "#");//(.) 第一个任意字符   \\1 取第一组数据   +  1个或者多个
 8           System.out.println(str) ; 
 9           }
10    }
复制代码

运行结果:

wer#yw#fghj

案列二:把重复项都变成单个

复制代码
1 import java.util.regex.*;
2 public class TestException{
3       public static void main(String[] args) {
4           String str="wer#####yw****fg???hj"; 
5     //后一个参数的含义 可以通过$  数字引用第一个参数中的组,这个美元符号代表就是前面小括号里的内容
6               str=str.replaceAll("(.)\\1+", "$1");
7               System.out.println(str); 
8           }
9    }
复制代码

运行结果:

wer#yw*fg?hj

案例三:电话号码中间几位用*表示

复制代码
1 import java.util.regex.*;
2 public class TestException{
3       public static void main(String[] args) {
4           String str2="15889895644";//158****5644  
5           str2=str2.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
6           System.out.println(str2);// $1表示符号前面第一个小括号,$2代表第二个,如果有第三个小括号,那也可以$3; 
7           }
8    }
复制代码

运行结果:

158****5644

(4)获取    字符串中没有直接提供该功能 只能通过正则表达匹配

案例一:获取正则表达式所匹配的字符串

复制代码
 1 import java.util.regex.*;
 2 public class TestException{
 3       public static void main(String[] args) {
 4           String str="da jio zhu yi laa, ming tian  fang jia laa";
 5           //1.定义规则
 6           String reg="\\b[a-z]{3}\\b";//任意三个字符 \\b 是单词的边界(明白为什么加这个)
 7           Pattern p =Pattern.compile(reg);
 8           //3.通过正则表达对象 获取匹配器对象   并把操作的字符串关联
 9           Matcher m =p.matcher(str);
10           while(m.find()){  //find()用来搜索与正则表达式相匹配的任何目标字符串
11           System.out.println(m.start()+"....."+m.group()+"..."+m.end());
12           } //start()开始位置    group()用来返回包含了所匹配文本的字符串     end()结束位置
13           }
14    }
15 /* 有关: 在regex(正则表达式)包中,包括了两个类,Pattern(模式类)和Matcher(匹配器类)。
16  * 这个大家也可以多去了解
17  */
复制代码

运行结果:

3.....jio...6
7.....zhu...10
14.....laa...17
35.....jia...38
39.....laa...42

四:最后来一个综合小案例

题目1:10.10.10.10   192.168.118.40  192.168.1.200  127.0.0.108   按照升序排序

复制代码
 1 import java.util.Arrays;
 2 import java.util.regex.*;
 3 public class TestException{
 4       public static void main(String[] args) {
 5           String ip="10.10.10.10  192.168.118.40  192.168.1.200  127.0.0.108";
 6           /*
 7            * 为了方便   每一个端都补零 保证每一个字段至少是三位
 8            */
 9           ip=ip.replaceAll("(\\d+)", "00$1");//补0,让至少有三位数
10           
11           ip=ip.replaceAll("0*(\\d{3})", "$1");//所有都变成三位数
12           
13           String [] ips =ip.split(" +");//用空格来切割
14           Arrays.sort(ips);//升序排序          
15           for(String x:ips){
16               System.out.println(x.replaceAll("0*(\\d+)", "$1"));//还原
17           }
18    }
19 }
20 /** 这个题目或许看着不难,难就难在思维模式,它这每一步都很关键,也是希望大家在学习的途中多思考,而不是停留在看的基础上
21  */
复制代码

运行结果:

10.10.10.10
127.0.0.108
192.168.1.200
192.168.118.40

这篇文章到这里结束了,接下来对于正则表达式我还会再写,比如Pattern(模式类)和Matcher(匹配器类),再比如如何获取文本中的电话号码等等深入的一些东西,不过最近应该不写了,

接下来我会写一些其它有关的知识。

Java使用patchca生成验证码

       Patchca是Piotr Piastucki写的一个java验证码开源库,打包成jar文件发布,patchca使用简单但功能强大。

本例实现了自定义背景,由于生成图片较小,波动太大时会导致部分文字显示不全,所以更改了滤镜属性。

效果图:

代码如下

复制代码
package com.ninemax.cul.servlet;  
  
import java.awt.Color;  
import java.awt.Graphics;  
import java.awt.image.BufferedImage;  
import java.awt.image.BufferedImageOp;  
import java.io.IOException;  
import java.io.OutputStream;  
import java.util.ArrayList;  
import java.util.List;  
import java.util.Random;  
  
import javax.imageio.ImageIO;  
import javax.servlet.ServletException;  
import javax.servlet.http.HttpServlet;  
import javax.servlet.http.HttpServletRequest;  
import javax.servlet.http.HttpServletResponse;  
import javax.servlet.http.HttpSession;  
  
import org.patchca.background.BackgroundFactory;  
import org.patchca.color.ColorFactory;  
import org.patchca.color.RandomColorFactory;  
import org.patchca.filter.ConfigurableFilterFactory;  
import org.patchca.filter.library.AbstractImageOp;  
import org.patchca.filter.library.WobbleImageOp;  
import org.patchca.font.RandomFontFactory;  
import org.patchca.service.Captcha;  
import org.patchca.service.ConfigurableCaptchaService;  
import org.patchca.text.renderer.BestFitTextRenderer;  
import org.patchca.text.renderer.TextRenderer;  
import org.patchca.word.RandomWordFactory;  
  
/**  
 * 验证码生成类  
 *  
 * 使用开源验证码项目patchca生成  
 * 依赖jar包:patchca-0.5.0.jar  
 * 项目网址:https://code.google.com/p/patchca/  
 *  
 * @author zyh 
 * @version 1.00  2012-7-12 New  
 */  
public class ValidationCodeServlet extends HttpServlet {  
    private static final long serialVersionUID = 5126616339795936447L;  
      
    private ConfigurableCaptchaService configurableCaptchaService = null;  
    private ColorFactory colorFactory = null;  
    private RandomFontFactory fontFactory = null;  
    private RandomWordFactory wordFactory = null;  
    private TextRenderer textRenderer = null;  
      
    public ValidationCodeServlet() {  
        super();  
    }  
  
    /** 
     * Servlet销毁方法,负责销毁所使用资源. <br> 
     */  
    public void destroy() {  
        wordFactory = null;  
        colorFactory = null;  
        fontFactory = null;  
        textRenderer = null;  
        configurableCaptchaService = null;  
        super.destroy(); // Just puts "destroy" string in log  
    }  
  
    public void doGet(HttpServletRequest request, HttpServletResponse response)  
            throws ServletException, IOException {  
        doPost(request, response);  
    }  
  
    public void doPost(HttpServletRequest request, HttpServletResponse response)  
            throws ServletException, IOException {  
        response.setContentType("image/png");  
        response.setHeader("cache", "no-cache");  
          
        HttpSession session = request.getSession(true);  
        OutputStream outputStream = response.getOutputStream();  
          
        // 得到验证码对象,有验证码图片和验证码字符串  
        Captcha captcha = configurableCaptchaService.getCaptcha();  
        // 取得验证码字符串放入Session  
        String validationCode = captcha.getChallenge();  
        session.setAttribute("validationCode", validationCode);  
        // 取得验证码图片并输出  
        BufferedImage bufferedImage = captcha.getImage();  
        ImageIO.write(bufferedImage, "png", outputStream);  
          
        outputStream.flush();  
        outputStream.close();  
    }  
  
    /** 
     * Servlet初始化方法 
     */  
    public void init() throws ServletException {  
        configurableCaptchaService = new ConfigurableCaptchaService();  
          
        // 颜色创建工厂,使用一定范围内的随机色  
        colorFactory = new RandomColorFactory();  
        configurableCaptchaService.setColorFactory(colorFactory);  
          
        // 随机字体生成器  
        fontFactory = new RandomFontFactory();  
        fontFactory.setMaxSize(32);  
        fontFactory.setMinSize(28);  
        configurableCaptchaService.setFontFactory(fontFactory);  
          
        // 随机字符生成器,去除掉容易混淆的字母和数字,如o和0等  
        wordFactory = new RandomWordFactory();  
        wordFactory.setCharacters("abcdefghkmnpqstwxyz23456789");  
        wordFactory.setMaxLength(5);  
        wordFactory.setMinLength(4);  
        configurableCaptchaService.setWordFactory(wordFactory);  
          
        // 自定义验证码图片背景  
        MyCustomBackgroundFactory backgroundFactory = new MyCustomBackgroundFactory();  
        configurableCaptchaService.setBackgroundFactory(backgroundFactory);  
          
        // 图片滤镜设置  
        ConfigurableFilterFactory filterFactory = new ConfigurableFilterFactory();  
          
        List<BufferedImageOp> filters = new ArrayList<BufferedImageOp>();  
        WobbleImageOp wobbleImageOp = new WobbleImageOp();  
        wobbleImageOp.setEdgeMode(AbstractImageOp.EDGE_MIRROR);  
        wobbleImageOp.setxAmplitude(2.0);  
        wobbleImageOp.setyAmplitude(1.0);  
        filters.add(wobbleImageOp);  
        filterFactory.setFilters(filters);  
          
        configurableCaptchaService.setFilterFactory(filterFactory);  
          
        // 文字渲染器设置  
        textRenderer = new BestFitTextRenderer();  
        textRenderer.setBottomMargin(3);  
        textRenderer.setTopMargin(3);  
        configurableCaptchaService.setTextRenderer(textRenderer);  
          
        // 验证码图片的大小  
        configurableCaptchaService.setWidth(82);  
        configurableCaptchaService.setHeight(32);  
    }  
      
    /** 
     * 自定义验证码图片背景,主要画一些噪点和干扰线 
     */  
    private class MyCustomBackgroundFactory implements BackgroundFactory {  
        private Random random = new Random();  
  
        public void fillBackground(BufferedImage image) {  
            Graphics graphics = image.getGraphics();  
              
            // 验证码图片的宽高  
            int imgWidth = image.getWidth();  
            int imgHeight = image.getHeight();  
              
            // 填充为灰色背景  
            graphics.setColor(Color.GRAY);  
            graphics.fillRect(0, 0, imgWidth, imgHeight);  
              
            // 画100个噪点(颜色及位置随机)  
            for(int i = 0; i < 100; i++) {  
                // 随机颜色  
                int rInt = random.nextInt(255);  
                int gInt = random.nextInt(255);  
                int bInt = random.nextInt(255);  
                  
                graphics.setColor(new Color(rInt, gInt, bInt));  
                  
                // 随机位置  
                int xInt = random.nextInt(imgWidth - 3);  
                int yInt = random.nextInt(imgHeight - 2);  
                  
                // 随机旋转角度  
                int sAngleInt = random.nextInt(360);  
                int eAngleInt = random.nextInt(360);  
                  
                // 随机大小  
                int wInt = random.nextInt(6);  
                int hInt = random.nextInt(6);  
                  
                graphics.fillArc(xInt, yInt, wInt, hInt, sAngleInt, eAngleInt);  
                  
                // 画5条干扰线  
                if (i % 20 == 0) {  
                    int xInt2 = random.nextInt(imgWidth);  
                    int yInt2 = random.nextInt(imgHeight);  
                    graphics.drawLine(xInt, yInt, xInt2, yInt2);  
                }  
            }  
        }  
    }  
}  
复制代码

 

 由于是个Servlet所以web.xml配置如下:

复制代码
<servlet>  
    <servlet-name>validationCode</servlet-name>  
    <servlet-class>com.ninemax.cul.servlet.ValidationCodeServlet</servlet-class>  
  </servlet>  
  
  <servlet-mapping>  
    <servlet-name>validationCode</servlet-name>  
    <url-pattern>/validationCodeServlet.png</url-pattern>  
  </servlet-mapping>  
复制代码

 

JSP引用(部分):

<img id="validationCode" alt="验证码图片" title="验证码图片" src="<%=path %>/validationCodeServlet.png" onclick="refreshCode(this)" />  
<a id="aRecode" href="javascript:void(0);" onclick="refreshCode()">换一张</a>  

 

JS重新载入图片方法(参考):

复制代码
/** 
 * 刷新验证码 
 * @param imgObj 验证码Img元素 
 */  
function refreshCode(imgObj) {  
    if (!imgObj) {  
        imgObj = document.getElementById("validationCode");  
    }  
    var index = imgObj.src.indexOf("?");  
    if(index != -1) {  
        var url = imgObj.src.substring(0,index + 1);  
        imgObj.src = url + Math.random();  
    } else {  
        imgObj.src = imgObj.src + "?" + Math.random();  
    }  
}  
复制代码

 

数组增删 集合删除

 

一、数组增删

复制代码
package com.test;
import java.util.List;  
import java.util.ArrayList;  
import java.util.Set;  
import java.util.HashSet;  


public class ArrayBlock {  
  
    /* 去掉数组中重复的值 */ 
    public static void testA() {  
        String [] str = {"cat", "dog", "pig", "dog",};  
    // 先把数组转为集合
        List<String> list = new ArrayList<String>();  
        for (int i=0; i<str.length; i++) {  
            if(!list.contains(str[i])) {  
                list.add(str[i]);  
            }  
        }  
       
      /*  toArray(T[] a)用法
       * 因为list集合默认是object类型,那传入new String[2],首先有泛型作用 
       * 如果list长度大于2,那new String[2]只有泛型作用,如果长度等于2
       * 那就用new String[2]这个数组,如果小于2, 那数组多余部分为null
      */
        String[] newStr =  list.toArray(new String[1]);  
    }  
  
    //删除数组中其中一个元素  
    public static void testB() {  
         String [] str = {"cat", "dog", "pig", "dog",};   
      
        //删除pig  
        List<String> list = new ArrayList<String>();  
        for (int i=0; i<str.length; i++) {  
            list.add(str[i]);  
        }
        //list移除记得放外面  
        list.remove(2); 
        //返回一个包含所有对象的指定类型的数组 
        String[] newStr =  list.toArray(new String[1]);   
     
    }  
  
    //在数组中增加一个元素  
    public static void testC() {  
         String [] str = {"cat", "dog", "pig", "dog",}; 
      
        //增加pee  
        List<String> list = new ArrayList<String>();  
        for (int i=0; i<str.length; i++) {  
            list.add(str[i]);  
        }  
       // list.add()默认在集合最后插入数据,而 add(2, "pee")就指定在索引第二个位置插入     
        list.add(2, "pee"); 
        String[] newStr =  list.toArray(new String[1]); 
    }  
} 
复制代码

 

二、集合删除数据

复制代码
package com.test;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;

public class ListBlock {
    
    public void deliect() {
        List<String> list = new ArrayList<String>();
        list.add("a");
        list.add("b");
        list.add("c");

        //方法一: 用for增强方法删除
        for (String str : list) {
            if (str.equals("a"))
            
            /* 在使用增强for循环的过程不能对元素进行删除、修改、增加的操作等操作。 
             * 但是,如果操作一下,立刻break跳出,也是不会报错的!
             */        
                list.remove(str);
        }
        
        //方法二:使用传统for循环遍历
         for (int i = 0; i < list.size(); i++) {
                String str = list.get(i);
                if (str.equals("a")) {
             /* 不会报错,但会少都一条信息, 因为执行删除操作;删除完成,则集合后边的元素会自动前移,
              * 导致下次遍历漏掉一个元素,所以少删后面那个元素。
              * 解决方法:在remove();方法下写上 --i;
              */
                 list.remove(i);
                }
            }
         
        //方法三:使用api提供的方法list.iterator(),这个方法不会出现问题
         Iterator<String> iterator = list.iterator();
            while (iterator.hasNext()) {
                String str = iterator.next();
                if (str.equals("a")) {
                    iterator.remove();
                }
            }
    }
}
复制代码

 

三、map集合删除数据

复制代码
package com.test;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

public class ListBlock {

    public static void main(String[] args) {
        HashMap<String, String> map = new HashMap<String, String>();
        map.put("1", "one");
        map.put("2", "two");
        map.put("3", "three");
        map.put("4", "four");

        // 删除元素
        Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<String, String> entry = it.next();
            String key = entry.getKey();
            int k = Integer.parseInt(key);
            if (k % 2 == 1) {
                
                /*iterator的remove()方法,也有需要我们注意的地方:
                 * 每调用一次iterator.next()方法,只能调用一次remove()方法。
                 * 调用remove()方法前,必须调用过一次next()方法。
                 */
                it.remove();
            }
        }
    }
}
复制代码

 

 大家看下哪里不对,或者需要补充的,欢迎指点。

 

 map集合排序

 这篇文章讲的不仅仅是map排序,比如把对象按某一属性排序,它都可以解决这些问题。         

比如,有N个对象,每个对象有个属性就是成绩,成绩分:优秀,良好,合格。那我们如何按照成绩的好坏进行排序呢,下面请看代码。

1.people对象

复制代码
package com.test;

/*people对象其实很简单,就提供了三个属性*/

class People {
    
    private String Name;   //姓名
    private String Score;  //成绩
    private String id;     //学号

    public String getName() {
        return Name;
    }

    public void setName(String name) {
        Name = name;
    }

    public String getScore() {
        return Score;
    }

    public void setScore(String score) {
        Score = score;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public People(String name, String score, String id) {
        super();
        Name = name;
        Score = score;
        this.id = id;
    }
}
复制代码

 

2.主要方法

复制代码
package com.test;

import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;

 
   /**
    * Map进行多条件排序输出
    * 成绩具有优秀,合格,不合格好吃属性。
    * 入口Map
    * 首先按照优秀,合格,不合格排序
    * 然后按照人名的标志Id排序
    * 出口Map
    * 
    * 
    */
 public class MainSort {
 
     /**
      * 准备参数,创建对象
      * @return
      */
     private static Map<String, People> getPeopleMap() {
         Map<String,People> PeopleMap = new TreeMap<>();
 
         // 创建对象
         People b = new People("小明"  , "优秀",  "b");
         People a = new People("小红"  , "合格",  "a");
         People c = new People("丁丁"  , "合格",  "c");
         People d = new People("冬冬"  , "良好",  "d");
         People e = new People("小黄"  , "优秀",  "e");
         People f = new People("小李"  , "良好",  "f");
         People g = new People("小钟"  , "优秀",  "g");

 
         // 添加乱序key值,把对象放入map集合
         PeopleMap.put("xniem", b);
         PeopleMap.put("akjd", a);
         PeopleMap.put("uioo", c);
         PeopleMap.put("qw84", d);
         PeopleMap.put("584sdf'", e);
         PeopleMap.put("4aisdf", f);
         PeopleMap.put("458jsf", g);
  
         return PeopleMap;
     }
 
     /**
      * 循环打印Map
      */
     private static void show(Map<String, People> PeopleMap) {
         // 循环Map 这个打印肯定是无序的,也不是按放入的先后顺序
         for (Map.Entry<String, People> PeopleOneMap : PeopleMap.entrySet()) {
             People People = PeopleOneMap.getValue();
            System.out.println(People.getName() + " " + People.getScore()+ " " + People.getId() );
         }
     }
        
       /*
        * 由于List能够直接使用Collections进行排序
        * 但是Map不行。
        * 这边所做的操作就是先将Map--》List
        * 然后对List进行排序
        * 然后在讲List--》转换成LinkedHashMap
        * 
        */
     public static Map<String, People> sortMapByValue(Map<String, People> PeopleMap) {
         if (PeopleMap == null || PeopleMap.isEmpty()) {
             return null;
         }
         // LinkedHashMap是有序的、或者TreeMap都是有序的(这里只能用LinkedHashMap)
         Map<String, People> sortedMap = new LinkedHashMap<String, People>();
       
          /* Set set=PeopleMap.entrySet();  PeopleMap.entrySet()返回的是一个set集合
           * 再讲ArrayList(Collection<? extends E> c) 可以放collection,set集合是其子类,map不行哦
           * 这步就是把map集合转为ArrayList集合 
           */ 
          
         List<Map.Entry<String, People>> entryList = new ArrayList<Map.Entry<String, People>>(PeopleMap.entrySet());
         
        //这步是关键,进过这步之后,entryList已经是个有序的ArrayList集合了
         Collections.sort(entryList, new MapValueComparator());    
         //通过迭代器取出
         Iterator<Map.Entry<String, People>> iter = entryList.iterator();
         // Map.Entry<String, People>,就是包装了一个map节点,这个节点封装了key,value值,以及别的值(比如hashmap中哈希码和next指针)
         Map.Entry<String, People> tmpEntry = null;
         while (iter.hasNext()) {
             tmpEntry = iter.next();
             sortedMap.put(tmpEntry.getKey(), tmpEntry.getValue());
        }
         return sortedMap;
     }
     
     /**
      * 主方法
      * 
      */
     public static void main(String[] args) {
         // 获取Map
         Map<String,People> PeopleMap = getPeopleMap();
         // 打印未排序的Map
         show(PeopleMap);
         System.out.println("-----------before-----------");
         // 打印排序完了的Map
         show(MainSort.sortMapByValue(PeopleMap));
         System.out.println("-----------after------------");
     }
 }
复制代码

 

 

3.Comparator方法

复制代码
package com.test;

import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

class MapValueComparator implements Comparator<Map.Entry<String, People>> {
 
     @Override
     public int compare(Entry<String, People> o1, Entry<String, People> o2) {
     
         // 获取比较的两个对象
         People People1 = o1.getValue();
         People People2 = o2.getValue();
         
         // 将成绩映射成具有比较关系的字符1、2、3
         Map<String,Integer> tasteLev = new HashMap<>();
         tasteLev.put("优秀", 1);
         tasteLev.put("良好", 2);
         tasteLev.put("合格", 3);   
       
         
         int cr = 0;
         // 判断成绩
         int a = tasteLev.get(People2.getScore())-tasteLev.get(People1.getScore());
         if (a!=0) {
             cr = (a>0) ? -1 : 2;
         } else {  
             
            /*其实上面就可以按成绩优秀,良好,合格排序了,
             *在做一步目的,就是在成绩相同的情况下,在按照学号进行排序 
             */
             
             // 按照对应的Id排序
             a = People2.getId().compareTo(People1.getId());
             if (a!=0) {
                 cr = (a>0)? -2 : 1;
             }
         }
         /* 注意上面对一个返回值对应的就是形成比较层次
          * 上层
          * --> 2
          * --> -1
          *     下层
          *    --> 1
          *      --> -2
          */
         return cr;
     }
 }
复制代码

   最后我们再来看后台输出

Serializable--初解

一 序列化是干什么的?

          我们知道,在jvm中引用数据类型存在于栈中,而new创建出的对象存在于堆中。如果电脑断电那么存在于内存中的对象就会丢失。那么有没有方法将对象保存到磁盘(对象持久化存储)或通过网络传输到远处的其他地方呢?

         答案是可以,但是我们必须要求所有支持持久化存储的类实现Serializable接口。Serializable就像个通行证,只有持有这个通行证,jvm才让类创建的对象进行持久化。这个接口将类与一个称为serialVersionUID的变量关联起来,这个serialVersionUID就是在反序列化中用来确定由哪个类来加载这个对象。

二、什么情况下需要序列化   
    a)当你想把的内存中的对象状态保存到一个文件中或者数据库中时候;
    b)当你想用套接字在网络上传送对象的时候;
    c)当你想通过RMI传输对象的时候;

三、JavaBean为什么要实现java.io.Serializable接口实现序列化?

        找了个比较好理解的例子:客户端访问了某个能开启会话功能的资源, web服务器就会创建一个与该客户端对应的HttpSession对象,每个HttpSession对象都要站用一定的内存空间。如果在某一时间段内访问站点的用户很多,web服务器内存中就会积累大量的HttpSession对象,消耗大量的服务器内存,即使用户已经离开或者关闭了浏览器,web服务器仍要保留与之对应的HttpSession对象,在他们超时之前,一直占用web服务器内存资源。

       web服务器通常将那些暂时不活动但未超时的HttpSession对象转移到文件系统或数据库中保存,服务器要使用他们时再将他们从文件系统或数据库中装载入内存,这种技术称为Session的持久化。

      将HttpSession对象保存到文件系统或数据库中,需要采用序列化的方式将HttpSession对象中的每个属性对象保存到文件系统或数据库中;将HttpSession对象从文件系统或数据库中装载如内存时,需要采用反序列化的方式,恢复HttpSession对象中的每个属性对象。所以存储在HttpSession对象中的每个属性对象必须实现Serializable接口。当然如果不是存储在session中的JavaBean可以不用存储哈。

举个简单例子:

     Student

复制代码
import java.io.Serializable;  
public class Student implements Serializable {  
    /*serialVersionUID来决定由哪个类来加载存在于文件中的对象 
     * 如果指定serialVersionUID的数值,那就能使得其不再与类的成员变量相关联 
     * 不然你已经把对象保存到数据库,这个时候你再给这个对象新增属性,那么反序列化 
     * 就会报:本地类不匹配的错误,但如果指定serialVersionUID值那就不会报错。 
     */   
     private static final long serialVersionUID = -5182532647273106745L;   
      
     //成员变量写成static的话是不能被持久化的    
    public static  String countryName="china";  
        private String name;    
        private int age;    
        //如果想对非静态的数据也不想序列化,则需要加入关键字    
       transient String sex;   
       /* 提供set和get方法,无参和有参方法*/   
}  
复制代码

   测试类

复制代码
 1 import java.io.*;  
 2 public class SerializableTest {   
 3     public static void main(String[] args) {    
 4             writeObj();    
 5             readObj();    
 6         }    
 7         public static  void writeObj()    
 8         {    
 9             Student student=new Student("小筱", 1, "女");       
10             try {    
11                 ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("d:\\student.txt"));    
12                 oos.writeObject(student);    
13                 oos.close();    
14             } catch (IOException e) {    
15                 e.printStackTrace();    
16             }    
17         }    
18         public  static  void  readObj()    
19         {    
20             try {    
21                 ObjectInputStream ooi=new ObjectInputStream(new FileInputStream("d:\\student.txt"));    
22                 try {    
23                     Object obj=ooi.readObject();    
24                     Student student=(Student)obj;     
25                     System.out.println("age:"+student.getAge()+",name:"+student.getName()+",countryName:"+student.countryName+",sex:"+student.getSex());    
26                 } catch (ClassNotFoundException e) {    
27                     e.printStackTrace();    
28                 }    
29                 ooi.close();    
30             } catch (IOException e) {    
31                 e.printStackTrace();    
32             }    
33         }    
34 }  
复制代码

第二个小例子我没有亲自测试:用套接字在网络上传送对象

 1.首先建立要传输的对象 

复制代码
 1 //建立用来持续化的对象    
 2 import java.io.Serializable;    
 3 public class ObjectSeri implements Serializable{    
 4         
 5     //成员变量写成static的话是不能被持久化的    
 6     //private关键字是不能被持久化的,脱离了JVM,成员变量是不在JVM的安全机制之内    
 7     private String name;    
 8     private String age;    
 9     /*set和get方法*/ <span style="color:#333333;"><strong>   
10   </strong></span>  
复制代码

 2.有了传输的对象,下一步就是建立一个服务端线程来监听socket端口,并且在run方法里面实现读取对象的数据

复制代码
 1 import java.io.IOException;    
 2     import java.io.ObjectInputStream;    
 3     import java.net.ServerSocket;    
 4     import java.net.Socket;      
 5 //serverTest类继承thread类,监听端口来的信息    
 6 public class serverTest extends Thread {    
 7 //  private final String serverIP = "127.0.0.1";    
 8     private final int serverPort = 3400;    
 9     private ServerSocket server;    
10     public serverTest() {    
11         try {    
12             // ServerSocket server=new ServerSocket(serverPort);    
13             server = new ServerSocket(serverPort);    
14             System.out.println("正在监听3400端口");    
15         } catch (IOException e) {    
16             e.printStackTrace();    
17         }    
18     }    
19     public void run() {    
20         Socket socket = null;    
21         ObjectInputStream in;    
22         while (true) {    
23             try {    
24                 synchronized (server) {    
25                     socket = server.accept();    
26                 }    
27                 System.out.println("当前的连接是:"    
28                         + socket.getInetAddress().toString());    
29                 socket.setSoTimeout(20000);    
30                 in = new ObjectInputStream(socket.getInputStream());    
31                 ObjectSeri data = (ObjectSeri) in.readObject();    
32                 System.out.println("The name is:" + data.getName()    
33                         + "and age is:" + data.getAge());    
34                 in.close();    
35                 in = null;    
36                 socket.close();    
37             } catch (IOException | ClassNotFoundException e) {    
38                 e.printStackTrace();    
39             }    
40         }    
41     }      
42      public static void main(String args[]) {    
43           (new serverTest()).start();    
44          }    
复制代码

3.最后,建立一个客户端来测试下

复制代码
 1 import java.io.ObjectOutputStream;    
 2     import java.net.InetSocketAddress;    
 3     import java.net.Socket;     
 4 //建立一个client测试类    
 5 public class TestClient {    
 6     private String address = "127.0.0.1";    
 7     private int port = 3400;    
 8     
 9     public TestClient() {    
10         // Prepare the data need to transmit    
11         ObjectSeri data = new ObjectSeri();    
12         data.setName("Scott");    
13         data.setAge("34");    
14         Socket client = new Socket();    
15         InetSocketAddress adr = new InetSocketAddress(this.address, this.port);    
16         try {    
17             client.connect(adr, 10000);    
18             ObjectOutputStream out = new ObjectOutputStream(    
19                     client.getOutputStream());    
20             // send object    
21             out.writeObject(data);    
22             out.flush();    
23             out.close();    
24             out = null;    
25             data = null;    
26             client.close();    
27             client = null;    
28         } catch (java.io.IOException e) {    
29     
30             System.out.println("IOException :" + e.toString());    
31         }    
32     }    
33     public static void main(String[] args) {    
34         new TestClient();     
35     }      
36 } <span style="color: rgb(51, 51, 51);"> </span>  
复制代码

 输出结果如下:

正在监听3400端口
当前的连接是:/127.0.0.1
The name is:Scottand age is:34

 

今天:2017:12:05 发现自己用到了,就是jquery表单提交,用post提交,这样有个最大的好处,就是我不用一个值一个值提交,而是把表单提交过去      

$.post('your url', $("form").serialize(), function(data) {  
        // your code  
    }  
});  

 

    小筱的窝:水滴石穿,成功的速度一定要超过父母老去的速度

 

posted @ 2022-02-25 16:25  hanease  阅读(68)  评论(0编辑  收藏  举报