一:Java开发常用知识点-基础篇

233 阅读14分钟

1.判空

1.判断对象是否为空

Java自带

判断是否为null 不为null处理逻辑

String demo="测试一段话";  
Optional.of(demo).ifPresent((d)->{  
    System.out.println("秀儿:"+d);  
});

等同于下面写法

String demo="测试一段话";  
if (demo==null){  
    System.out.println("秀儿:"+demo);  
}

hutool中方法:判断是否为null

  • ObjectUtil.isNull
  • ObjectUtil.isNotNull

注意:此方法不能判断对象中字段为空的情况,如果需要检查Bean对象中字段是否全空,请使用BeanUtil.isEmpty。 springboot中方法:判断是否为null

  • boolean isEmpty(Object obj)

示例:

Demo demo=new Demo();  
boolean empty = ObjectUtils.isEmpty(demo);  
System.out.println(empty);

2.判断字符串是否为空

判断字符串是否为 null,或 ""。注意,包含空白符的字符串为非空

  1. 可以选择判断对象的方法

  2. hutool中StrUtil方法:

  • isEmpty()
  1. springboot中StringUtils方法:
  • boolean isEmpty(Object str)

判断字符串是否包含实际内容,即非仅包含空白符,也就是 Not Blank

hutool中StrUtil方法:

  • isBlankisNotBlank

springboot中StringUtils方法:

  • boolean hasText(CharSequence str)

3.判断集合时候为空

1.hutool中的方法

  • ObjectUtil.isEmpty()
  • CollUtil.isEmpty()
  • CollUtil.isNotEmpty()

2.springboot中的方法

  • CollectionUtils.isEmpty()

2.类型转换

1.数组->集合

String[] strings = new String[6];  
Arrays.stream(strings).collect(Collectors.toList());

hutool中的方法

String[] strings = new String[6];  
CollUtil.toList(strings);

springboot中的方法

String[] strings = new String[6];  
List<String> list = (List<String>) CollectionUtils.arrayToList(strings);

2.集合->数组

List<String> list = new ArrayList<>();  
String[] array = list.toArray(new String[0]);

3.bean

BeanUtil.fillBean方法是bean注入的核心方法,此方法传入一个ValueProvider接口,通过实现此接口来获得key对应的值。CopyOptions参数则提供一些注入属性的选项。

CopyOptions的配置项包括:

  1. editable 限制的类或接口,必须为目标对象的实现接口或父类,用于限制拷贝的属性,例如一个类我只想复制其父类的一些属性,就可以将editable设置为父类。
  2. ignoreNullValue 是否忽略空值,当源对象的值为null时,true: 忽略而不注入此值,false: 注入null
  3. ignoreProperties 忽略的属性列表,设置一个属性列表,不拷贝这些属性值
  4. ignoreError 是否忽略字段注入错误

可以通过CopyOptions.create()方法创建一个默认的配置项,通过setXXX方法设置每个配置项。

ValueProvider接口需要实现两个方法:

  1. value方法是通过key和目标类型来从任何地方获取一个值,并转换为目标类型,如果返回值不和目标类型匹配,将会自动调用Convert.convert方法转换。
  2. containsKey方法主要是检测是否包含指定的key,如果不包含这个key,其对应的属性将会忽略注入。

首先定义两个bean:

// Lombok注解
@Data
public class Person{
    private String name;
    private int age;
}

// Lombok注解
@Data
public class SubPerson extends Person {
    public static final String SUBNAME = "TEST";

    private UUID id;
    private String subName;
    private Boolean isSlow;
}

然后注入这个bean:

Person person = BeanUtil.fillBean(new Person(), new ValueProvider<String>(){

    @Override
    public Object value(String key, Class<?> valueType) {
        switch (key) {
            case "name":
                return "张三";
            case "age":
                return 18;
        }
        return null;
    }

    @Override
    public boolean containsKey(String key) {
        //总是存在key
        return true;
    }
    
}, CopyOptions.create());

Assert.assertEquals(person.getName(), "张三");
Assert.assertEquals(person.getAge(), 18);

同时,Hutool还提供了BeanUtil.toBean方法,此处并不是传Bean对象,而是Bean类,Hutool会自动调用默认构造方法创建对象。

