后端开发知识点整理汇总

背景介绍

  • 本文主要是对Java后端日常开发常用的知识做一些整理,以便使用时查看。

Java8 Lambda编程

  • 为什么lambda表达式使用的局部变量要是final的
    • 为什么 Lambda 表达式(匿名类) 不能访问非 final 的局部变量呢?
    • 因为实例变量存在堆中,而局部变量是在栈上分配,Lambda 表达(匿名类) 会在另一个线程中执行。如果在线程中要直接访问一个局部变量,可能线程执行时该局部变量已经被销毁了,而 final 类型的局部变量在 Lambda 表达式(匿名类) 中其实是局部变量的一个拷贝,因为之前的存放在栈中(lambda表达式在其他线程运行的时候可能栈已经释放了),所以必须要拷贝出一份来。
    • 在Lambda表达式中可以捕获静态变量和实例变量,但是如果想要捕获局部变量的时候就需要声明成final的,即使我们不主动声明,编译器也会为我们自动声明成final的,不能再重新赋值。也就是Lambda表达式中访问的局部变量(隐式被声明为final的)是可读不可写的,但是Lambda表达式中访问的实例变量和静态变量是可读可写的。
  • java8将list转为map
public Map<Long, String> getIdNameMap(List<Account> accounts) {
    return accounts.stream().collect(Collectors.toMap(Account::getUserId, Account::getUsername));
}
  • 将实体对象转换成Map
public Map<Long, Account> getIdAccountMap(List<Account> accounts) {
   return accounts.stream().collect(Collectors.toMap(Account::getId, account -> account));
}

public Map<Long, Account> getIdAccountMap(List<Account> accounts) {
    return accounts.stream().collect(Collectors.toMap(Account::getId, Function.identity()));
}
  • 将List转换为Map,其中Map的key为指定的,value为List对象
Map<String,List<VehicleVO>> vOMap = vehicleVOList.stream()
                .collect(Collectors.groupingBy(XXXVO::getPlateNo));
  • filter筛选条件
//过滤出并返回符合filter筛选条件的;
list.stream().filter(x->x.indexOf(keyword) >= 0).collect(Collectors.toList());
  • 指定具体收集的map
public Map<String, Account> getNameAccountMap(List<Account> accounts) {
    return accounts.stream().collect(Collectors.toMap(Account::getUsername, Function.identity(), (key1, key2) -> key2, LinkedHashMap::new));
}

toMap还有另一个重载方法,可以指定一个Map的具体实现,来收集数据:

  • 对List中的元素进行分组
 Map<String,List<TestVO>> result = testList.stream().collect(Collectors.groupingBy(e->e.getName()));
  • 移除List中的重复元素
protected final <T> List<T> removeDuplicates(List<T> list) {
        return new ArrayList(new LinkedHashSet(list));
 }
  • 获取List中的最小值/最大值
String minStartValidTimeStr = testList.stream().min(String::compareTo).get();
  • Lambda表达式中解决计数的问题
/**
 * 定义外部计数类
 */
class CountOuter {
    private int i = 0;
    private final List<String> testList = new ArrayList<>();
    public Integer count() {
        return i++;
    }
    public Integer getCount() {
        return i;
    }
    public void addElementToList(String testId) {
        testList .add(testId);
    }
    public List<String> getList() {
        return testList;
    }
}

在代码中使用上述外部类:

 CountOuter countOuter = new CountOuter();
 totalMap.put(tet.getPlateNo(),countOuter.getCount());
 List<String> testIdList = countOuter.getList();

Gson使用

  • 使用gson 使用gson 将json字符串转换为List<Map<String,object>> 数组
List<Map<String, Object>> resultList= new Gson().fromJson(objListStr, new TypeToken<List<Map<String, Object>>>(){}.getType()); 
  • Gson创建
Gson gson1 = new GsonBuilder().setPrettyPrinting().serializeNulls().create();
Foo foo = new Foo();
String json1 = gson1.toJson(foo);
  • Gson使用示例
public class Sample {
    public static void main(String[] args) {
        String json = "{\"nestedPojo\":[{\"name\":null, \"value\":42}]}";
        Gson gson = new Gson();
        gson.fromJson(json, Pojo.class);
    }
}

class Pojo {
    NestedPojo nestedPojo;
}

class NestedPojo {
    String name;
    int value;
}

{
    "nestedPojo": [
        {
            "name": null,
            "value": 42
        }
    ]
}

class Custom implements JsonDeserializer<NestedPojo> {
    @Override
    public NestedPojo deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        NestedPojo nestedPojo = new NestedPojo();
        JsonArray jsonArray = json.getAsJsonArray();
        if (jsonArray.size() != 1) {
            throw new IllegalStateException("unexpected json");
        }
        JsonObject jsonObject = jsonArray.get(0).getAsJsonObject(); // get only element
        JsonElement jsonElement = jsonObject.get("name");
        if (!jsonElement.isJsonNull()) {
            nestedPojo.name = jsonElement.getAsString();
        }
        nestedPojo.value = jsonObject.get("value").getAsInt();
        return nestedPojo;
    }
}

