【慕课记录】Java实操避坑指南 -- 代码规范(二)

3-1、2、3
使用BigDecimal出现精读和除法除不尽问题

package com.imooc.java.escape;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * <h1>数值计算和时间计算</h1>
 * */
@SuppressWarnings("all")
public class NumberAndTime {

    /**
     * <h2>scale 需要与小数位匹配</h2>
     * */
    private static void scaleProblem() {

        BigDecimal decimal = new BigDecimal("12.222");
//        BigDecimal result = decimal.setScale(12);
//        System.out.println(result);

        BigDecimal result = decimal.setScale(2, BigDecimal.ROUND_HALF_UP);
        System.out.println(result);
    }

    /**
     * <h2>BigDecimal 做除法时出现除不尽的情况</h2>
     * */
    private static void divideProblem() {

//        System.out.println(new BigDecimal(30).divide(new BigDecimal(7)));
        System.out.println(
                new BigDecimal(30).divide(new BigDecimal(7), 2,
                        BigDecimal.ROUND_HALF_UP)
        );
    }

    /**
     * <h2>精度问题导致比较结果和预期的不一致</h2>
     * */
    private static void equalProblem() {

        BigDecimal bd1 = new BigDecimal("0");
        BigDecimal bd2 = new BigDecimal("0.0");

        System.out.println(bd1.equals(bd2));
        System.out.println(bd1.compareTo(bd2) == 0);
    }

    /**
     * <h2>SimpleDateFormat 可以解析大于/等于它定义的时间精度</h2>
     * */
    private static void formatPrecision() throws Exception {

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        String time_x = "2020-03-01 10:00:00";
        String time = "2020-03";

        System.out.println(sdf.parse(time_x));
        System.out.println(sdf.parse(time));
    }

    /**
     * <h2>SimplleDateFormat 存在线程安全问题</h2>
     * */
    private static void threadSafety() {

        SimpleDateFormat sdf = new SimpleDateFormat(
                "yyyy-MM-dd HH:mm:ss");

        ThreadPoolExecutor threadPoolExecutor =
                new ThreadPoolExecutor(
                10, 100, 1, TimeUnit.MINUTES,
                new LinkedBlockingDeque<>(1000)
        );

        while (true) {

            threadPoolExecutor.execute(() -> {
                String dateString = "2020-03-01 10:00:00";
                try {
                    Date parseDate = sdf.parse(dateString);
                    String dateString2 = sdf.format(parseDate);
                    System.out.println(dateString.equals(dateString2));
                } catch (ParseException ex) {
                    ex.printStackTrace();
                }
            });

        }
    }

    public static void main(String[] args) throws Exception {

//        scaleProblem();
//        divideProblem();
//        equalProblem();

//        formatPrecision();
        threadSafety();
    }
}

3-4、5
增强for循环的使用
3-6
判定等于的逻辑需要重写equals和hashcode

package com.imooc.java.escape;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * <h1>如果不好好判等, 集合存储就会乱套</h1>
 * */
public class EqualOrElse {

    public static class User implements Comparable<User> {

        private String name;
        private Integer age;

        public User() {}

        public User(String name, Integer age) {
            this.name = name;
            this.age = age;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Integer getAge() {
            return age;
        }

        public void setAge(Integer age) {
            this.age = age;
        }

        @Override
        public boolean equals(Object obj) {

            if (obj instanceof User) {
                User user = (User) obj;
                return this.name.equals(user.name) && this.age == user.age;
            }

            return false;
        }

        @Override
        public int hashCode() {

            int result = name.hashCode();
            result = 31 * result + age;

            return result;
        }

        @Override
        public int compareTo(User o) {
            return (this.age - o.age) + this.name.compareTo(o.name);
        }
    }

