java开发报错记录

MyBatis查询无命中记录时返回的list的size为1,显示 All elements are null

大白话:sql查询时查询结果显示空,但是数据却显示1条(正常应该0条)
相关网址推荐1
相关网址推荐2
造成原因:
1.由于使用聚合函数造成。内/左/右连接也会**(更合理的说法:由于我们的sql查询的字段值值刚好都为 null ; 所以就导致该对象为 null ;)**
2.实体类的字段名以及字段的个数必须和数据库的字段名和字段个数一一对应(网上说法,意思字段名保持一致)。
3.仅仅是因为我们要查询的字段是空的,但是其他数据都不是空的,所以他把这个数据数据库并没有当作一条空数据来看,还是映射给了我们的对象,导致List的内部有一个空对象,因为list内部是可以支持null的,
解决方法:
方法1: 这个最快,如果数据都是空 使用后长度就是0了

//对接收的集合进行处理,去掉为null的数据,如下:
list.removeAll(Collections.singleton(null));

方法2: 不推荐

//缺陷:没办法解决一个list多个null的问题 
(!CollectionUtils.isEmpty(list)&& list.get(0)!=null)

//在使用复合函数并且返回list样式的时候,可使用如下方式判断
//这样无论是返回[null]还是返回[],都可以在这个判断中处理。
if(1 == list.size()&& null == list.get(0) || 0 == list.size()){
//list为空时
}else{
//list不为空时
}

方法3:
可以使用SQL的IFNULL函数做一下判断就好。


方法4:
可以使用java8的Stream流达到直接解决达到目的:

list.parallelStream().filter(Objects::nonNull).collect(Collectors.toList())

我的解决:
我的业务需求:查出为空必须赋值0
用sql源头上解决
在这里插入图片描述
用代码解决:
在这里插入图片描述

防患未然:
如何提前发现这个问题,建议每个sql去数据库执行,弄成查不到数的时候看显示的条数,如果为0正常集合判空拦截即可,如果不为0且都是空,那就多加一手判断,具体还是看业务需求。

Mybatis+Mysql无查询数据时List、Set、Map的返回值为null还是空集

UnsupportedOperationException报错

这个报错无外呼你本来是个数组 然后利用Arrays.asList 把这个数组转成数组
然后去add等其他操作,就会报这个错,因为此list并不具备任何 ArrayList的功能。
原因总结:
我们调用Arrays的asList()方法将数组转换成List时返回的是Arrays的静态内部类ArrayList,它自身并未重写add()方法,而其父类AbstractList实现的add()方法只会抛出UnsupportedOperationException,导致我们调用Arrays的静态内部类ArrayList的add()方法时,实际调用的是只会抛出UnsupportedOperationException的AbstractList的add()方法,这就是异常出现的原因了。
解决办法:
如果你真的必须将数组转换成List的话,那就自己写个转换方法吧,反正就得转成真的list

private static <E>  List<E> transferArrayToList(E[] array){
        List<E> transferedList = new ArrayList<>();
        Arrays.stream(array).forEach(arr -> transferedList.add(arr));
        return transferedList;
}


  	    List title1List = new ArrayList<>();
        Integer[] array ={1,2,3};
        List<Integer> list = Arrays.asList(array);
        for (Integer integer : list) {
            title1List.add(integer);
        }
        title1List.add(4);
        System.out.println(title1List);//[1, 2, 3, 4]


        List title1List = new ArrayList<>();
        Integer[] array ={1,2,3};
        List<Integer> list = Arrays.asList(array);
        Arrays.stream(array).forEach(arr -> title1List.add(arr));
        title1List.add(4);
        System.out.println(title1List);//[1, 2, 3, 4]
        
		// todo 推荐使用这个一步到位不用for循环
 		String[] strs={"a","b","c"};
        List<String> lists = new ArrayList<>(Arrays.asList(strs));
        System.out.println(lists.add("d"));
        System.out.println(lists);
        
		//通过集合工具类Collections.addAll()方法(最高效)
        //根据数组的长度创建一个长度相同的List,然后通过Collections.addAll()方法,
       // 将数组中的元素转为二进制,然后添加到List中,这是最高效的方法。
            String[] strs={"a","b","c"};
            ArrayList< String> arrayList = new ArrayList<String>(strs.length);
            Collections.addAll(arrayList, strs);
            arrayList.add("d");
            System.out.println(arrayList);
            