基于BeanUtil.fillBean方法Hutool还提供了Map对象键值对注入Bean,其方法有:

  1. BeanUtil.fillBeanWithMap 使用Map填充bean
HashMap<String, Object> map = CollUtil.newHashMap();
map.put("name", "Joe");
map.put("age", 12);
map.put("openId", "DFDFSDFWERWER");

SubPerson person = BeanUtil.fillBeanWithMap(map, new SubPerson(), false);
  1. BeanUtil.fillBeanWithMapIgnoreCase 使用Map填充bean,忽略大小写
HashMap<String, Object> map = CollUtil.newHashMap();
map.put("Name", "Joe");
map.put("aGe", 12);
map.put("openId", "DFDFSDFWERWER");
SubPerson person = BeanUtil.fillBeanWithMapIgnoreCase(map, new SubPerson(), false);

同时提供了map转bean的方法,与fillBean不同的是,此处并不是传Bean对象,而是Bean类,Hutool会自动调用默认构造方法创建对象。当然,前提是Bean类有默认构造方法(空构造),这些方法有:

1. BeanUtil.toBean

HashMap<String, Object> map = CollUtil.newHashMap();
map.put("a_name", "Joe");
map.put("b_age", 12);
// 设置别名,用于对应bean的字段名
HashMap<String, String> mapping = CollUtil.newHashMap();
mapping.put("a_name", "name");
mapping.put("b_age", "age");
Person person = BeanUtil.toBean(map, Person.class, CopyOptions.create().setFieldMapping(mapping));

2. BeanUtil.toBeanIgnoreCase

HashMap<String, Object> map = CollUtil.newHashMap();
map.put("Name", "Joe");
map.put("aGe", 12);

Person person = BeanUtil.toBeanIgnoreCase(map, Person.class, false);

bean->map

BeanUtil.beanToMap方法则是将一个Bean对象转为Map对象。

SubPerson person = new SubPerson();
person.setAge(14);
person.setOpenid("11213232");
person.setName("测试A11");
person.setSubName("sub名字");

Map<String, Object> map = BeanUtil.beanToMap(person);

Bean转Bean

Bean之间的转换主要是相同属性的复制,因此方法名为copyProperties,此方法支持Bean和Map之间的字段复制。

BeanUtil.copyProperties方法同样提供一个CopyOptions参数用于自定义属性复制。

SubPerson p1 = new SubPerson();
p1.setSlow(true);
p1.setName("测试");
p1.setSubName("sub测试");

Map<String, Object> map = MapUtil.newHashMap();

BeanUtil.copyProperties(p1, map);

Alias注解

5.x的Hutool中增加了一个自定义注解:@Alias,通过此注解可以给Bean的字段设置别名。

首先我们给Bean加上注解:

// Lombok注解
@Getter
@Setter
public static class SubPersonWithAlias {
    @Alias("aliasSubName")
    private String subName;
    private Boolean slow;
SubPersonWithAlias person = new SubPersonWithAlias();
person.setSubName("sub名字");
person.setSlow(true);

// Bean转换为Map时,自动将subName修改为aliasSubName
Map<String, Object> map = BeanUtil.beanToMap(person);
// 返回"sub名字"
map.get("aliasSubName")

同样Alias注解支持注入Bean时的别名:

Map<String, Object> map = MapUtil.newHashMap();
map.put("aliasSubName", "sub名字");
map.put("slow", true);

SubPersonWithAlias subPersonWithAlias = BeanUtil.mapToBean(map, SubPersonWithAlias.class, false);
// 返回"sub名字"
subPersonWithAlias.getSubName();

3.常用方法

1.集合或者数组 字符串拼接

  • String.join() 2.略

4.时间处理

时间类型使用LocalDateTime

采用hutool对时间进行处理

Date、long、Calendar之间的相互转换

//当前时间
Date date = DateUtil.date();
//当前时间
Date date2 = DateUtil.date(Calendar.getInstance());
//当前时间
Date date3 = DateUtil.date(System.currentTimeMillis());
//当前时间字符串,格式:yyyy-MM-dd HH:mm:ss
String now = DateUtil.now();
//当前日期字符串,格式:yyyy-MM-dd
String today= DateUtil.today();

字符串转日期

DateUtil.parse方法会自动识别一些常用格式,包括:

yyyy-MM-dd HH:mm:ss