    /**
     * <h2>实现/不实现 equals 方法和 hashcode 对于判等的影响</h2>
     * */
    private static void equalsAndHashcode() {

        User user1 = new User("qinyi", 19);
        User user2 = new User("qinyi", 19);

//        System.out.println(user1.equals(user2));

        Set<User> userSet = new HashSet<>();
        userSet.add(user1);
        userSet.add(user2);

        Map<User, Integer> userIntegerMap = new HashMap<>();
        userIntegerMap.put(user1, 0);
        userIntegerMap.put(user2, 0);

        System.out.println(userSet.size());
        System.out.println(userIntegerMap.size());
    }

    /**
     * <h2>集合元素索引与 equals 方法相关</h2>
     * */
    private static void compareToAndEquals() {

        List<User> users = new ArrayList<>();
        users.add(new User("qinyi", 10));
        users.add(new User("qinyi", 20));

        User user = new User("qinyi", 20);

        int index1 = users.indexOf(user);
        int index2 = Collections.binarySearch(users, user);

        System.out.println(index1);
        System.out.println(index2);
    }

    public static void main(String[] args) {

//        equalsAndHashcode();
        compareToAndEquals();
    }
}

在这里插入图片描述
indexOf() 找到元素对应的索引;

compareTo和equals都要实现逻辑上的判等,需同步

3-7
在这里插入图片描述
1、单字母驼峰 lombok 会解析为全小写
需要极力避免
在这里插入图片描述
2、@Data 注解在子类默认不比较父类里的属性,导致equals会不符合预期
注意:
如果父类没有@Data 则没有重写 equals 方法(比如父类只用了 @Getter和@Setter),会导致继承的子类出现两种情况
1、@EqualsAndHashCode(callSuper = false) 时,也是默认不写,两个 “形态上” 相等的数据,会被认为相等,应为不会比较父类,父类没重写也没关系
2、@EqualsAndHashCode(callSuper = true) 时,代表会比较父类,因为父类没重写,会导致认为不相等,很有可能违背业务初衷(一般业务里,从数据库读到两条完全相等的数据会被认为需要去重,使用流的distinct在这里会失效。)
结论:父类应打上@Data注解。
在这里插入图片描述
在这里插入图片描述

3-8:避免抽象类和接口选择失误
在这里插入图片描述
共同有状态的属性 用 抽象类:起床、上下班
特有的独立的属性用 接口:程序员,部分程序员

在这里插入图片描述
不能new 抽象类和接口,此是语法错误

3-9:java8新增的 默认方法和静态方法
在这里插入图片描述
默认方法是为了配合jdk函数是接口实现的更有拓展性

3-10:lambda表达式
在这里插入图片描述
在这里插入图片描述
看方法的返回值:返回stream的大多是 中间操作

package com.imooc.java.escape.function_interface_lambda;

import java.util.HashMap;
import java.util.Map;

/**
 * <h1>函数式接口的使用</h1>
 * */
@SuppressWarnings("all")
public class Main {

    private static final Map<Long, Worker> id2WorkerMap = new HashMap<>();

    static {
        id2WorkerMap.put(1L, new Worker(1L, "qinyi", 19));
    }

    public static void main(String[] args) {

//        IFindWorker findWorker = id -> id2WorkerMap.get(id);

        IFindWorker findWorker = id2WorkerMap::get;

        System.out.println(findWorker.findWorkerById(1L));
    }
}

package com.imooc.java.escape.function_interface_lambda;

import java.util.HashMap;
import java.util.Map;

/**
 * <h1>函数式接口的使用</h1>
 * */
@SuppressWarnings("all")
public class Main {

    private static final Map<Long, Worker> id2WorkerMap = new HashMap<>();

    static {
        id2WorkerMap.put(1L, new Worker(1L, "qinyi", 19));
    }

    public static void main(String[] args) {

//        IFindWorker findWorker = id -> id2WorkerMap.get(id);

        IFindWorker findWorker = id2WorkerMap::get;

        System.out.println(findWorker.findWorkerById(1L));
    }
}

package com.imooc.java.escape.function_interface_lambda;

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <h1>Lambda 表达式的使用</h1>
 * */
public class StudyLambda {

