美文网首页
2020 java 面试专题记录

2020 java 面试专题记录

作者: 痴痴爱码字 | 来源:发表于2020-08-21 09:41 被阅读0次

面试专题

Java体系

stream流

  • 大白话理念 :
    Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。
    Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。
    这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等
  • ==集合接口分为 串行流stream() 和 并行流parallelStream() ==
  • 主要分为 中间操作和最终操作
    • 中间操作:
      • 过滤类型 : ==filter(过滤),distinct(去重),limit(限流)==,skip(跳过)
      • 映射 : ==map==,flatMap
    • 最终操作 :
      • 查找 : ==allMatch,anyMatch==,noneMathch,findFirst,findAny
      • 归约 : ==reduce==
      • 收集 : ==counting(总数), maxBy(最大值), minBy(最小值), summingInt, summingLong, summingDouble(求和), averageInt, averageLong,== ==averageDouble(平均数),== summarizingInt, summarizingLong, summarizingDouble(一次性查询元素个数、总和、最大值、最小值和平均值),==joining(字符串拼接), groupingBy(分组),== partitioningBy(分区)

lambda和接口

接口的默认方法 :

  • 默认方法允许我们在接口里添加新的方法,而不会破坏实现这个接口的已有类的兼容性,也就是说不会强迫实现接口的类实现默认方法
    默认方法和抽象方法的区别是抽象方法必须要被实现,默认方法不是。作为替代方式,接口可以提供一个默认的方法实现,所有这个接口的
    实现类都会通过继承得倒这个方法(如果有需要也可以重写这个方法)
  • 默认方法是可以在接口中写执行体的。主要作用:
    • 1.接口升级,可以避免改变其他实现类。
    • 2.函数拼接
public interface Animal {
    default void fly() {
        System.out.println("birds can fly...");
    }

    default void swim() {
        System.out.println("fishes can swim......");
    }
}

public class Bird implements Animal {
}

public class TestMain {

    public static void main(String[] args) {

        Bird bird = new Bird();
        bird.fly();

        Fish fish = new Fishe();
        fish.swim();
    }
}

接口的静态方法 :

  • 因为静态方法不可以实例化,在接口中也是一样的
  • 所以在接口中定义静态方法的作用就是静态方法的作用:
  • 不需要实例化,直接使用,节省内存空间
  • 注意:接口中静态方法和类中静态方法一样,只能通过接口.静态方法名的方式调用
public interface AnimalFactory {

    static Animal create(Supplier<Animal> supplier) {
        return supplier.get();
    }
}

public class TestAnimalFactory {

    public static void main(String[] args) {
        // 生产一只鸟
        Animal bird = AnimalFactory.create(Bird::new);
        bird.fly();
     // 生产一条鱼
        Animal fish = AnimalFactory.create(Fishe::new);
        fish.swim();
    }
}

函数式接口

  • 每一个lambda表达式都对应一个类型,通常是接口类型。而“函数式接口”是指仅仅只包含一个抽象方法的接口,每一个该类型的lambda表达式都会被匹配到这个抽象方法。因为 默认方法 不算抽象方法,所以你也可以给你的函数式接口添加默认方法。
  • JDK 1.8 之前已有的函数式接口:
    • java.lang.Runnable
    • java.util.concurrent.Callable
    • java.security.PrivilegedAction
    • java.util.Comparator
    • java.io.FileFilter
    • java.nio.file.PathMatcher
    • java.lang.reflect.InvocationHandler
    • java.beans.PropertyChangeListener
    • java.awt.event.ActionListener
    • javax.swing.event.ChangeListener
  • JDK 1.8 新增加的函数接口:
    • java.util.function
@FunctionalInterface
interface GreetingService 
{
    void sayMessage(String message);
}

Lambda 表达式

  • Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。
  • ambda表达式的重要特征:
    • 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
    • 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
    • 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
    • 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。
// 1. 不需要参数,返回值为 5  
() -> 5  
  
// 2. 接收一个参数(数字类型),返回其2倍的值  
x -> 2 * x  
  
// 3. 接受2个参数(数字),并返回他们的差值  
(x, y) -> x – y  
  
