java

java

  • java
    • 枚举类
    • 时间操作类
    • 正则表达式
    • IO
    • 范型
    • 异常
    • volatile内存模型
    • 多线程
    • 反射
    • classLoader
    • 动态代理
    • 注解 Annotation
    • 函数式编程和lambda表达式(1.8新功能)
    • AutoCloseable自动释放资源的必要条件(1.8新功能)
    • Optional类(1.8新功能)
    • 默认方法(1.8新功能)
    • JUnit单元测试
    • maven
    • jdbc

枚举类

  1. 如果枚举类中保护了方法则最后一个枚举值要用;

  2. 构造函数必须是私有的。

  3. 枚举中定义的抽象方法,必须每个都要实现。

    package learn;
    
    interface IColor{
        String getColor();
    }
    
    enum Color implements IColor{
        Red(1){
            public String getColor() {
                return "红色";
            }
        }, 
        Bule(2){
            public String getColor() {
                return "蓝色";
            }
        }, 
        Green(3){
            public String getColor() {
                return "绿色";
            }
        };
        private int index;
        private Color(int index) {
            this.index = index;
        }
        public int getIndex() {
            return index;
        }
    }
    
    public class MyEnumClass {
        public static void main(String[] arg) {
            for (Color c : Color.values()) {
                System.out.println(c.name() + "--->" + c.getColor() + "--->" + c.getIndex());
            }
        }
    }
    

时间操作类

  1. 各个时间相关操作类

    操作 1.8之前的版本 1.8新加的版本
    获取当前时间对象 Date dt = new Date() LocalDateTime dt = LocalDateTime.now()
    时间对象转毫秒 long ms = dt.getTime() Instant ins = Instant.now(); long ms = ins.toEpochMilli();
    毫秒转时间对象 Date dt = new Date(ms) Instant ins = Instant.ofEpochMilli(ms); LocalDateTime dt = LocalDateTime.ofInstant(ins, ZoneId.systemDefault();
    时间对象转字符串 DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String s = df.format(dt) DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); String s = df.format(dt);
    字符串转时间对象 SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date dt = df.parse(s); DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); LocalDateTime dt = LocalDateTime.parse(s, df);

正则表达式

  1. 常用的表达式

    表达式 说明 类别
    \t tab制表符 单个字符的匹配
    \n 空行 单个字符的匹配
    [abc] a,b,c中的一个 单个字符的匹配
    [^abc] 匹配不是a,b,c的字符 单个字符的匹配
    [a-zA-z] 匹配a到z和A到Z的字符 单个字符的匹配
    \d 0到9的任意一个数字 单个字符的匹配
    \D 匹配不是0到9的任意一个字符 单个字符的匹配
    \s 匹配任意一个空白字符 单个字符的匹配
    \S 匹配任意一个不是空白的字符 单个字符的匹配
    \w 匹配任意一个字符或数字或下划线,相当于[a-zA-Z_0-9] 单个字符的匹配
    \W 匹配任意一个不是字符或数字或下划线的字符,相当于[^\w] 单个字符的匹配
    ? 出现一次或零次 量词表达式
    + 出现至少一次 量词表达式
    * 出现任意次数 量词表达式
    {n} 出现n次 量词表达式
    {n, } 出现大于等于n次 量词表达式
    {n, m} 出现n到m次 量词表达式
    XY 两个表达式连接 逻辑表达式
    X Y 两个表达式中的任意一个 逻辑表达式
    (X) 表达式组 逻辑表达式
  2. 常用的表达式方法

    方法 说明
    String.matches(String regex) : boolean 是否匹配正则表达式
    String.replaceAll(String regex, String replacement) : String 替换所有匹配项
    String.replaceFirst(String regex, String replacement) : String 替换首个匹配项
    String.spilt(String reges) : String[] 分割
    java.util.regex包内的类(Pattern, Matcher) 提供分组功能
  3. 示例

    package main.base;
    
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    public class MyRegex {
        private static void checkEmail(String email) {
            String regex = "[a-zA-Z0-9]\\w*@[a-zA-Z0-9-_]+.(com|cn|com.cn|org)";
            System.out.println(email + " is email:" + email.matches(regex));
        }
        
        private static void checkPhone(String phone) {
            // 010123456 (010)-1234567 123456
            String regex = "(\\d{3,4}|\\(\\d{3,4}\\)-)?\\d{6,7}";
            System.out.println(phone + " is phone:" + phone.matches(regex));
        }
        
        private static void checkIp(String ip) {
            String regex = "\\d{1,3}.\\d{1,3}.\\d{1,3}.\\d{1,3}";
            System.out.println(ip + " is ip:" + ip.matches(regex));
        }
        
        private static void group(String msg) {
            System.out.println("-----------");
            String regex = "#\\{\\w+\\}";
            Pattern pattern = Pattern.compile(regex);
            Matcher match = pattern.matcher(msg);
            while(match.find()) {
                System.out.println(match.group(0).replaceAll("(#\\{|\\})", "") + "、");
            }
            System.out.println("-----------");
        }
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            checkEmail("[email protected]");
            checkEmail("liu_200@qq_c-d.com.cn");
            checkEmail("[email protected]");
            
            checkPhone("123456");
            checkPhone("0101123456");
            checkPhone("(0738)-1234567");
            checkPhone("123456789");
            checkPhone("010-123456");
            
            checkIp("1.1.1.1");
            checkIp("1.1.1");
            
            group("INSERT INTO TABLE(name, age) VALUES(#{name}, #{age})");
        }
    
    }
    
    