//Java8可通过stream流将3种基本类型、及String类型的数组转为List
List<Integer> intList= Arrays.stream(new int[] { 1, 2, 3, }).boxed().collect(Collectors.toList());
List<Long> longList= Arrays.stream(new long[] { 1, 2, 3 }).boxed().collect(Collectors.toList());
List<Double> doubleList= Arrays.stream(new double[] { 1, 2, 3 }).boxed().collect(Collectors.toList());

String[] arrays = {"tom", "jack", "kate"};
List<String> stringList= Stream.of(arrays).collect(Collectors.toList());

在这里插入图片描述

上面说的都太空了,下面我们去源码里看
asList方法是数组工具类 Arrays中的一个静态方法
Arrays.asList()方法的作用是将数组或一些元素转为集合;
asList方法返回值得到的集合并不是我们通常使用的List集合
不能使用其修改集合相关的方法,如果使用修改集合相关的方法add/remove/clear方法会抛出java.lang.UnsupportedOperationException的异常;
注:其get、set、contains()等方法可以正常使用
在这里插入图片描述
顺带再说下Arrays.asList(引用数据类型的数组);为什么放基本数据类型数组就会编译报错,原因是泛型所致。
在这里插入图片描述
在这里插入图片描述

关于java中的trim()没有去除数据库字段末尾空格

发现一个字符串数据后面有空格,代码使用了replaceAll(" ", “”),trim()方法都不能去除空格。 当时就Debug查看字符串每个字符的ASCII码值,然后发现后面空格的ASCII值竟然为160。
造成原因:
因为trim方法只能去除 普通的空格,也就是ASCII码中32的空格。而 的ASCII码是160(u00A0是16进制,它的10进制就是160)
解决办法:

telephone.replaceAll("\\u00A0","");

反正去空格的代码如下,搭配使用应该可以去掉

telephone.replaceAll("\\u00A0","");
telephone.replaceAll("\\s","");
telephone.replaceAll(" ","");
telephone.trim();
//当然了 如果能通过sql在源头上解决是更好的选择 这里我没有实践尝试 
//思路给出如下:(常规空格)
字符前的(左边)空格,用ltrim(string) 
字符后的(右边)空格,用rtrim(string) 
字符中的(任意位置)空格,用replace(string, ' ', ' ')

//当发现空格为不间断空格 &nbsp;就得用下面:
mysql中使用replace(replace(store_code,CHAR(194),''),CHAR(160),'')
mysql 去除特殊字符(制表符、换行符、回车)导致的空白:
update table set field = replace(replace(replace(field,char(9),''),char(10),''),char(13),'');
char(9):水平制表符 (tab键 或者 \t)
char(10):换行键 (\n)
char(13):回车键 (Enter键)

获取字符串的ASCII码:

char[] chars = content.toCharArray();
for (char c : chars) {
System.out.println(((int) c));
}

java的"\s+"什么意思?

String[] tt=addr.split("\\s+");
\\s ==\s 表示转义字符 ,\s表示匹配任意空格(包括空格,制表符,换页符)
\\s+中的'+'表示多次匹配

课外补充:

java正则表达式特殊字符转义:

/**
 * 使用replaceall查找字符替换为其它置顶字符
 * @author Administrator
 *
 */