  • yyyy/MM/dd HH:mm:ss
  • yyyy.MM.dd HH:mm:ss
  • yyyy年MM月dd日 HH时mm分ss秒
  • yyyy-MM-dd
  • yyyy/MM/dd
  • yyyy.MM.dd
  • HH:mm:ss
  • HH时mm分ss秒
  • yyyy-MM-dd HH:mm
  • yyyy-MM-dd HH:mm:ss.SSS
  • yyyyMMddHHmmss
  • yyyyMMddHHmmssSSS
  • yyyyMMdd
  • EEE, dd MMM yyyy HH:mm:ss z
  • EEE MMM dd HH:mm:ss zzz yyyy
  • yyyy-MM-dd'T'HH:mm:ss'Z'
  • yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
  • yyyy-MM-dd'T'HH:mm:ssZ
  • yyyy-MM-dd'T'HH:mm:ss.SSSZ
String dateStr = "2017-03-01";
Date date = DateUtil.parse(dateStr);

我们也可以使用自定义日期格式转化:

String dateStr = "2017-03-01";
Date date = DateUtil.parse(dateStr, "yyyy-MM-dd");

格式化日期输

String dateStr = "2017-03-01";
Date date = DateUtil.parse(dateStr);

//结果 2017/03/01
String format = DateUtil.format(date, "yyyy/MM/dd");

//常用格式的格式化,结果:2017-03-01
String formatDate = DateUtil.formatDate(date);

//结果:2017-03-01 00:00:00
String formatDateTime = DateUtil.formatDateTime(date);

//结果:00:00:00
String formatTime = DateUtil.formatTime(date);

获取Date对象的某个部分

Date date = DateUtil.date();
//获得年的部分
DateUtil.year(date);
//获得月份,从0开始计数
DateUtil.month(date);
//获得月份枚举
DateUtil.monthEnum(date);
//.....

开始和结束时间

有的时候我们需要获得每天的开始时间、结束时间,每月的开始和结束时间等等,DateUtil也提供了相关方法:

String dateStr = "2017-03-01 22:33:23";
Date date = DateUtil.parse(dateStr);

//一天的开始,结果:2017-03-01 00:00:00
Date beginOfDay = DateUtil.beginOfDay(date);

//一天的结束,结果:2017-03-01 23:59:59
Date endOfDay = DateUtil.endOfDay(date);

日期时间偏移

日期或时间的偏移指针对某个日期增加或减少分、小时、天等等,达到日期变更的目的。Hutool也针对其做了大量封装

String dateStr = "2017-03-01 22:33:23";
Date date = DateUtil.parse(dateStr);

//结果:2017-03-03 22:33:23
Date newDate = DateUtil.offset(date, DateField.DAY_OF_MONTH, 2);

//常用偏移,结果:2017-03-04 22:33:23
DateTime newDate2 = DateUtil.offsetDay(date, 3);

//常用偏移,结果:2017-03-01 19:33:23
DateTime newDate3 = DateUtil.offsetHour(date, -3);

针对当前时间,提供了简化的偏移方法(例如昨天、上周、上个月等):

//昨天
DateUtil.yesterday()
//明天
DateUtil.tomorrow()
//上周
DateUtil.lastWeek()
//下周
DateUtil.nextWeek()
//上个月
DateUtil.lastMonth()
//下个月
DateUtil.nextMonth()

日期时间差

有时候我们需要计算两个日期之间的时间差(相差天数、相差小时数等等),Hutool将此类方法封装为between方法:

String dateStr1 = "2017-03-01 22:33:23";
Date date1 = DateUtil.parse(dateStr1);

String dateStr2 = "2017-04-01 23:33:23";
Date date2 = DateUtil.parse(dateStr2);

//相差一个月,31天
long betweenDay = DateUtil.between(date1, date2, DateUnit.DAY);

格式化时间差

有时候我们希望看到易读的时间差,比如XX天XX小时XX分XX秒,此时使用DateUtil.formatBetween方法:

//Level.MINUTE表示精确到分
String formatBetween = DateUtil.formatBetween(between, Level.MINUTE);
//输出:31天1小时
Console.log(formatBetween);

星座和属相

// "摩羯座"
String zodiac = DateUtil.getZodiac(Month.JANUARY.getValue(), 19);

// "狗"
String chineseZodiac = DateUtil.getChineseZodiac(1994);

其它

//年龄
DateUtil.ageOfNow("1990-01-30");

//是否闰年
DateUtil.isLeapYear(2017);

5.数字处理

使用hutool工具

加减乘除