    /**
     * <h2>Java 1.8 之前创建线程</h2>
     * */
    private static void baseUse() {

        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Anonymous Class Thread run()");
            }
        }).start();
    }

    /**
     * <h2>Java8 创建线程</h2>
     * */
    private static void easyUseLambda() {

        new Thread(() -> System.out.println("Anonymous Class Thread run()")).start();
    }

    /**
     * <h2>按照字符串长度进行排序</h2>
     * */
    private static void myCompare() {

        // java8 之前
        List<String> list = Arrays.asList("z", "y", "x", "a");
        Collections.sort(list, new Comparator<String>() {
            @Override
            public int compare(String s1, String s2) {

                if (s1 == null)
                    return -1;
                if (s2 == null)
                    return 1;
                return s1.length() - s2.length();
            }
        });

        // java8 使用 lambda 表达式去实现
        Collections.sort(list, (s1, s2) -> {
            if (s1 == null)
                return -1;
            if (s2 == null)
                return 1;
            return s1.length() - s2.length();
        });
    }

    /**
     * <h2>要理解 stream 的中间操作和结束操作</h2>
     * */
    private static void howToUseLambda() {

        List<String> names = Arrays.asList("qinyi", "imooc");

        List<String> newNames =
                names.stream().filter(n -> n.startsWith("q"))
                .map(n -> n.toUpperCase())
                .collect(Collectors.toList());
        System.out.println(newNames);
    }

    /**
     * <h2>Stream 和 lambda 可能导致计算低效</h2>
     * */
    private static void badUseLambda() {

        List<String> names = Arrays.asList("qinyi", "imooc");

        int longestNameSize =
                names.stream()
                .filter(s -> s.startsWith("q"))
                .mapToInt(String::length)
                .max()
                .getAsInt();

        int longest = 0;
        for (String str : names) {
            if (str.startsWith("q")) {
                int len = str.length();
                longest = Math.max(len, longest);
            }
        }

        System.out.println(longest);
    }
}

package com.imooc.java.escape.function_interface_lambda;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * <h1>Java Object</h1>
 * */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Worker {

    private Long id;
    private String name;
    private Integer age;
}

自定义的带参数带返回值的函数式接口

package com.imooc.java.escape.function_interface_lambda;

import java.util.HashMap;
import java.util.Map;

/**
 * <h1>函数式接口的使用</h1>
 * */
@SuppressWarnings("all")
public class Main {

    private static final Map<Long, Worker> id2WorkerMap = new HashMap<>();

    static {
        id2WorkerMap.put(1L, new Worker(1L, "qinyi", 19));
        id2WorkerMap.put(2L, new Worker(2L, "qi222nyi", 19));
    }

    // 使用自定义的函数式接口作为方法参数
    private static Worker doSomething(IFindWorker inter, Long id) {
        return inter.findWorkerById(id); // 调用自定义的函数式接口方法
    }

    public static void main(String[] args) {

//        IFindWorker findWorker = id -> id2WorkerMap.get(id);

//        IFindWorker findWorker = id2WorkerMap::get;

        System.out.println("worker = " + doSomething(
                (id) -> id2WorkerMap.get(id),2L
        ));

//        System.out.println(findWorker.findWorkerById(1L));
    }
}

在这里插入图片描述
接口定义
在这里插入图片描述
==4-1、2:序列化相关 ==
在这里插入图片描述
在这里插入图片描述
1、当父类没序列化时,如果父类没有提供无参构造函数则报错;如果提供,则可以
在这里插入图片描述
2、引用对象和自身都必须实现序列化才行
在这里插入图片描述
3、会影响。java序列化算法 不会重复多次序列化
4-3:泛型
在这里插入图片描述
类型擦除
java的泛型是伪泛型

在字节码会被擦除
在这里插入图片描述
通过反射 在运行时 将不是 int型的数据插入到 list
在这里插入图片描述
在这里插入图片描述

package com.imooc.java.escape;

import java.util.ArrayList;
import java.util.List;

/**
 * <h1>理解泛型</h1>
 * */