public class Test {
	/*java正则表达式特殊字符转义
	点的转义:. ==> \\u002E
	美元符号的转义:$ ==> \\u0024
	乘方符号的转义:^ ==> \\u005E
	左大括号的转义:{ ==> \\u007B
	左方括号的转义:[ ==> \\u005B
	左圆括号的转义:( ==> \\u0028
	竖线的转义:| ==> \\u007C
	右圆括号的转义:) ==> \\u0029
	星号的转义:* ==> \\u002A
	加号的转义:+ ==> \\u002B
	问号的转义:? ==> \\u003F
	反斜杠的转义:\ ==> \\u005C*/
	public static void main(String[] args) {
		String str1 = "english*english中文#中文中文a*english中文*English中文Power!!";
		String substr = "", regex = "\\u002A";
		str1 = str1.replaceAll(regex, substr);    
		System.out.println(str1);
/* replaces each substring of this string that matches the given  regular expression with the given replacement */
	}
}

三种空格unicode(\u00A0,\u0020,\u3000)表示的区别
\u00A0实际上是一个不间断的空格字符

1.不间断空格\u00A0,主要用在office中,让一个单词在结尾处不会换行显示,快捷键ctrl+shift+space ;
2.半角空格(英文符号)\u0020,代码中常用的;
3.全角空格(中文符号)\u3000,中文文章中使用;

trim()是去掉首尾空格
2.str.replace(" ", ""); 去掉所有空格,包括首尾、中间
String str = " hell o ";
String str2 = str.replaceAll(" ", "");
System.out.println(str2);
3.或者replaceAll(" +",""); 去掉所有空格
4.str = .replaceAll("\s*", "");
可以替换大部分空白字符, 不限于空格
s 可以匹配空格、制表符、换页符等空白字符的其中任意一个
5.或者下面的代码也可以去掉所有空格,包括首尾、中间
public String remove(String resource,char ch)
{
StringBuffer buffer=new StringBuffer();
int position=0;
char currentChar;
while(position<resource.length())
{
currentChar=resource.charAt(position++);
if(currentChar!=ch) buffer.append(currentChar); } return buffer.toString();
}
以上

关于前后时间不一致问题

案例1:有这么个需求,页面流程我要记录你的一个申请时间跟一个审核时间,最后结果审核时间总是大于申请时间。经过一翻查阅,在sql中我保存时间的insert语句一个时间用的是 now(),一个用的是java的new Date()。也不知道怎么会犯这个浑。这里提醒大家前后时间统一就不会出现这种问题。推荐插入时接收new Date()参数进行保存。
按例2:你在代码中先 new Date() 然后写了一堆代码 然后再 new Date()
服务器性能好的话可能两次的时间是一样的,进而可能造成问题。

按例3:数据库里面的时间和实际时间差了 13 小时
这个是别人分享的一个按例,教你遇到问题该怎么分析,写的挺详细,大家可以参考借鉴。

以后可能碰到这么个问题记录一下:
我们分析一下出现问题的几种可能:
通过查询大料材料我总结如下
system_time_zone使用的时区问题、mysql版本问题、java数据库连接使用UTC(某个)时区

  1. 下面先看 show variables like "%time_zone%";的运行结果
    UTC、CST会有相关问题
select now();
show variables like "%time_zone%";
-- 查出结果如下
-- system_time_zone	(这个我目前是空,是UTC就有问题)UTC时区比中国慢8小时
-- 如果是 CST  则差13 个小时!如果处在冬令时还会相差 14 个小时!
-- time_zone	SYSTEM
-- CST解决办法也很简单,明确指定 MySQL 数据库的时区,不使用引发误解的 CST:
-- 方法一:使用命令(优点:不需要重启MySQL服务,缺点:一旦MySQL服务被重启,设置就会消失)
set global time_zone = '+8:00'set time_zone = '+8:00';
flush privileges;
方法二:修改my.ini配置文件(优点:永久保存设置,缺点:需重启MySQL服务)
或者修改 my.cnf 文件,在 [mysqld] 节下增加 default-time-zone = '+08:00'。
修改时区操作影响深远,需要重启 MySQL 服务器,建议在维护时间进行。