// 4. 接收2个int型整数,返回他们的和  
(int x, int y) -> x + y  
  
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)  
(String s) -> System.out.print(s)
public class Java8Tester {
   public static void main(String args[]){
      Java8Tester tester = new Java8Tester();
        
      // 类型声明
      MathOperation addition = (int a, int b) -> a + b;
        
      // 不用类型声明
      MathOperation subtraction = (a, b) -> a - b;
        
      // 大括号中的返回语句
      MathOperation multiplication = (int a, int b) -> { return a * b; };
        
      // 没有大括号及返回语句
      MathOperation division = (int a, int b) -> a / b;
        
      System.out.println("10 + 5 = " + tester.operate(10, 5, addition));
      System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction));
      System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication));
      System.out.println("10 / 5 = " + tester.operate(10, 5, division));
        
      // 不用括号
      GreetingService greetService1 = message ->
      System.out.println("Hello " + message);
        
      // 用括号
      GreetingService greetService2 = (message) ->
      System.out.println("Hello " + message);
        
      greetService1.sayMessage("Runoob");
      greetService2.sayMessage("Google");
   }
    
   interface MathOperation {
      int operation(int a, int b);
   }
    
   interface GreetingService {
      void sayMessage(String message);
   }
    
   private int operate(int a, int b, MathOperation mathOperation){
      return mathOperation.operation(a, b);
   }
}

执行结果:
$ javac Java8Tester.java 
$ java Java8Tester
10 + 5 = 15
10 - 5 = 5
10 x 5 = 50
10 / 5 = 2
Hello Runoob
Hello Google

Lambda 作用域 :

lambda 表达式只能引用标记了 final 的外层局部变量,这就是说不能在 lambda 内部修改定义在域外的局部变量,否则会编译错误。


springboot 框架

springboot 1.x 和 2.x 的区别

  • 2.x 至少需要 JDK 8 的支持
  • 2.x 增加响应式 Spring 编程支持
  • 2.x 增加 HTTP/2 支持
  • 部分配置有改动

Spring Boot @RestController和@controller有什么区别?

  • @RestController注解相当于@ResponseBody + @Controller合在一起的作用,返回的是json或文本数据。
  • @Controller 可以配合视图解析器进行路由控制

Spring Boot 的配置文件有哪几种格式?它们有什么区别?

  • .properties 和 .yml,它们的区别主要是书写格式不同。

Spring Boot 自动配置原理是什么?

  • 注解 @EnableAutoConfiguration, @Configuration, @ConditionalOnClass 就是自动配置的核心,首先它得是一个配置文件,其次根据类路径下是否有这个类去自动配置。

Spring Boot 有哪几种读取配置的方式?

  • Spring Boot 可以通过 @PropertySource,@Value,@Environment, @ConfigurationProperties 来绑定变量

Mybatis 框架

#{}和${}的区别是什么?

  • {}是预编译处理,${}是字符串替换。

  • Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;
  • Mybatis在处理{}时,就是把{}替换成变量的值。
  • 使用#{}可以有效的防止SQL注入,提高系统安全性。

当实体类中的属性名和表中的字段名不一样 ,怎么办 ?

  • 通过在查询的sql语句中定义字段名的别名,让字段名的别名和实体类的属性名一致。
  • 通过<resultMap>来映射字段名和实体类属性名的一一对应的关系。