  • NumberUtil.add 针对数字类型做加法
  • NumberUtil.sub 针对数字类型做减法
  • NumberUtil.mul 针对数字类型做乘法
  • NumberUtil.div 针对数字类型做除法,并提供重载方法用于规定除不尽的情况下保留小数位数和舍弃方式。

以上四种运算都会将double转为BigDecimal后计算,解决float和double类型无法进行精确计算的问题。这些方法常用于商业计算。

保留小数

保留小数的方法主要有两种:

  • NumberUtil.round 方法主要封装BigDecimal中的方法来保留小数,返回BigDecimal,这个方法更加灵活,可以选择四舍五入或者全部舍弃等模式。
double te1=123456.123456;
double te2=123456.128456;
Console.log(round(te1,4));//结果:123456.1235
Console.log(round(te2,4));//结果:123456.1285
  • NumberUtil.roundStr 方法主要封装String.format方法,舍弃方式采用四舍五入。
double te1=123456.123456;
double te2=123456.128456;
Console.log(roundStr(te1,2));//结果:123456.12
Console.log(roundStr(te2,2));//结果:123456.13

decimalFormat

针对 DecimalFormat.format进行简单封装。按照固定格式对double或long类型的数字做格式化操作。

long c=299792458;//光速
String format = NumberUtil.decimalFormat(",###", c);//299,792,458

格式中主要以 # 和 0 两种占位符号来指定数字长度。0 表示如果位数不足则以 0 填充,# 表示只要有可能就把数字拉上这个位置。

  • 0 -> 取一位整数
  • 0.00 -> 取一位整数和两位小数
  • 00.000 -> 取两位整数和三位小数
  • # -> 取所有整数部分
  • #.##% -> 以百分比方式计数,并取两位小数
  • #.#####E0 -> 显示为科学计数法,并取五位小数
  • ,### -> 每三位以逗号进行分隔,例如:299,792,458
  • 光速大小为每秒,###米 -> 将格式嵌入文本

关于格式的更多说明,请参阅:Java DecimalFormat的主要功能及使用方法

是否为数字

  • NumberUtil.isNumber 是否为数字
  • NumberUtil.isInteger 是否为整数
  • NumberUtil.isDouble 是否为浮点数
  • NumberUtil.isPrimes 是否为质数

随机数

  • NumberUtil.generateRandomNumber 生成不重复随机数 根据给定的最小数字和最大数字,以及随机数的个数,产生指定的不重复的数组。
  • NumberUtil.generateBySet 生成不重复随机数 根据给定的最小数字和最大数字,以及随机数的个数,产生指定的不重复的数组。

整数列表

NumberUtil.range 方法根据范围和步进,生成一个有序整数列表。 NumberUtil.appendRange 将给定范围内的整数添加到已有集合中

其它

  • NumberUtil.factorial 阶乘
  • NumberUtil.sqrt 平方根
  • NumberUtil.divisor 最大公约数
  • NumberUtil.multiple 最小公倍数
  • NumberUtil.getBinaryStr 获得数字对应的二进制字符串
  • NumberUtil.binaryToInt 二进制转int
  • NumberUtil.binaryToLong 二进制转long
  • NumberUtil.compare 比较两个值的大小
  • NumberUtil.toStr 数字转字符串,自动并去除尾小数点儿后多余的0

6.文件处理

hutool工具

FileUtil类包含以下几类操作工具:

  1. 文件操作:包括文件目录的新建、删除、复制、移动、改名等
  2. 文件判断:判断文件或目录是否非空,是否为目录,是否为文件等等。
  3. 绝对路径:针对ClassPath中的文件转换为绝对路径文件。
  4. 文件名:主文件名,扩展名的获取
  5. 读操作:包括类似IoUtil中的getReader、readXXX操作
  6. 写操作:包括getWriter和writeXXX操作

在FileUtil中,我努力将方法名与Linux相一致,例如创建文件的方法并不是createFile,而是touch,这种统一对于熟悉Linux的人来说,大大提高了上手速度。当然,如果你不熟悉Linux,那FileUtil工具类的使用则是在帮助你学习Linux命令。这些类Linux命令的方法包括:

  • ls 列出目录和文件
  • touch 创建文件,如果父目录不存在也自动创建
  • mkdir 创建目录,会递归创建每层目录
  • del 删除文件或目录(递归删除,不判断是否为空),这个方法相当于Linux的delete命令
  • copy 拷贝文件或目录

这些方法提供了人性化的操作,例如touch方法,在创建文件的情况下会自动创建上层目录(我想对于使用者来说这也是大部分情况下的需求),同样mkdir也会创建父目录。

需要注意的是,del方法会删除目录而不判断其是否为空,这一方面方便了使用,另一方面也可能造成一些预想不到的后果(比如拼写错路径而删除不应该删除的目录),所以请谨慎使用此方法。

关于FileUtil中更多工具方法,请参阅API文档。

FileReader

在JDK中,同样有一个FileReader类,但是并不如想象中的那样好用,于是Hutool便提供了更加便捷FileReader类。

//默认UTF-8编码,可以在构造中传入第二个参数做为编码
FileReader fileReader = new FileReader("test.properties");
String result = fileReader.readString();

FileReader提供了以下方法来快速读取文件内容:

  • readBytes
  • readString
  • readLines

同时,此类还提供了以下方法用于转换为流或者BufferedReader:

  • getReader
  • getInputStream

FileWriter

相应的,文件读取有了,自然有文件写入类,使用方式与FileReader也类似:

FileWriter writer = new FileWriter("test.properties");
writer.write("test");

写入文件分为追加模式和覆盖模式两类,追加模式可以用append方法,覆盖模式可以用write方法,同时也提供了一个write方法,第二个参数是可选覆盖模式。

同样,此类提供了:

  • getOutputStream
  • getWriter
  • getPrintWriter

这些方法用于转换为相应的类提供更加灵活的写入操作。

SpringBoot中文件 IO工具

FileCopyUtils

  1. 输入
// 从文件中读入到字节数组中
byte[] copyToByteArray(File in)
// 从输入流中读入到字节数组中
byte[] copyToByteArray(InputStream in)
// 从输入流中读入到字符串中
String copyToString(Reader in)
  1. 输出
// 从字节数组到文件
void copy(byte[] in, File out)
// 从文件到文件
int copy(File in, File out)
// 从字节数组到输出流
void copy(byte[] in, OutputStream out)
// 从输入流到输出流
int copy(InputStream in, OutputStream out)
// 从输入流到输出流
int copy(Reader in, Writer out)
// 从字符串到输出流
void copy(String in, Writer out)

ResourceUtils

  1. 从资源路径获取文件
// 判断字符串是否是一个合法的 URL 字符串。
static boolean isUrl(String resourceLocation)
// 获取 URL
static URL getURL(String resourceLocation)
// 获取文件(在 JAR 包内无法正常使用,需要是一个独立的文件)
static File getFile(String resourceLocation)
  1. Resource
// 文件系统资源 D:...
FileSystemResource
// URL 资源,如 file://... http://...
UrlResource
// 类路径下的资源,classpth:...
ClassPathResource
// Web 容器上下文中的资源(jar 包、war 包)
ServletContextResource
// 判断资源是否存在
boolean exists()
// 从资源中获得 File 对象
File getFile()
// 从资源中获得 URI 对象
URI getURI()
// 从资源中获得 URI 对象
URL getURL()
// 获得资源的 InputStream
InputStream getInputStream()
// 获得资源的描述信息
String getDescription()

StreamUtils