time_zone说明mysql使用system的时区,system_time_zone说明system使用UTC时区
在这里插入图片描述
美国从“3月11日”至“11月7日”实行夏令时,美国中部时间改为 UTC-05:00,与 UTC+08:00 相差 13 小时。
当 MySQL 的 time_zone 值为 SYSTEM 时,会取 system_time_zone 值作为协调时区。

  1. 版本问题
    受害人描述:

      经过不断的尝试,探索终于发现时mysql-connector-java的版本问题,
      项目A使用的版本是5.1.41,项目B使用的8.0.11。
      写入数据时,8.0这个版本会自动根据,
      传入时间的时区和mysql的时区,自动把时间进行调整   
      
       服务器的mysql版本是5,如果服务器的mysql版本是8,
       则项目不能使用5        版本的mysql-connector-java库。
    
  2. java数据库连接使用的是UTC(某个)时区
    步骤一:修改java中的时区为东八区
    核心就是:修改spring.datasource.url后面的serverTimezone=GMT为serverTimezone=Asia/Shanghai就可以了。

spring.datasource.url=jdbc:mysql://localhost:3306/flashsale?useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai

// serverTimezone可以设置为北京时间GMT%2B8、上海时间Asia/Shanghai或者香港时间Hongkong
url: jdbc:mysql://localhost:3306/test?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=true

spring.datasource.jdbc-url=jdbc:mysql://${config.service.db.ip}:${config.service.db.port}/dahua_record?userUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai

步骤二:修改MySQL数据库的时区为东八区
(Windows下叫my.ini,Linux下叫my.cnf,别搞错了)

// 方法一:使用命令(优点:不需要重启MySQL服务,缺点:一旦MySQL服务被重启,设置就会消失)
mysql> set time_zone = '+8:00';
mysql> set global time_zone = '+8:00';
// 方法二:修改my.ini配置文件(优点:永久保存设置,缺点:需重启MySQL服务)
[mysqld]
// 设置默认时区
default-time_zone='+8:00'

参考博客地址:
一次因“CST”时区协商问题导致数据库时间戳错误的 debug 经历
mysql传入时间正确,但是插入到数据库时间错误,相差几个小时。
Mysql查询的数据和显示的数据时区不一致解决方案
mysql数据库获取执行时间差_Mysql数据库显示时间与应用程序获取到的不一致的问题…

关于null值拼接bug

由于后续需求,我加入数据库一个字段,走新流程这个字段是一定会拿到值的,也就不会出现这个问题,这个就是历史数据,导致数据库查不到这个字段的值 ,我在进行字符串拼接的时候 页面展示了null。
解决办法:进行null判断 非空才让连续拼接。

        String str = null;
        System.out.println(str);//null 没有值 所以下面报错
//        System.out.println(str.equals(null));//java.lang.NullPointerException
        str = str + "";
        System.out.println(str);//null  此时是字符串 null 不是空值的意思
        System.out.println(str.equals(null));//false
        System.out.println(str.equals("null"));//true

ClassNotFoundException/NoClassDefFoundError出现原因及解决

常见原因:

  1. 没有引入jar包;
  2. jar包冲突;(依赖错jar包了)
  3. pom中增加依赖后classpath没有被更新;
  4. maven依赖的scope设置不合理;

我当时的解决是,取消maven自动导包,然后再maven pom依次引入依赖,手动导包。
取消方法:
在这里插入图片描述

下面是别人遇到的解决方式:
出现原因:
在IDEA中,maven配置provided,运行时依赖不起作用;
maven配置provided,依赖只作用于编译和打包等,但不能用于运行类。通俗的说,配置了provided,就是在告诉IDEA,你不要担心,我会在运行时提供这个依赖,但是实际上却并没有提供依赖。除非将这个依赖加到类路径下,那么就OK了。所以解决办法也就出来了。
解决方法:
去掉 provided,改为 compile,当然只去掉也可,默认就是compile。注:改完后,在maven上运行一下reimport,重新导入一下。打完收工。
或者去
在这里插入图片描述