IO

  1. 如果不希望某个字段序列化,可以在声明时加入transient

    private transient int age;
    
  2. 字节流(InputStream,OutputStream)和字符流(Reader,Writer)的区别:

    1. java最早的时候只提供了字节流
    2. 字符流可以方便的进行中文处理,但字节流处理时需要进行字节的编码和解码
    3. 网络传输或数据保存的时候,操作的都是字节流
    4. 字符流操作需要缓冲区处理数据,字节流操作时没有使用缓冲区,字符流会在关闭时候默认清空缓冲区,如果操作时没有关闭,则用户可以使用flush方法手工清空缓冲区。
  3. 常用流

class 用途 子类
OutputStream 字节输出流 FileOutputStream
InputStream 字节输入流 FileInputStream
Writer 字符输出流 FileWriter
Reader 字符输入流 FileReader
InputStreamReader 字节输入流变为字符输入流,不建议使用,因为频繁地进行字符与字节间的相互转换
OutputStreamWriter 字节输出流变为字符输出流,不建议使用,因为频繁地进行字符与字节间的相互转换
BufferedWriter 字节输出流变为字符输出流,建议使用
BufferedReader 字节输入流变为字符输入流,建议使用
ByteArrayOutputStream 字节内存操作流
ByteArrayInputStream 字节内存操作流
CharArrayWriter 字符内存操作流
CharArrayReader 字符内存操作流
PrintStream 字节打印流,简化输出问题
PrintWriter 字符打印流
SequenceInputStream 合并流
ObjectInputStream 对象反序列化
ObjectOutputStream 对象序列化

文件流:

  • FileOutputStream: 程序 ----> 文件
  • FileInputStream: 程序 <---- 文件

内存操作流:

  • ByteArrayInputStream: 程序 ----> 内存
  • ByteArrayOutputStream: 程序 <---- 内存

范型

  1. 定义范型类时把类型参数放到类名称的后面,定义范型函数时需要把类型参数放到函数的返回值前面。
  2. 通配符
通配符 说明
类型未知,用来定义函数返回值或函数参数的
定义为T或T的子类,用来定义函数返回值或函数参数的
超类匹配,用来灵活写入,用来定义范型类型中类型参数的