@SuppressWarnings("all")
public class Genericity {

    /**
     * <h2>简单使用泛型</h2>
     * */
    private static void easyUse() throws Exception {

        List<String> left = new ArrayList<>();
        List<Integer> right = new ArrayList<>();

//        System.out.println(left.getClass());
//        System.out.println(left.getClass() == right.getClass());

//        if (left instanceof ArrayList<Double>) {}
//        if (left instanceof ArrayList) {
//
//        }
//
//        if (left instanceof ArrayList<?>) {}

        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.getClass().getMethod("add", Object.class).invoke(list, "abcd");
        list.getClass().getMethod("add", Object.class).invoke(list, 1.2);

        for (int i = 0; i != list.size(); ++i) {
            System.out.println(list.get(i));
        }
    }

    /**
     * <h2>泛型是先检查再编译</h2>
     * */
    private static void checkAndCompile() {

        ArrayList<String> list = new ArrayList<>();
        list.add("1234");
//        list.add(123);
    }

    /**
     * <h2>泛型不支持继承</h2>
     * */
    private static void genericityCanNotExtend() {

        // 第一类错误
//        ArrayList<String> first = new ArrayList<Object>();
//
        ArrayList<Object> list1 = new ArrayList<>();
//        list1.add(new Object());
//        ArrayList<String> list2 = list1;

        // 第二类错误
//        ArrayList<Object> second = new ArrayList<String>();
//
//        ArrayList<String> list1 = new ArrayList<>();
//        list1.add(new String());
//        ArrayList<Object> list2 = list1;
    }

    /**
     * <h2>泛型类型变量不能是基本数据类型</h2>
     * */
    private static void baseTypeCanNotUseGenericity() {

//        List<int> invalid = new ArrayList<>();
    }

    /**
     * <h2>泛型的类型参数只能是类类型, 不能是简单类型</h2>
     * */
    private static <T> void doSomething(T... values) {
        for (T value : values) {
            System.out.println(value);
        }
    }

    public static void main(String[] args) throws Exception {

//        easyUse();

        Integer[] ints1 = new Integer[]{1, 2, 3};
        int[] ints2 = new int[]{1, 2, 3};

        doSomething(ints1);
        System.out.println("----------------");
        doSomething(ints2);
    }
}

在这里插入图片描述
且不要用 原始类型:比如 List list = new ArrayList<>();然后往里面丢任何类型的东西

4-6:反射
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1、数据类型需要一致

private static void reflectDeclaredMethod() throws Exception {

        Class<Boss> clz = Boss.class;
        Method[] methods = clz.getDeclaredMethods();

//        Method method = clz.getDeclaredMethod("numeric", int.class);
        Method method = clz.getDeclaredMethod("numeric", Integer.class);
        System.out.println(method.invoke(clz.newInstance(), 19));
    }
public class Boss extends Worker {

    public String boss(String hello) {
        return Boss.class.getName() + ": " + hello;
    }

    public String numeric(Integer age) {
        return Boss.class.getName() + ": " + age;
    }
}

4-8:StringBuilder
在这里插入图片描述
不要依赖于编译器的自动优化

在这里插入图片描述
加入了 synchronized 关键字 同步锁
在这里插入图片描述
4-9、10:深浅拷贝
友情链接
在这里插入图片描述
对引用对象是否发生了新地址的拷贝

在这里插入图片描述
1、类没有实现 Cloneable 接口会报错
object提供的方法即是浅拷贝
在这里插入图片描述
2、实现深拷贝的方法
简单的new后返回
使用native的clone改进
在这里插入图片描述
在这里插入图片描述
3、通过序列化的方式实现深拷贝

public Worker clone() {

        Worker worker = null;

        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(this);

            // 将流序列化成对象
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            worker = (Worker) ois.readObject();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }

        return worker;
    }

需要特别注意:
string 不是基本数据类型,但是在浅拷贝里,worker2不会改变worker1的值,原因是 string在set用法时是放进常量值,不是通过new出来的;

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值