  1. 输入
void copy(byte[] in, OutputStream out)
int copy(InputStream in, OutputStream out)
void copy(String in, Charset charset, OutputStream out)
long copyRange(InputStream in, OutputStream out, long start, long end)
  1. 输出
byte[] copyToByteArray(InputStream in)
String copyToString(InputStream in, Charset charset)
// 舍弃输入流中的内容
int drain(InputStream in)

7.文件路径

1.某个resources下的路径

String filePath = Thread.currentThread().getContextClassLoader().getResource("").getPath();

也就是Classes下的路径

2.当前运行的tomcat的路径

String realPath = request.getSession().getServletContext().getRealPath("");

其返回值为当前运行的tomcat路径  

其路径为:xxxx/xxxx/tomcat/webapps 

注意:其路径为绝对路径

8.MultipartFile转文件

将spring上传的文件保存到指定位置

import org.apache.commons.io.FileUtils;  
import org.springframework.stereotype.Component;  
import org.springframework.web.multipart.MultipartFile;  
  
import java.io.File;  
import java.io.IOException;  
  
@Component  
public class FileTool {  
public void saveFile(String filePath, MultipartFile file){  
File saveFile = new File(filePath);  
if (!saveFile.exists()){  
try {  
FileUtils.touch(saveFile);  
FileUtils.copyInputStreamToFile(file.getInputStream(),saveFile);  
} catch (IOException e) {  
throw new ServerException("文件保存出错:"+e.getMessage());  
}  
}  
}  
}

9.发送http请求

10.HttpServletResponse返回数据

1.返回html页面信息

response.setContentType("text/html;charset=UTF-8");  
response.getWriter().write(body);

2.返回json数据

response.setContentType("application/json; charset=UTF-8");  
response.getWriter().write(body);

3.返回流信息

//防止数据返回乱码
response.setHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode(fileName ,"utf-8"));

返回文件流

import java.net.URLEncoder;  
import org.springframework.util.FileCopyUtils;

public void backResponse(HttpServletResponse response,String fileName,String filePath) throws Exception {  
response.setHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode(fileName ,"utf-8"));  
OutputStream out = response.getOutputStream();  
FileCopyUtils.copy(new FileInputStream(new File(filePath)),out);  
out.close();  
}

11.HttpServletRequest获取请求方式以及请求参数

0. 获取url后面的请求参数

image.png

String queryString = request.getQueryString();  
System.out.println(queryString);

结果:

uuid=1&name=2

1. application/json方式请求

image.png

//获取请求类型
String type = request.getContentType();
//获取请求方式
String method = request.getMethod();
//获取参数
BufferedReader streamReader = new BufferedReader( new InputStreamReader(request.getInputStream(), "UTF-8"));  
StringBuilder body = new StringBuilder();  
String inputStr;  
while ((inputStr = streamReader.readLine()) != null){  
body.append(inputStr);  
}  
System.out.println(body.toString());

hutool版本

//获取请求类型  
String type = request.getContentType();  
//获取请求方式  
String method = request.getMethod();  
//获取参数  
FastByteArrayOutputStream read = IoUtil.read(request.getInputStream());  
System.out.println(read.toString());

2. form-data请求方式

image.png

String type = request.getContentType();  
String method = request.getMethod();  
Map<String, String[]> map = request.getParameterMap();  
System.out.println(type);  
System.out.println(method);  
System.out.println(JSONUtil.toJsonStr(map));

结果

multipart/form-data; boundary=--------------------------495998452566244224249539
POST
{"uuid":["1"],"name":["2"]}

3. x-www-form-urlencoded请求方式

image.png

request.setCharacterEncoding("utf-8");  
String type = request.getContentType();  
String method = request.getMethod();  
Map<String, String[]> map = request.getParameterMap();  
System.out.println(type);  
System.out.println(method);  
System.out.println(JSONUtil.toJsonStr(map));

结果

application/x-www-form-urlencoded
POST
{"uuid":["1"],"name":["2"]}

4. 获取上传文件参数

if (request instanceof MultipartHttpServletRequest) {  
    MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;  
    Iterator<String> fileNames = multipartRequest.getFileNames();  
    while (fileNames.hasNext()) {  
        String param = fileNames.next();  
        List<MultipartFile> files = multipartRequest.getFiles(param);  
    }  
}