异常

  1. Exception和RuntimeException的区别

    • Exception:强制程序必须处理的异常
    • RuntimeException:是Exception异常的子类,可以由用户决定是否进行异常处理
  2. throws标识的方法表示要处理的异常

  3. java1.7之后新增try-with-resources结构的异常处理,类似try....catch....finally结构,可以自动调用try语句中定义的实例化对象的close方法释放资源。

volatile内存模型

  1. volatile定义的是属性的,表示该变量不进行内存拷贝操作,而是直接进行变量的操作。把这个关键字用于同步是一种错误的使用,无法描述同步的处理,它只是一种直接内存处理,不进行副本的操作

  2. 内存模型:前提知识:cpu有L2缓冲,cpu直接从缓冲中读取变量

    • 读取一个变量时先从cpu缓冲中读取,如果命中则读取该值;如果没有命中则从主内存到加载到cpu缓冲中,进行变量副本的拷贝,读取该值
    • 变量赋值成功之后,更新cpu缓冲中的值,然后再把值刷新到主内存中

    volatile关键字修饰的变量,直接操作主内存,也就是不进行副本的拷贝

多线程

  1. 线程的创建方式有两种:

    • extend Thread
    • implements Runnable
    • implements Callable(可以获取线程的返回值,使用FutureTask)

    这两种方法的区别:

    • 继承Thread的方式下,线程类不能再继承其他父类,而使用Runable接口可以避免单继承带来的局限
    • Runnable可以多个线程共享相同资源
  2. Thread的start方法只能启动一次。

  3. join方法会阻塞当前方法,直到join的线程执行完毕

  4. wait、notify、notifyAll这3个方法只能在synchronized方法中调用。并且notify只能唤醒同一对象监视器中调用的wait线程。

  5. 结束现场的方法有suspend、resume、stop方法,但都不建议使用,因为suspend、resume可能会导致死锁发生,stop方法可能会导致共享的数据不完整。

  6. 内存模型:每个线程有自己的工作内存,读取变量的时候从主内存中读取到工作内存中,访问的是自己工作内存中的副本,最后在把工作内存中的副本刷新到主内存中。当一个变量声明为volatile时,线程在写入变量时会直接存到主内存中。但volatile并不保证操作的原子性。

  7. 延迟加载的建议

    // 第一种:基于volatile的解决方案
    public class Instance {
        private volatile static Instance instance;
        public static Instance getInstance(){
            if (instance == null){
                synchronized(SafeDoubleCheckedLocking.class){
                    if (instance == null){
                        instance = new Instance();
                    }
                }
            }
    
            return instance;
        }
    }
    
    // 第二种:基于类初始化的解决方案
    public class Instance{
        private static class InstanceHolder{
            public static Instance instance = new Instance();
        }
    
        public static Instance getInstance(){
            return InstanceHolder.instance;
        }
    }
    
  8. 线程池

    手动创建线程池的方法:
    public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, RejectedExecutionHandler handler)

    • corePoolSize:核心线程的数量(线程池维护的线程最少数量)
    • maximumPoolSize:线程的最大数量
    • keepAliveTime:线程所允许的空闲时间
    • unit:线程空闲时间单位
    • workQueue:缓冲队列,常用的是java.until.concurrent.ArrayBlockingQueue,其他还有:
      * LinkedBlockingQueue
      * SynchronousQueue
      * DelayedWorkQueue
    • handler:线程池对拒绝任务的处理策略:常用的值:
      * ThreadPoolExecutor.AbortPolicy:抛出异常
      * ThreadPoolExecutor.CallerRunPolicy:重试添加当前任务
      * ThreadPoolExecutor.DiscardOldestPolicy:抛弃旧的任务
      * ThreadPoolExecutor.DiscardPolicy:抛弃当前任务

    而是通过 ThreadPoolExecutor 的方式,这样 的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。 说明:Executors 返回的线程池对象的弊端如下: 1)FixedThreadPool 和 SingleThreadPool: 允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。 2)CachedThreadPool 和 ScheduledThreadPool: 允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。

  9. 线程池的工作机制:

    • 线程池数量小于corePoolSize时,即使有空闲线程也创建一个新的线程执行任务
    • 线程池的数量等于corePoolSize时,但workQueue还未满时,新加的任务放入缓冲队列
    • 线程池数量大于corePoolSize时,且workQueue满,并且线程数量小于maximumPoolSize时,创建一个新的线程处理任务
    • 线程池数量大于corePoolSize时,且workQueue满,并且线程数量等于maximumPoolSize时,按照handler策略进行任务拒绝处理
  10. 线程池(Executors)

    线程池类型(创建方法) 工作队列 适用场景 特点
    newCachedThreadPool SynchronousQueue 并发执行大量短期任务 最大线程数是Integer.MAX_VALUE
    newFixedThreadPool LinkedBlockingQueue 执行长期任务 固定数目的线程池;
    newScheduledThreadPool DelayedWorkQueue 周期性或延迟执行的任务 定时及周期的执行线程池
    newSingleThreadExecutor LinkedBlockingQueue 串行执行任务 corePoolSize和maximumPoolSize都为1
  11. 线程池的异常处理

    • 在Run方法中捕获异常
    • 利用submit执行任务,利用返回的Future对象的get方法获取异常
    • 重新ThreadPoolExcutor.afterExecute方法
    • 为工作线程设置UncaughtExceptionHandler(不推荐)
  12. ThreadLocal类:将多个线程共享变量关联到具体的线程,调用set方法保存变量,调用get方法读取变量,调用remove方法删除。如果不调用remvoe方法将可能导致oom。