Gson gson = new GsonBuilder().registerTypeAdapter(NestedPojo.class, new Custom()).create();

Jackson中ObjectMapper属性设置

ObjectMapper om = new ObjectMapper();
// 属性为Null的不进行序列化,只对pojo起作用,对map和list不起作用
om.setSerializationInclusion(JsonInclude.Include.NON_NULL);
// json进行换行缩进等操作
om.enable(SerializationFeature.INDENT_OUTPUT);
// json不进行换行缩进等操作  默认就是不进行操作,写了这行和没写的效果一样
om.disable(SerializationFeature.INDENT_OUTPUT);
// json是否允许属性名没有引号 ,默认是false
om.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
//json是否允许属性名为单引号 ,默认是false
om.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
// 遇到未知属性是否抛出异常 ,默认是抛出异常的
om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// 当实体类没有setter方法时,序列化不报错,返回一个空对象
om.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
// 所有的字母小写,下划线作为名字之间分隔符,例如 snake_case
om.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
// 所有名字(包括第一个字符)都以大写字母开头,后跟小写字母,没有分隔符,例如 UpperCamelCase
om.setPropertyNamingStrategy(PropertyNamingStrategy.UPPER_CAMEL_CASE);
// 第一个单词以小写字母开头,后续每个单词都是大写字母开头,没有分隔符,例如 lowerCamelCase
om.setPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CAMEL_CASE);
// 所有的字母小写,没有分隔符,例如 lowercase
om.setPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CASE);
// “Lisp” 风格,采用小写字母、连字符作为分隔符,例如 “lower-case” 或 “first-name”
om.setPropertyNamingStrategy(PropertyNamingStrategy.KEBAB_CASE);
  • 使用jackson时过滤null值
  1. 方法一:使用yml配置方式
spring:
  jackson:
    default-property-inclusion: non_null
  1. 方法二:使用Bean注入方式配置
@Configuration
public class MyJacksonConfig {
    @Bean
    @Primary
    @ConditionalOnMissingBean(ObjectMapper.class)
    public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder)
    {
        ObjectMapper objectMapper = builder.createXmlMapper(false).build();
        // 通过该方法对mapper对象进行设置,所有序列化的对象都将按改规则进行系列化
        // Include.Include.ALWAYS 默认
        // Include.NON_DEFAULT 属性为默认值不序列化
        // Include.NON_EMPTY 属性为 空("") 或者为 NULL 都不序列化,则返回的json是没有这个字段的。这样对移动端会更省流量
        // Include.NON_NULL 属性为NULL 不序列化
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 允许出现单引号
        objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        return objectMapper;
    }
}

Java知识整理

  • BigDecimal相加
BigDecimal b1 = BigDecimal.ZERO;
BigDecimal b2 = BigDecimal.valueOf(3);
b2 = b2.add(b1); // 这样写的话会把新的对象赋值给b2
b2.add(b1);      // 这样的话b2是不会变化的 

Java8日期使用

  • java8字符串转LocalDateTime
String param;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime nowDate = LocalDateTime.parse(param,formatter);
  • 计算两个LocalDateTime的时间差
		LocalDateTime nowDate =  LocalDateTime.now();
        int interval = 5;
        LocalDateTime before3HourOfNow = nowDate.minus(interval, ChronoUnit.HOURS);
        long hoursInterval = ChronoUnit.HOURS.between( before3HourOfNow,nowDate);

        Duration duration = Duration.between(before3HourOfNow, before3HourOfNow);
        duration.toDays();

序列化/反序列化

  • transient 关键字修饰的属性不会被序列化, static 属性也不会被序列化.

泛型

  1. 泛型方法的概念
    方法的参数类型是泛型,而不是具体的参数。
    注意:是方法的参数是泛型,而不是方法的返回值。

  2. 泛型方法的定义格式

[访问权限] <泛型> 返回值类型 方法名([泛型标识 参数名称]){方法体;}
  1. 泛型方法实例
public <T2> void printArray(T2[] arr){}

以上方法就是泛型方法,方法的参数是一个数组,但是这个数组存放的数据类型不是具体的,而是一个泛型。另外,因为这个T2泛型是我们自己定义的,不是Java官方的
所以为了表示T2也是一种泛型标识,需要在方法的前面也需要添加泛型,用于告诉编译器T2表示泛型。

  • 注:泛型的类型参数使用大写形式,且比较短,一般一个字母,这是很常见的。在java库中,使用变量E表示集合的元素类型。KV分别表示键与值的类型,比如:Map的键与值。T(需要时还可以用临近的字母US)表示“任意类型”。

CURL 用法整理

  • 发送POST请求
curl -H "Content-Type: application/json" 
-X POST 
-d '{"user_id": "123", "coin":100, "success":1, "msg":"OK!" }' 
"http://<HTTP地址>:8001/test" -v

参数 内容
-H 请求头
-d POST内容
-X 请求协议

  • 使用示例
    详细的请求信息,需要加上 -v 参数
  • 使用示例
curl -H "token:test string" -X GET https://test address?lng=11.67&lat=39.5254