还有人:clean 一下重启 可以试试
在这里插入图片描述
课外补充:
NoClassDefFoundError和ClassNotFoundException区别
我们经常被java.lang.ClassNotFoundException和java.lang.NoClassDefFoundError这两个错误迷惑不清,尽管他们都与Java classpath有关,但是他们完全不同。NoClassDefFoundError发生在JVM在动态运行时,根据你提供的类名,在classpath中找到对应的类进行加载,但当它找不到这个类时,就发生了java.lang.NoClassDefFoundError的错误,而ClassNotFoundException是在编译的时候在classpath中找不到对应的类而发生的错误。==ClassNotFoundException比NoClassDefFoundError容易解决,是因为在编译时我们就知道错误发生,并且完全是由于环境的问题导致。==而如果你在J2EE的环境下工作,并且得到NoClassDefFoundError的异常,而且对应的错误的类是确实存在的,这说明这个类对于类加载器来说,可能是不可见的。
NoClassDefFoundError错误发生的原因
NoClassDefFoundError错误的发生,是因为Java虚拟机在编译时能找到合适的类,而在运行时不能找到合适的类导致的错误。例如在运行时我们想调用某个类的方法或者访问这个类的静态成员的时候,发现这个类不可用,此时Java虚拟机就会抛出NoClassDefFoundError错误。与ClassNotFoundException的不同在于,==这个错误发生只在运行时需要加载对应的类不成功,而不是编译时发生。==很多Java开发者很容易在这里把这两个错误搞混。

简单总结就是,NoClassDefFoundError发生在编译时对应的类可用,而运行时在Java的classpath路径中,对应的类不可用导致的错误。

怎么解决NoClassDefFoundError错误
根据前文,很明显NoClassDefFoundError的错误是因为在运行时类加载器在classpath下找不到需要加载的类,所以我们需要把对应的类加载到classpath中,或者检查为什么类在classpath中是不可用的,这个发生可能的原因如下:
对应的Class在java的classpath中不可用。
你可能用jar命令运行你的程序,但类并没有在jar文件的manifest文件中的classpath属性中定义。
可能程序的启动脚本覆盖了原来的classpath环境变量。
因为NoClassDefFoundError是java.lang.LinkageError的一个子类,所以可能由于程序依赖的原生的类库不可用而导致。
检查日志文件中是否有java.lang.ExceptionInInitializerError这样的错误,NoClassDefFoundError有可能是由于静态初始化失败导致的。
如果你工作在J2EE的环境,有多个不同的类加载器,也可能导致NoClassDefFoundError。

关于binary的使用防止可能潜在的错误

因为有的MySQL特别是4.*以前的对于中文检索会有不准确的问题,可以在检索的时候加上binary。
在这里插入图片描述
网址

# ,就可以准确的查询对应记录来。
select * from usertest where username like binary  '%夏%' 
# binary区分大小写
select 1=1 -- 1
select binary 'ABCD'='abcd' COM1;-- 0
select 'ABCD'='abcd' COM2; -- 1
# 下面修改了数据库一般肯定不让动数据库,知道即可,不推荐使用
alter table usertest modify username varchar(32) binary; 

binary保存二进制字符串,它保存的是字节而不是字符,没有字符集限制
binary(8)可以保存8个字符,每个字符占1个字节,共占8个字节。

关于业务中存储数据字段存反对历史数据的处理

这个总体解决方式也很简单,具体根据你业务,我遇到如下处理

首先把代码先更正,保证今后数据正常在这里插入图片描述
针对已入库的历史数据通过更新数据库,具体如下
新建临时字段,这个跟java里弄个临时变量一个思想

首先说一下:我们这个表存储各种类型的通知,只有这个标题类型存反了,所以只能修改这个类型的数据,进行两字段互换。

ALTER TABLE target_table ADD COLUMN `tmp_agency_type` varchar(2000) NULL AFTER `gmt_modified`;
update target_table set tmp_agency_type = agency_type WHERE agency_title = '标题类型' ;
update target_table set agency_type = agency_title WHERE tmp_agency_type is not null ;
update target_table set agency_title = tmp_agency_type WHERE tmp_agency_type is not null ;
ALTER TABLE target_table DROP COLUMN `tmp_agency_type`;