反射

  1. 获取反射的三种方式

    • 通过实例化对象的getClass方法
    • 通过类的静态属性 类名.class
      通过类的名称 class.forName(类的全名)
  2. 对象的实例化:class对象的newInstance方法,会调用类的无参构造函数。

  3. Field,Method:在调用private字段的get/set方法时会抛出非法访问的异常(lllegalAccessException),这个时候应该先调用setAccessible(true)以关闭java的检查机制。

classLoader

classLoader.png
  1. 自定义classLoader的目的:可以让jvm加载不在CLASSPATH路径中的class文件。

  2. 自定义的classLoader会最后加载,因为jvm提供双亲加载模式。比如如果自定义了一个java.lang.String类,那这个类将不会加载。

动态代理

dynamicProxy.png
  1. 动态代理示例

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class MyDynamicProxy {
    
        public static void main(String[] args) {
            RealyNetMessage netMessage = new RealyNetMessage();
            IMessage message = (IMessage)Proxy.newProxyInstance(
                    RealyNetMessage.class.getClassLoader(),
                    RealyNetMessage.class.getInterfaces(),
                    new RealNetMessageProxy(netMessage));
            message.send("动态代理");
        }
    
    }
    
    interface IMessage{
        public void send(String msg);
    }
    
    class RealyNetMessage implements IMessage{
        @Override
        public void send(String msg) {
            System.out.println("发送消息:"+ msg);
        }
    }
    // InvocationHandler
    class RealNetMessageProxy implements InvocationHandler{
        IMessage target;
        
        public RealNetMessageProxy(IMessage target){
            this.target = target;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if ("send".equals(method.getName())) { // 代理send方法
                if (connect()) {
                    Object returnData = method.invoke(target, args);  // 注意:这里只能是目标对象
                    close();
                    return returnData;
                }
            }
            return null;
        }
        // 发送消息前链接
        private boolean connect() {
            System.out.println("发送消息前链接");
            return true;
        }
        // 发送完毕之后要释放资源
        private void close() {
            System.out.println("发送完毕之后要释放资源");
        }
    }
    

