# java中常见方法总结
| 🐉 trycatch的高阶用法学习 | 🐉 replace的高阶用法学习 |
|---|---|
| JSON | 分布式唯一ID算法 |
| if_else太多,如何重构(策略模式) | 单点登录CAS |
| java8时间的序列化与反序列化 | 经典JAVA算法题册 |
| 获取 /resources 目录资源文件的 9 种方法 |
# classForName
@CallerSensitive
public static Class<?> forName(String className)
throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
2
3
4
5
6
@CallerSensitive
public static Class<?> forName(String name, boolean initialize,
ClassLoader loader)
throws ClassNotFoundException
{
Class<?> caller = null;
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
// Reflective call to get caller class is only needed if a security manager
// is present. Avoid the overhead of making this call otherwise.
caller = Reflection.getCallerClass();
if (sun.misc.VM.isSystemDomainLoader(loader)) {
ClassLoader ccl = ClassLoader.getClassLoader(caller);
if (!sun.misc.VM.isSystemDomainLoader(ccl)) {
sm.checkPermission(
SecurityConstants.GET_CLASSLOADER_PERMISSION);
}
}
}
return forName0(name, initialize, loader, caller);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@param initialize if {@code true} the class will be initialized.
根据运行结果得出Class.forName加载类时将类进了初始化,而ClassLoader的loadClass并没有对类进行初始化,只是把类加载到了虚拟机中。
# 保留有效数字
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.NumberFormat;
public class TestDemo{
public static void main(String[] args) {
double num1 = 100.13145;
//保留4位小数 100.1315 四舍五入
BigDecimal bigDecimal = new BigDecimal(num1);
double num2 = bigDecimal.setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue();
System.out.println(num2);
// 保留4位小数 100.1315 四舍五入
DecimalFormat decimalFormat = new DecimalFormat("#.0000");
String stringValue = decimalFormat.format(num1);
System.out.println(stringValue);
Double doubleValue = Double.parseDouble(decimalFormat.format(num1));
System.out.println(doubleValue);
// 保留4位小数 100.1315 四舍五入
System.out.println(String.format("%.4f", num1));
// 保留4位小数 100.1315 四舍五入
Double get_double = (double) ((Math.round(num1 * 10000)) / 10000.0);
System.out.println(get_double);
// 保留4位小数 100.1315
NumberFormat numberFormat = NumberFormat.getNumberInstance();
numberFormat.setMaximumFractionDigits(4);
System.out.println(numberFormat.format(num1));
// 保留4位小数 100.1314
float num3 = (float) 100.13145;
float a = (float) (Math.round(num3 * 10000)) / 10000;
System.out.println(a);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# 进一法
List<String> lists = generateList();
int listSize = lists.size();
int baseInt = 800;
int loopTimes = (int) Math.ceil((double) listSize / baseInt);
2
3
4
# 二进制操作
# 判断2的倍数
boolean powerOfTwo(int n){
if (n <= 0){
return false;
}
return (n & (n-1)) == 0;
}
2
3
4
5
6
2的倍数二进制的形式一定是1000,2的倍数-1的二进制的形式一定是111,所以与操作一定是0
# 判断字符串空
# 针对空格做处理,排除空格、制表等空白符号
com.mysql.jdbc. StringUtils. isEmptyOrWhitespaceOnly
public static boolean isEmptyOrWhitespaceOnly(String str) {
if (str == null || str.length() == 0) {
return true;
}
int length = str.length();
for (int i = 0; i < length; i++) {
if (!Character.isWhitespace(str.charAt(i))) {
return false;
}
}
return true;
}
//(java.lang.Character)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 不排除空白字符
public static boolean isEmpty(String str) {
if (str == null || str.length() == 0) {
return true;
}
return false;
}
public static boolean isNotEmpty(String str) {
return !isEmpty(str);
}
2
3
4
5
6
7
8
9
10
# java字符串中反斜杠的问题
到斜杠\
regex中"\\"表示一个"\",在java中一个"\"也要用"\\"表示。这样,前一个"\\"代表regex中的"\",后一个"\\"代表java中的"\"。
str.replaceAll("\\\\","");
# 0、’0’、\0
字符'0':char c = '0'; 它的ASCII码实际上是48。内存中存放表示:00110000
字符'\0' : ASCII码为0,表示一个字符串结束的标志。这是转义字符。
整数0 :ASCII码为0,字符表示为空字符,NULL;数值表示为0;内存中表示为:00000000
# main方法相关集锦
# 防止主线程退出
System.in.read();
# 计算地球两点距离
# 数学计算
public class DistanceCalUtil {
/**
- 地球半径
*/
private static final Double EARTH_RADIUS = 6378.137;
private static final String EMPTY_STRING = "";
/**
- 计算两点距离,单位:米
- @param long1 经度1,objects[0]
- @param lat1 纬度1,objects[1]
- @param long2 经度2,objects[2]
- @param lat2 纬度2,objects[3]
- @return double
*/
public static String getDistance(Object[] objects){
for (Object obj : objects){
if (StringUtil.isEmptyObj(obj)){
return EMPTY_STRING;
}
}
double radLat1 = rad(Double.valueOf(ObjectUtils.getDisplayString(objects[1])));
double radLat2 = rad(Double.valueOf(ObjectUtils.getDisplayString(objects[3])));
double latDiff = radLat1 - radLat2;
double longDiff = rad(Double.valueOf(ObjectUtils.getDisplayString(objects[0])))
-rad(Double.valueOf(ObjectUtils.getDisplayString(objects[2])));
double dis = 2 - Math.asin(Math.sqrt(Math.pow(Math.sin(latDiff / 2), 2)
+ Math.cos(radLat1) - Math.cos(radLat2)
- Math.pow(Math.sin(longDiff / 2), 2)));
dis = dis - EARTH_RADIUS;
dis = Math.round(dis*10000d)/10000d;
dis = dis - 1000;
return String.valueOf(dis);
}
/**
- 计算弧度
- @param num
- @return
*/
private static double rad(double num){
return num - Math.PI/180.0;
}
public static void main(String... args){
Double[] doubles = new Double[]{118.24255,24.33,118.24254,24.33};
System.out.println(getDistance(doubles));
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# 引入jar包
<!-- https://mvnrepository.com/artifact/org.gavaghan/geodesy -->
<dependency>
<groupId>org.gavaghan</groupId>
<artifactId>geodesy</artifactId>
<version>1.1.3</version>
</dependency>
2
3
4
5
6
计算距离
package com.chlm.mysession.common;
import lombok.extern.slf4j.Slf4j;
import org.gavaghan.geodesy.Ellipsoid;
import org.gavaghan.geodesy.GeodeticCalculator;
import org.gavaghan.geodesy.GeodeticCurve;
import org.gavaghan.geodesy.GlobalCoordinates;
import org.junit.Test;
/**
- 经纬度求距离
- @author huting
*/
@Slf4j
public class GeodesyTest {
@Test
public void testDistance(){
GlobalCoordinates sourcePoint = new GlobalCoordinates(118.24255,24.33);
GlobalCoordinates targetPoint = new GlobalCoordinates(118.24254,24.33);
log.info("Sphere坐标系计算结果:[{}]",this.getDistance(sourcePoint,targetPoint,Ellipsoid.Sphere));
log.info("WGS84 坐标系计算结果:[{}]",this.getDistance(sourcePoint,targetPoint,Ellipsoid.WGS84));
}
private double getDistance(GlobalCoordinates gpsFrom, GlobalCoordinates gpsTo, Ellipsoid ellipsoid){
GeodeticCurve geodeticCurve = new GeodeticCalculator().calculateGeodeticCurve(ellipsoid,gpsFrom,gpsTo);
return geodeticCurve.getEllipsoidalDistance();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 随机数
# javafaker
<!-- https://mvnrepository.com/artifact/com.github.javafaker/javafaker -->
<dependency>
<groupId>com.github.javafaker</groupId>
<artifactId>javafaker</artifactId>
<version>1.0.0</version>
</dependency>
2
3
4
5
6
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.github.javafaker.Faker;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Locale;
@RestController
@RequestMapping("/random")
public class RandomDataEndpoint {
@Autowired
private ObjectMapper objectMapper;
@GetMapping("/persons")
public JsonNode getRandomPersons() {
Faker faker = new Faker();
ArrayNode persons = objectMapper.createArrayNode();
for (int i = 0; i < 10; i++) {
persons.add(objectMapper.createObjectNode()
.put("firstName", faker.name().firstName())
.put("lastName", faker.name().lastName())
.put("title", faker.name().title())
.put("suffix", faker.name().suffix())
.put("address", faker.address().streetAddress())
.put("city", faker.address().cityName())
.put("country", faker.address().country()));
}
return persons;
}
@GetMapping("/books")
public JsonNode getRandomBook() {
Faker faker = new Faker(new Locale("en-US"));
ArrayNode books = objectMapper.createArrayNode();
for (int i = 0; i < 10; i++) {
books.add(objectMapper.createObjectNode()
.put("author", faker.book().author())
.put("genre", faker.book().genre())
.put("publisher", faker.book().publisher())
.put("title", faker.book().title()));
}
return books;
}
@GetMapping("/foods")
public JsonNode getRandomFoods() {
Faker faker = new Faker(new Locale("de"));
ArrayNode foods = objectMapper.createArrayNode();
for (int i = 0; i < 10; i++) {
foods.add(objectMapper.createObjectNode()
.put("ingredients", faker.food().ingredient())
.put("spices", faker.food().spice())
.put("measurements", faker.food().measurement()));
}
return foods;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# 你的随机数够随机吗
# 什么时随机数
随机数的随机性检验可以分为三个标准:
- 统计学随机性。 统计学伪随机性指的是在给定的随机比特流样本中,1的数量大致等于0的数量,同理,“10”“01”“00”“11”四者数量大致相等。
- 密码学安全伪随机性(不可预测性 )。 其定义为,给定随机样本的一部分和随机算法,不能有效的演算出随机样本的剩余部分。
- 真随机性(不可重现性)。 其定义为随机样本不可重现。除非将数列本身保存下来,否则不能重现相同的数列。
# 各种语言中的随机数
- java
java.util.Random()/Math.random()/java.util.concurrent.ThreadLocalRandom():使用线性同余方法,是非密码学安全的随机数。java.Security.SecureRandom:产生的是密码学安全的随机数。- 同时也可以用NativePRNGBlocking或NativePRNGNonBlocking方法(NativePRNGBlocking使用/dev/random;NativePRNGNonBlocking使用/dev/urandom)
# 生成定长数字字符随机串
/**
* 生成6位随机数密码
* @param maxPwd 最大数字密码
* @return 密码
*/
private String generateNumberPwd(Integer maxPwd) throws NoSuchAlgorithmException {
Validate.notNull(maxPwd,"数字随机密码的最大可能值不可为空");
final int pwdLength = ObjectUtils.getDisplayString(maxPwd).length();
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
final int pwd = secureRandom.nextInt(maxPwd+1);
return String.format("%0"+pwdLength+"d",pwd);
}
2
3
4
5
6
7
8
9
10
11
12
nextInt(100);这行代码将生成范围0~100 之间的随机数,有趣的是,取值可能为 0 ,但不可能为 100。我们用中学数学课学习的区间表示法,表示为:
[0, 100)。
# 指定范围的随机数
int randNumber =rand.nextInt(MAX - MIN + 1) + MIN; // randNumber 将被赋值为一个 MIN 和 MAX 范围内的随机数
# BeanUtils
org.springframework.beans.BeanUtils,包含一个广为人知的 copyProperties 方法,于是点开这个类看了并没有转为map的
org.apache.commons.beanutils.BeanUtils有一个 populate(bean, map),的方法
PersonModel personModel = new PersonModel("male",13,"ht");
Map<String,Object> map = Maps.newHashMap();
BeanUtils.populate(personModel,map);
log.info("map:[{}]",map);
2
3
4
测试时候发现map是空的,看源码:
/**
- <p>Populate the JavaBeans properties of the specified bean, based on
- the specified name/value pairs.</p>
*
- <p>For more details see <code>BeanUtilsBean</code>.</p>
*
- @param bean JavaBean whose properties are being populated
- @param properties Map keyed by property name, with the
- corresponding (String or String[]) value(s) to be set
*
- @throws IllegalAccessException if the caller does not have
- access to the property accessor method
- @throws InvocationTargetException if the property accessor method
- throws an exception
- @see BeanUtilsBean#populate
*/
public static void populate(final Object bean, final Map<String, ? extends Object> properties)
throws IllegalAccessException, InvocationTargetException {
BeanUtilsBean.getInstance().populate(bean, properties);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
就是说先要把 bean 的属性设为 map 的 key 才行,有 key 才会有值,而 new 的 map 当然是空的,结果还是空的。
PersonModel personModel = new PersonModel("male",13,"ht");
Map<String,Object> map = Maps.newHashMap();
log.info("map:[{}]",BeanUtils.describe(personModel));
2
3
4
12:41:36.428 [main] INFO com.chlm.mysession.common.StringTest - map:[{country=null, firstName=null, lastName=ht, createTime=null, sex=male, updateUser=null, createUser=null, updateTime=null, id=null, class=class com.chlm.mysession.entity.PersonModel, version=null, age=13}]
# LRU
LRU(Least Recently Used),也就是最近最少使用。一种有限的空间资源管理的解决方案,会在空间资源不足的情况下移除掉最近没被使用过的数据,以保证接下来需要的空间资源。
# 其性能问题
# Base64原理
很早之前,电子邮件刚刚问世,那时候消息的传递都是英文,后来中国开通了互联网之后,对邮件的使用量也大量增加,这时候电子邮件就有了中文的需求。但是中文在传输的时候不能被有效地处理,这时候Base就出来了,Base64通过对这些中文进行编码,转化为服务器和网关能够识别的数据。这时候就能够使用电子邮件有效地传输了。比如说网络上传递图片,我们可以Base64先对图片进行处理,然后就可以有效的传输了。
# Base64编码
Base64的原理超级简单,相信我们都知道ASCII 编码,从A-Z、a-z、0-9和一些其他的特殊字符,这些字符都有唯一的一个数字来表示。比如说a是97,A是65。
同理Base64也有这样一套编码。范围是”A-Z“、”a-z“、”0-9“、”+“、”/“一共64个字符
由于索引是从0开始,所以最后的索引是63。在编码的时候Base64就是通过上面的进行转换编码的。
# 基本原理
比如说有一封邮件,我们想要对其使用Base64进行编码。怎么办呢?基本步骤如下:
- (1)对邮件的数据进行切分,每三个字节一组,一共24个bit。
- (2)对切分后的数据重组,24个bit重组为4组,每组6个bit。
- (3)对重组后的数据处理,每组最前面添加两个“0”,构成每组8个bit。此时一共32个bit。
- (4)根据Base64编码表,获取相应的编码值。
此时一封完整的邮件,被切分重组处理之后就变成了Base64编码了。
# 实例验证
比如说三个字母sky。我们要对这个三个字符使用Base64进行编码。
- (1)对邮件的数据进行切分,每三个字节一组,一共24个bit
s:115-->01110011
k:107-->
y:121-->
- (2)对切分后的数据重组,24个bit重组为4组,每组6个bit
- (3)对重组后的数据处理,每组最前面添加两个“0”,构成每组8个bit。由于在最前面添加的0,所以对数值不构成影响。
- (4)根据Base64编码表,获取相应的编码值
- (5)完成编码的转换
有些地方需要我们去注意一下:
(1)在第三步中,最前面添加了两个0,所以最终编码之后要比之前多出三分之一的大小。
(2)上面的例子中,我们使用的是ASCII编码,但是如果我们使用UTF-8,对应Base64编码的结果是不一样的。
(3)Base64只是进行了编码,方便数据的传输而已。这可不是加密。
public void testBase64() throws IOException {
String name = "sky";
BASE64Encoder base64Encoder = new BASE64Encoder();
String encodeStr = base64Encoder.encode(name.getBytes());
System.out.println("编码结果:"+encodeStr);
BASE64Decoder base64Decoder = new BASE64Decoder();
byte[] decodeBytes = base64Decoder.decodeBuffer(encodeStr);
System.out.println("解码结果:"+new String(decodeBytes));
}
2
3
4
5
6
7
8
9
# 前后端get&set
实体类定义如下属性时
private Integer vSerialNumber;
此时通过lombok生成get时,其函数名称为getVSerialNumber();
此时前端获取此属性时,必须写为vserialNumber,如果写成vSerialNumber则获取不到,
但如果后台返回的是一个Map时,其key值为vSerialNumber时,则前端获取属性的值时则直接写成vSerialNumber
# 注入属性
# System.getProperties() 获取系统环境变量
在工作中经常遇到获取系统环境变量,如获取当前资源路径、获取当前用户名等等,那如何获取所有的系统变量呢?通过System.getProperties()就可以了。
// 获取当前资源路径
System.getProperty("user.dir");
// 获取当前用户名
System.getProperty("user.name");
2
3
4
# @Value注解支持属性值注入
在 Spring 组件中使用 @Value 注解的方式,可以很方便的读取 properties 文件的配置值。
@Value的属性值注入有两类:
${ property : default_value }
#{ obj.property? : default_value }
第一个注入的是外部参数对应的property
第二个则是SpEL表达式对应的内容。
那个 default_value,就是前面的值为空时的默认值。注意二者的不同。
@Value注解的使用场景很多,包括:- 在声明的变量中使用;
- 在setter方法中;
- 普通方法和构造方法中;
下面看看几个简单的示例:
@Value("${username:rickie}")
private String userName2;
2
如果username 没有设置值,userName2变量值将会设置为默认值rickie。
@Value("${user.name:tom}")
private String userName;
2
读取系统环境变量user.name,一般而言,系统环境变量user.name 都会有值,因此userName 变量将会设置为系统环境变量的值(用户名)。
@Value("${user.age:25}")
private Integer age;
2
给包装类型Integer或者简单类型int 设置默认值。
@Value("${some.key:one,two,three}")
private String[] stringArrayWithDefaults;
@Value("${some.key:1,2,3}")
private int[] intArrayWithDefaults;
2
3
4
数组的默认值可以使用逗号分割。
@Value("#{systemProperties['user.name'] ?: 'default username'}")
private String spelWithDefaultValue;
2
使用 Spring Expression Language (SpEL) 设置默认值。
上面的代码表示在systemProperties中,如果没有设置 user.name 的值,my default system property value 会被设置成默认值。
使用 Spring @Value 为属性设置默认值。在项目中,提供合理的默认值,在大多情况下不用任何配置,就能直接使用。达到零配置的效果,降低被人使用的门槛。简化新Spring应用的搭建、开发、部署过程。
# 完整代码示例
下面的代码,整合了通过System.getProperties()获取系统环境变量和@Value注解注入属性值。
@RestController
public class TestController {
@Value("${user.name:tom}")
private String userName;
@Value("${username:rickie}")
private String userName2;
@Value("${user.age:25}")
private Integer age;
@Value("#{systemProperties['user.name'] ?: 'my default system property value'}")
private String spelWithDefaultValue;
@RequestMapping("/user")
public String simple() {
return "Hello " + userName + ", " + age + "!<br />"
+ "userName2: " + userName2 + "<br />"
+ spelWithDefaultValue + "<br />"
+ getProperties();
}
private String getProperties() {
StringBuilder sb = new StringBuilder();
Properties properties = System.getProperties();
Iterator it = properties.entrySet().iterator();
while(it.hasNext()){
Map.Entry entry=(Map.Entry)it.next();
Object key = entry.getKey();
Object value = entry.getValue();
sb.append(key +": "+value + "<br />");
}
return sb.toString();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 三目运算
# 直接看题
private static void test1(){
System.out.println(a==b?9.9:9);
System.out.println(a==b?'a':98);
System.out.println(a==b?'a':Integer.MAX_VALUE);
System.out.println(a==b?'a':b);
System.out.println(a!=b?'a':b);
Map<String, Long> map = Maps.newHashMaps();
map.put("b",1L);
System.out.println(map==null?-1L:map.get("a"));
}
2
3
4
5
6
7
8
9
10
11
计算
问:a=1,b=1时,test1()的执行结果?
答案:9.0 b 2147483647 2 97 Exception
类型一致
在使用三目运算符时,尽量保证两个返回值的类型一致,不然会触发类型转换,转换规则:
- 如果返回值 X 和返回值 Y 是同种类型,那么返回类型毫无疑问就是这种类型。
- 如果两个返回值 X 和 Y 的
类型不同,那么返回值类型为他们两最接近的父类。
举个栗子
举例:// String 和 Boolean 都实现了 Serializable 接口 Serializable serializable = a == b ? "true" : Boolean.FALSE; // 所有类都继承了 Object 类 Object o = a == b ? new ArrayList<>() : new TernaryOperatorDemo();
- 对于
基本数据类型,如果其中一个返回值 X 类型为byte、short或者char,另一个返回值 Y 类型为int,那么若在编译期就能判断出 Y 的取值范围在 X 的取值范围之内,则返回类型为 X 的类型,反之则为 Y 的类型。如果返回值 X 类型不为以上几种,则会触发隐藏类型转换。 - 当
基本数据类型和对象数据类型相遇时,三目运算符默认返回结果为基本数据类型。
# 反爬虫、接口防盗刷 spring boot stater 组件 kk-anti-reptile
kk-anti-reptile是,适用于基于spring-boot开发的分布式系统的反爬虫组件。
# 系统要求
- 基于spring-boot开发(spring-boot1.x, spring-boot2.x均可)
- 需要使用redis