关于夏时令时间问题

夏令时间,指在夏天的时候,将时钟拨快一个小时,以提早日光的使用,在英国称为夏令时间;
解决办法重写获取日期的方法

如果想知道夏时令更多知识请参考这篇文章
问题背景:保险公司成立日期设置为东八区解决1991之前返回前一天23点的问题
以下是博主的解决措施:
在这里插入图片描述

        <dependency>
            <groupId>com.fasterxml.jackson.dataformat</groupId>
            <artifactId>jackson-dataformat-xml</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.9</version>
        </dependency>
import org.apache.commons.lang3.ObjectUtils;
import java.util.Date;
import java.util.TimeZone;
 
 //直接用注解貌似不能解决问题
//    @JsonFormat(pattern = "yyyy-MM-dd")
//    @JsonFormat(pattern="yyyy-MM-dd",timezone="GMT+8")
//    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "Asia/Shanghai")
    private Date dateOfIncorporation;
    public Date getDateOfIncorporation() {
        TimeZone tz =TimeZone.getTimeZone("Asia/Shanghai");
        if(ObjectUtils.isNotEmpty(dateOfIncorporation) && tz.inDaylightTime(dateOfIncorporation)){
            long b=dateOfIncorporation.getTime();
            b=b+60*60*1000;
            return new Date(b);
        }else{
            return dateOfIncorporation;
        }
    }

在这里插入图片描述

Date birthday=new Date(Long.parseLong(birthdaystr));
TimeZone tz =TimeZone.getTimeZone("Asia/Shanghai");
//如果是夏令时,+1小时
if(tz.inDaylightTime(birthday)){
	long b=birthday.getTime();
	b=b+60*60*1000;
	birthday=new Date(b);
	LOGGER.info("birthday转换成功:"+birthday.getTime());
}

看网上有说加注解:@JsonFormat(pattern = “yyyy-MM-dd”, timezone = “Asia/Shanghai”),没有亲自尝试

也可参考:基于java时区转换夏令时的问题及解决方法

MAP<STRING,OBJECT>接收参数,LONG类型降级为INTEGER,报类型转换异常

在这里插入图片描述

具体可参考此网址

使用 Map<String,Object> 对象接收前端传递的参数,在后端取参时,因为接口文档中明确该字段类型为 Long ,所以对接收的参数进行了强转,即 (Long)参数 ,但是却发生了类型转换异常,报错信息如下:

class java.lang.Integer cannot be cast to class java.lang.Long 
(java.lang.Integer and java.lang.Long are in module java.base of loader 'bootstrap')

包装类型数据不支持直接跨类型强转
Integer对象直接转Long对象是会报错的

在这里插入图片描述

解决措施利用 instanceof或者直接使用实体类接收,因为实体类中限制了字段类型。
在这里插入图片描述

        Object num1 = 123;
        Integer num2 = 123;
        //Long no1= (Long) num2;//编译不通过
        Long no = num1 instanceof Integer ? Long.parseLong(num1.toString()) : (Long) num1;
        System.out.println(no);

其他类似强转报错

//如 map中取值转BigDecimal报错
 Map<String, Object> map = new HashMap<>();
 map.put("score", 10);
BigDecimal score = (BigDecimal) map.get("score");
//Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.math.BigDecimal
System.out.println(score);
//正确做法 下面这个我没尝试,个人觉得 10这里会被认为是Integer  BigDecimal接收String的类型最好
//直接把Integer转String 
BigDecimal score2 = new BigDecimal((Integer) map.get("score"));
System.out.println(score2);

//由于不确定是 Integer 还是 Long,而且包装类型之间强转会报错。所以我们就不能进行强转,可以按照如下方法操作
// 不直接强转先用 Object 接收
Object number = map.get("number");
// 下面两种二选一
Long longNumber = Long.valueOf(number.toString());
Long longNumber = Long.valueOf(String.valueOf(number));

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值