注解 Annotation

  1. 定义的时候使用@interface。定义属性的时候需要在变量名后加()。也可以在定义的时候使用default定义默认值,未定义默认值的在使用时需要指定值。

  2. 自定义的注解要添加@Retention(value=RetentionPolicy.RUNTIME)才能配合使用反射。

  3. @Target可以定义注解使用的范围

  4. 如果希望注解能被子类继承,则要使用@Inherited定义注解

  5. 使用@Documented和@Retention(value=RetentionPolicy.RUNTIME)定义的注解将出现在javadoc文档中

  6. 常用内置注解

    1. 作用在代码的注解是

      • @Override - 检查该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
      • @Deprecated - 标记过时方法。如果使用该方法,会报编译警告。
      • @SuppressWarnings - 指示编译器去忽略注解中声明的警告。
    2. 作用在其他注解的注解(或者说 元注解)是:

      • @Retention - 标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。
      • @Documented - 标记这些注解是否包含在用户文档中。
      • @Target - 标记这个注解应该是哪种 Java 成员。
      • @Inherited - 标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)
    3. 从 Java 7 开始,额外添加了 3 个注解:

      • @SafeVarargs - Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。
      • @FunctionalInterface - Java 8 开始支持,标识一个匿名函数或函数式接口。
      • @Repeatable - Java 8 开始支持,标识某注解可以在同一个声明上使用多次。
    @Retention(value=RetentionPolicy.RUNTIME)
    @interface LoginInfo{
        public String name() default "a";
        public String password();
    }
    

函数式编程和lambda表达式(1.8新功能)

  1. lambda表达式不是匿名内部类,是函数式接口。

  2. 函数式接口是接口中只能有一个抽象方法。

  3. 方法引用:只要方法的签名和函数式接口的定义相同,就可以直接引用该方法

    方法引用 表示代码
    静态方法 [类名]::[方法名]
    实例方法 [类名]::[方法名]
    构造方法 [类名]::new

AutoCloseable自动释放资源的必要条件(1.8新功能)

  1. 继承AutoCloseable接口

  2. 实例化该对象时需要使用try异常语句

    class NetMessage implements AutoCloseable{
        public void close() throws Exception{
            System.out.println("[auto close]------");
        }
        public void send(String msg) {
            System.out.println("发送消息:" + msg);
        }
    }
    
    public class MyAutoCloseable {
        public static void main(String[] args) {
            try(NetMessage nm = new NetMessage()){
                nm.send("test");
            }
            catch(Exception ex) {
                ex.printStackTrace();   
            }
        }
    }
    

Optional类(1.8新功能)

  1. Optional封装了null的处理

  2. 常用方法:

    操作 存数据 读数据 说明
    数据可能为空 Optional.ofNullable Optional.orElse
    数据不会为空 Optional.of Optional.get 如果存或读取的数据为空,则这两个方法都会抛异常

默认方法(1.8新功能)

JUnit单元测试

  1. 常用的注解

    注解 说明
    @Test 测试方法,方法不能有参数,不能用在static方法上
    @BeforeEach 每次调用@Test前执行,用来实例化变量
    @AfterEach 每次@Test执行之后调用,用来清理实例化变量
    @BeforeAll 启动@Test前执行一次,用来初始化静态变量
    @AfterAll @Test都执行完毕之后调用
    @Disabled 不执行该测试方法
    @EnableOnOs 在指定系统上运行
    @DisabledOnOs 不在指定系统上不运行
    @DisableOnJre 只在特定jre版本或以上运行
    @EnableIf 万能条件测试
    @ParameterizedTest 参数化测试,测试方法要有参数
  2. 参数化测试中指定参数值的方式有

    • @ValueSource
    • @CsvSource
    • @CsvFileSource
    • @MethodSource:允许定义一个同名的静态方法提供参数
  3. 异常测试

    Assertions.assertThrows(RuntimeException.class, ()->{
                myjunit.division(4, 0);
            });
    