curl的请求头中有多个参数:

curl -H "token:xxxx,map:true" -X GET http://test.aaa.com/bbb?location=120.88,41.99
curl -H "Content-Type:application/json"  -H "Authorization:aaa" -X POST --data '{"number":"京F58XX","startTime":"2021-05-13 00:32:27","endTime":"2021-05-15 00:32:27"}' http://xxxx.com/xxxx/common/xxxx

查看建表语句

show create table 表名;  
show full COLUMNS from 表名;
describe 表名;

反射

  • 获取反射中的Class对象
    • 在反射中,要获取一个类或调用一个类的方法,我们首先需要获取到该类的 Class 对象。
      Java API 中,获取 Class 类对象有三种方法:
  • 第一种,使用 Class.forName 静态方法。当你知道该类的全路径名时,你可以使用该方法获取 Class 类对象。
Class clz = Class.forName("java.lang.String");
  • 第二种,使用 .class 方法。这种方法只适合在编译前就知道操作的 Class
Class clz = String.class;
  • 第三种,使用类对象的 getClass() 方法。
String str = new String("Hello");
Class clz = str.getClass();
  • 通过反射创建类对象
    通过反射创建类对象主要有两种方式:
    • 通过 Class 对象的 newInstance() 方法、
    • 通过 Constructor 对象的 newInstance() 方法。
  • 第一种:通过 Class 对象的 newInstance() 方法。
Class clz = Apple.class;
Apple apple = (Apple)clz.newInstance();
  • 第二种:通过 Constructor 对象的 newInstance() 方法
Class clz = Apple.class;
Constructor constructor = clz.getConstructor();
Apple apple = (Apple)constructor.newInstance();
  • 通过 Constructor 对象创建类对象可以选择特定构造方法,而通过 Class 对象则只能使用默认的无参数构造方法。下面的代码就调用了一个有参数的构造方法进行了类对象的初始化。
Class clz = Apple.class;
Constructor constructor = clz.getConstructor(String.class, int.class);
Apple apple = (Apple)constructor.newInstance("红富士", 15);
  • 与获取类属性一样,当我们去获取类方法、类构造器时,如果要获取私有方法或私有构造器,则必须使用有 declared 关键字的方法。
  • 反射获取method对象示例
Class clz = Class.forName("目录名.Apple");
//获取类中指定名称对应的method对象
Method method = clz.getMethod("setPrice", int.class);
Constructor constructor = clz.getConstructor();
Object object = constructor.newInstance();
method.invoke(object, 4);
 public void setPrice(int price) {
        this.price = price;
    }
Method method = clz.getMethod("setPrice", int.class); 
method.invoke(object, 4);   //就是这里的invoke方法

注意:getMethod方法中的第一个参数为方法名称,第二个参数表示获取的方法的入参类型

判断两个包装类型是否相等

		// 2)两个包装类型
        Integer c = 100;
        Integer d = 100;
        System.out.println(c == d);   //结果:true

        // 3)
        c = 200;
        d = 200;
        System.out.println(c == d);   //结果:false

Integer中:-128 到 127 之间的数会从 IntegerCache 中取,然后比较,所以第二段代码(100 在这个范围之内)的结果是 true,而第三段代码(200 不在这个范围之内,所以 new 出来了两个 Integer 对象)的结果是 false

欢迎关注我的微信公众号ItBeeCoder

在这里插入图片描述

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Web后端开发是指构建和维护Web应用程序的服务器端部分。它涉及处理请求、数据存储、业务逻辑和与前端交互等任务。下面是一些Web后端开发的基础知识: 1. 编程语言:常见的后端开发语言Java、Python、PHP、Ruby、Node.js等。选择一种语言开发后端需要考虑其性能、可扩展性和适用场景。 2. 服务器:后端应用程序在服务器上运行。常见的Web服务器软件包括Apache、Nginx、IIS等。这些服务器可以处理HTTP请求并将其路由到相应的后端应用程序。 3. 框架:后端开发常使用框架来简化开发过程。框架提供了一组工具和类库,帮助开发人员处理常见的任务,如路由请求、处理表单数据、数据库交互等。常见的后端框架有Spring(Java)、Django(Python)、Laravel(PHP)等。 4. 数据库:后端应用程序通常需要与数据库进行交互来存储和检索数据。常见的关系型数据库有MySQL、PostgreSQL、Oracle等;非关系型数据库有MongoDB、Redis等。 5. RESTful API:后端开发中,API(Application Programming Interface)起着关键的作用,它定义了前端和后端之间的通信接口。RESTful API是一种常见的API设计风格,它使用HTTP协议的GET、POST、PUT、DELETE等动词来操作资源。 6. 安全性:后端开发需要考虑应用程序的安全性。常见的安全措施包括身份验证、访问控制、数据加密等。 7. 测试与调试:后端开发需要进行测试和调试,以确保应用程序的正确性和稳定性。常见的测试方法包括单元测试、集成测试和端到端测试。 这些是Web后端开发的基础知识,希望能对你有所帮助。如果你有具体的问题或需要更深入的了解,请随时提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值