模糊查询like语句该怎么写?

  • like concat('%', #{name}, '%') 有效防止SQL注入

如何执行批量插入?

  • 使用<foreach>

如何获取自动生成的(主)键值?

  • <inset usegeneratedkeys=”true” keyproperty=”id”>

在mapper中如何传递多个参数?

  • 在映射文件中使用#{0},#{1}代表传递进来的第几个参数
  • 使用@param注解:来命名参数
  • 使用Map集合作为参数来装载

接口绑定有几种实现方式,分别是怎么实现的?

  • 接口绑定有两种实现方式:
    • 通过注解绑定,在接口的方法上面加上@Select@Update等注解里面包含Sql语句来绑定
    • 通过xml里面写SQL来绑定,在这种情况下,要指定xml映射文件里面的namespace必须为接口的全路径名.

Mysql

mysql优化

  • ==字段类型选择尽可能小(占用存储空间少)、尽可能定长(占用存储空间固定)、尽可能使用整数。==
  • ==索引 首先应考虑在 where 及 order by 涉及的列上建立索引。==
  • 少用(不用)多表操作(子查询,联合查询),而是将复杂的SQL拆分多次执行。如果查询很原子(很小),会增加查询缓存的利用率。
  • 分页查询优化 在子查询中只查询数据的id并分页 然后根据子查询的id在进行查询完整数据
  • ==使用join 代替 子查询==
  • ==对查询单条是 添加limit 1==
  • ==不要在列上进行运算==
  • 不使用NOT IN和<>操作 NOT IN可以NOT EXISTS代替,id<>3则可使用id>3 or id<3来代替。
  • 应尽量避免在 where 子句中使用 or 来连接条件,如果一个字段有索引,一个字段没有索引,将导致引擎放弃使用索引而进行全表扫描
    select id from t where num=10 or Name = 'admin'
    #可以这样查询:
    select id from t where num = 10
    union all
    select id from t where Name = 'admin'
  • ==exists 代替 in==
  • 分页时每页条数过大时 要先分页再JOIN
  • ==不要使用 select *==
  • ==如何避免死锁==
    • 注意程序的逻辑
        根本的原因是程序逻辑的顺序,最常见的是交差更新
    
        Transaction 1: 更新表A -> 更新表B
        
        Transaction 2: 更新表B -> 更新表A
        
        这类问题要从程序上避免,所有的更新需要按照一定的顺序
    
    • 保持事务的轻量
      • 提高运行的速度
      • 尽量快提交事务,减少持有锁的时间
    • 设置锁等待超时参数,我们可以通过 innodb_lock_wait_timeout 设置合理的等待超时阈值,特别是在一些高并发的业务中,我们可以尽量将该值设置得小一些,避免大量事务等待,占用系统资源,造成严重的性能开销。

redis

常用数据类型

  • String(字符串):Redis最基本的数据类型,一个键对应一个值,一个键值最大存储512MB
  • Hash(哈希):hash是一个键值对的集合,是一个String类型的field和value的映射表,适合用于存储对象.可用作简易的消息队列
  • List(列表):是redis的简单的字符串列表,按插入顺序排序
  • Set(集合):是String字符串类型的无序集合,也不可重复
  • ZSet(sorted set 有序集合)是String类型的有序集合,也不可重复。有序集合中的每个元素都需要指定一个分数,根据分数对元素进行升序排序。可以做排行榜

Redis应用场景,能做什么

  1. 数据缓存(最常用)
  2. 会话session管理器(最常用)
  3. 消息队列(支付)
  4. 活动排行榜或计数
  5. 发布,订阅消息(消息通知)
  6. 商品列表,评论列表

缓存穿透

  • 描述:缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大
  • 解决方案:
    • 接口层增加校验,如使用布隆过滤器封装全部id ,查询时 先去redis查询,如果没有,再去查看布隆过滤器中是否存在. 如果不存在直接返回 存在再到数据库中进行查询;
    • 从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击

缓存击穿

  • 描述:缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力
  • 解决方案
    • 设置热点数据永远不过期
    • 加互斥锁

缓存雪崩

  • 描述:缓存雪崩是指缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机。和缓存击穿不同的是, 缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。
  • 解决方案
    • 缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
    • 如果缓存数据库是分布式部署,将热点数据均匀分布在不同搞得缓存数据库中。
    • 设置热点数据永远不过期。

布隆过滤器

Memcache与Redis的区别都有哪些?

  • 存储方式 Memecache把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小。 Redis有部份存在硬盘上,redis可以持久化其数据
  • 数据支持类型 memcached所有的值均是简单的字符串,redis作为其替代者,支持更为丰富的数据类型 ,提供list,set,zset,hash等数据结构的存储
  • redis的速度比memcached快很多
    -Redis支持数据的备份,即master-slave模式的数据备份。

单线程的redis为什么这么快

  • 纯内存操作
  • 单线程操作,避免了频繁的上下文切换
  • 采用了非阻塞I/O多路复用机制

如果redis没有设置expire,他是否默认永不过期?

  • Redis无论有没有设置expire,他都会遵循redis的配置好的删除机制,在配置文件里设置:
    redis最大内存不足"时,数据清除策略,默认为"volatile-lru"。
    • volatile-lru ->对"过期集合"中的数据采取LRU(近期最少使用)算法.如果对key使用"expire"指令指定了过期时间,那么此key将会被添加到"过期集合"中。将已经过期/LRU的数据优先移除.如果"过期集合"中全部移除仍不能满足内存需求,将OOM.
    • allkeys-lru ->对所有的数据,采用LRU算法
    • volatile-random ->对"过期集合"中的数据采取"随即选取"算法,并移除选中的K-V,直到"内存足够"为止. 如果如果"过期集合"中全部移除全部移除仍不能满足,将OOM
    • allkeys-random ->对所有的数据,采取"随机选取"算法,并移除选中的K-V,直到"内存足够"为止
    • volatile-ttl ->对"过期集合"中的数据采取TTL算法(最小存活时间),移除即将过期的数据.
    • noeviction ->不做任何干扰操作,直接返回OOM异常

Redis 部署方式

  • 单机
  • 哨兵
  • 集群

分布式锁

  • 加锁 : 使用SETNX, 只在键 key 不存在的情况下, 将键 key 的值设置为 value 。
    若键 key 已经存在, 则 SETNX 命令不做任何动作。
    SETNX 是『SET if Not eXists』(如果不存在,则 SET)的简写。
  • 解锁 : 使用lua脚本 避免死锁

Redis的持久化

  • Redis持久有两种方式:快照(RDB),仅附加文件(AOF)

Redis 发布订阅

  • Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。
  • Redis 客户端可以订阅任意数量的频道。

linux

常用命令

  • ls : 展示文件夹内内容
  • cd : 切换到目录
  • tree : 显示树形的层级目录结构,非原生命令,需要安装tree
  • cp : 复制文件
  • rm : 删除文件
  • mv : 移动文件
  • pwd : 显示当前所在实际路径
  • tar : 压缩解压
  • mkdir : 创建目录
  • rmdir : 删除目录 , -p 递归删除目录
  • ps : 显示运行的进程信息
  • kill : 终止进程 , -9 强制中断一个进程的进行
  • crontab : 启动linux定时任务的服务
  • free : 显示Linux系统中空闲的、已用的物理内存及swap内存,及被内核使用的buffer
  • top : Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器
  • chmod : 配置 文件权限 ,-R:进行递归的持续更改,即连同子目录下的所有文件都会更改
  • useradd : 建立用户账号
  • vi/vim : 使用vi编辑器
  • cat : 连接文件或标准输入并打印。这个命令常用来显示文件内容,或者将几个文件连接起来显示,或者从标准输入读取内容并显示,它常与重定向符号配合使用。
  • tail : 将文件写到标准输出, -f 可以方便的查阅正在改变的日志文件
  • ifconfig : 用来查看和配置网络设备
  • whereis : 只能用于程序名的搜索,而且只搜索二进制文件(参数-b)、man说明文件(参数-m)和源代码文件(参数-s)
  • grep : 该命令常用于分析一行的信息,若当中有我们所需要的信息,就将该行显示出来,该命令通常与管道命令一起使用,用于对一些命令的输出进行筛选加工等等,比如可以加在ps, tail, cat后面

查看端口

  • ==netstat== -tunlp | grep 8888
netstat命令各个参数说明如下:
-t : 指明显示TCP端口 
-a : 显示所有的套接字
-u : 指明显示UDP端口 
-l : 仅显示监听套接字(所谓套接字就是使应用程序能够读写与收发通讯协议(protocol)与资料的程序) 
-p : 显示进程标识符和程序名称,每一个套接字/端口都属于一个程序。 
-n : 不进行DNS轮询,显示IP(可以加速操作) 
  • lsof -i:80 : 查看进程占用哪些文件的
  • fuser 22/tcp -v : fuser命令和lsof正好相反,是查看某个文件被哪个进程占用的。

相关文章

网友评论

      本文标题:2020 java 面试专题记录

      本文链接:https://www.haomeiwen.com/subject/dejpdktx.html