maven

  1. 依赖关系

    scope 说明 示例
    compile 编译时需要用到该jar包(默认) commons-logging
    runtime 编译时不需要,但运行时需要用到 mysql
    test 编译Test时需要用到该jar包 junit
    provided 编译时需要用到,但运行时由JDK或某个服务器提供 servlet-api
  2. 添加阿里镜像:linux:sudo find / -name *settings.xml找到maven的配置文件(也可以在eclipse中调整设置)

    
        
            
                aliyun
                aliyun
                central
                
                http://maven.aliyun.com/nexus/content/groups/public/
            
        
    
    
  3. maven常用构建

    • mvn clean
    • mvn clean compile
    • mvn clean test
    • mvn clean package
  4. 在线搜索包名:

    • https://maven.aliyun.com/mvn/search
    • https://search.maven.org
  5. maven实例

    
        mysql
        mysql-connector-java
        5.1.47
        runtime
    
    

jdbc

  1. 一条sql语句执行多次时,可以使用批处理

  2. 使用PreparedStatement预防sql注入

  3. 数据库事物的四大特性(ACID):

    • Atomicity:原子性
    • Consistency:一致性
    • Isolation:隔离性
    • Durability:持久性
  4. 并发问题:

    • 脏读:读取另一个事物未提交的记录
    • 不可重复读取:对同一条记录两次读取不一致,因为另一个事物对该记录做了修改
    • 幻读:对同一张表的两次查询不一致,因为另一个事物插入了一条记录
  5. 事物隔离用来解决并发问题。数据库的隔离级别

    Isolation Level 脏读(Dirty Read) 不可重复读(Non Repeatable Read) 幻读(Phantom Read)
    Read Uncommitted(读未提交) Yes Yes Yes
    Read Committed(读取已提交的) - Yes Yes
    Repeatable Read(可重复读) - - Yes
    Serializable(串行化) - - -

    mysql默认事物隔离为:Repeatable Read

  6. jdbc设置隔离级别的方式:connection.setTransactionIsolation(int level),其中参数值有:(默认情况下没有必要设置)

    • Connection.TRANSACTION_READ_UNCOMMITTED
    • Connection.TRANSACTION_READ_COMMITTED
    • Connection.TRANSACTION_REPEATABLE_READ
    • Connection.TRANSACTION_SERIALIZABLE
  7. jdbc连接池:jdbc默认不提供数据库连接池,但提供了连接池的接口javax.sql.DataSource;第三方实现的连接池必须继承DataSource。

  8. mysql连接池

    • C3P0(推荐)
    • Apache Commons DBCP
    • BoneCP
    • Druid
    • HikariCP
  9. mysql代码示例

    // mysql连接
    void connect(){
        Class.forName("com.mysql.cj.jdbc.Driver").newInstance();  // mysql8.0及以上,以下为:com.mysql.jdbc.Driver
        Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test?user=root&password=Xcy123456");
    }
    
    // batch批处理
    void batch(){
        PreparedStatement pre = conn.preparedStatement("INSERT INTO coupons (user_id, type, expires) VALUES (?,?,?)");
        for(int i = 0; i < 5; ++i){
            pre.setString(1, "");
            pre.setInt(1, 0);
            pre.setString(1, "");
            pre.addBatch();
        }
        pre.executeBatch();  // 执行批处理
    }
    
    // Transaction 数据库事务PreparedStatement
    void transaction(){
        Connection conn = openConnection();
        try {
            // 关闭自动提交:
            conn.setAutoCommit(false);
            // 执行多条SQL语句:
            insert(); update(); delete();
            // 提交事务:
            conn.commit();
        } catch (SQLException e) {
            // 回滚事务:
            conn.rollback();
        } finally {
            conn.setAutoCommit(true);
            conn.close();
        }
    }
    

你可能感兴趣的:(java)