JAVA基础之接口与内部类

接口与内部类

本文主要整理了一些作者看JAVA核心技术卷第六章遇到的难点以及其思考,欢迎小伙伴及时指出错误!

1. Lambda表达式

1. 关于懒计算

在JAVA8中,提供了 Supplier这个接口实现懒计算

原理是这样的,主要依据是以下三个原理

  • 在JAVA8的新特性中,只要一个接口只有一个抽象方法(不包括default和static),那么这个接口就会被被认为是一个函数式接口,可以使用lambda表达式,而注解 @FunctionalInterface 和我们的 @Override 一样,用于提示,不写也可以,但是建议写

  • lambda表达式在被调用时才执行

  • lambda表达式可以做类型推断(不是太重要的原理)

我们可以观察Objects.requireNoNull 方法,在参数为 null 会抛出一个异常,异常的内容与我们传递的第二个参数有关

这个方法有三个重载,我们主要关注的是有两个方法的重载

  • 首先是传统的重载
public static <T> T requireNonNull(T obj,String message) {
    if (obj == null)
        throw new NullPointerException(message);
    return obj;
}

这里直接传入了一个String类型的message,这样看虽然没什么不妥,但是设想一下,如果我们的 null 不是一个经常出现的结果,同时我们的String是通过调用某个方法得到的,这样每次执行非空判断,都会调用我们对message写的方法,比如我们传入一个时间

new LocalDate(1970,1,1);

这样如果有大量的进程调用这个判断,同时并没有那么多null,会造成性能浪费

  • 基于懒计算的优化
public static <T> T requireNonNull(T obj,Supplier<String> messageSupplier) {
    if (obj == null)
        throw new NullPointerException(messageSupplier.get());
    return obj;
}

与上面不同,这里的第二个参数是一个 Supplier 接口,我们从第一点可以得知,由于该接口只有一个抽象方法,因此它是一个函数式接口,我们可以使用Lambda表达式; 又根据我们第二点,lambda表达式只有在被调用的时候才会执行,那么如果我们没有那么多的空判断,这个方法就不会执行,当我们的第二个参数很复杂(比如要向数据库查询数据),这样就可以节省了大量的性能,第二个参数的lambda表达式我们可以这样写

() -> new LocalDate(1970,1)

类似的,与懒计算设计思路相似的优化方法还有懒加载,即页面的元素(比如图片或者视频等)只有在被调用(比如我们往下翻页的时候)才加载,这样大大缓解了服务器的压力与网络的压力,毕竟不是所有人都会看到底的

2. Predicate接口

@FunctionalInterface
public interface Predicate<T> {

    boolean test(T t);

    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }

    default Predicate<T> negate() {
        return (t) -> !test(t);
    }
    
    default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }

    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null == targetRef)
                ? Objects::isNull
                : object -> targetRef.equals(object);
    }

可以看出,这个接口同样只有一个抽象方法,因此他也是一个函数式接口,这个函数式接口很有用,因为它可以返回一个布尔值,在我们传入一个方法可以做判断

3. 关于方法引用

  • 方法引用主要有三种情况

    • object :: instanceMethod 等价于向方法传递参数的lambda表达式
    • Class :: instanceMethod 等价于第一个参数作为方法的隐式参数(即this,表示该参数自己,方法包括定义自己的属性或者调用自己的一些方法,最后的结果会返回到这个参数上),其余的参数会传递到方法
    • Class :: staticMethod 等价于所有的参数都传递到静态方法中,与上面的区别是有没有隐式参数(即改变了自己的值)
  • 虽然我们可以用lambda表达式来等价方法引用,但是两者最重要的区别是 方法引用会立即执行,而lambda表达式只有在调用的时候才会执行

  • 只有当lambda表达式的方法体只调用一个方法而不做其他操作时,我们才可以将lambda表达式重写为方法引用,比如下面的就不可以,因为它除了方法调用,还进行了比较

s -> s.length() == 0

4. 关于构造器引用

  • 构造器引用的基本结构

    • Class :: new
    • 表示 Class 构造器的一个引用,引用的构造器取决于上下文,编译器会自动推导
  • 数组类型的构造器引用

    • Class[] :: new

    • 等价于

      x -> new Class[x]
      

      即创建了一个指定类型的对象数组

5. 关于变量的作用域

  • lambda可以捕获外围作用域中的变量的值
  • lambda表达式中捕获的值必须实际上是 事实最终变量,即初始化后就不再为其赋新值, 这是由于lambda表达式在调用后才执行,如果改变的话会造成不安全
  • lambda表达式的体与嵌套块有相同的作用域,我们可以理解为,在lambda表达式左侧传入的变量和上下文的变量的作用域是一致的
    • 在lambda表达式中,没与参数也要写括号 () -> xxx
    • 在lambda表达式中,会自动推断变量类型,可以不写,(String first) -> xxx 和 (first) -> xxx是一样的,因此如果上文有first这个变量,这里就会报变量冲突的错误

2. 内部类

1. 局部内部类

  • 在一个方法中局部定义的类叫做局部内部类

  • 声明局部类时不能有访问说明符(即 public private protected),作用域仅限于声明这个局部类的类中 ==> 可以访问类的全部属性,包括私有属性

  • 优点: 对外部世界完全屏蔽

2. 匿名内部类

  • 如果只想创建局部内部类的一个对象而不需要给其指定名字,可以使用匿名内部类

  • new SuperType(construction parameters) 
    {
        inner class methods and data
    }
    
  • SuperType可以是接口 ==> 匿名内部类实现这个接口

  • SuperType可以使一个类 ==> 匿名内部类拓展这个类

  • 如果参数列表的结束小括号后面跟着一个开始大括号,就是在定义匿名内部类

  • 与lambda表达式最大的区别

    • lambda编译后不会生成class文件,那么也就略过了类的加载、验证、解析等。相当于是在运行时再进行相应的操作
    • 这里主要体现在对Spring的影响中,在spring注入过程中,无法注入含确定类型的入参和出参方法的实现类,所以,才会出现无法确定类型,导致注入失败,从而springboot启动失败的问题。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 目录 连接 连接池产生原因 连接池实现原理 小结 TEMPERANCE:Eat not to dullness;drink not to elevation.节制
摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 一个优秀的工程师和一个普通的工程师的区别,不是满天飞的架构图,他的功底体现在所写的每一行代码上。-- 毕玄 1. 命名风格 【书摘】类名用 UpperCamelC
今天犯了个错:“接口变动,伤筋动骨,除非你确定只有你一个人在用”。哪怕只是throw了一个新的Exception。哈哈,这是我犯的错误。一、接口和抽象类类,即一个对象。先抽象类,就是抽象出类的基础部分,即抽象基类(抽象类)。官方定义让人费解,但是记忆方法是也不错的 —包含抽象方法的类叫做抽象类。接口
Writer :BYSocket(泥沙砖瓦浆木匠)微 博:BYSocket豆 瓣:BYSocketFaceBook:BYSocketTwitter :BYSocket一、引子文件,作为常见的数据源。关于操作文件的字节流就是 —FileInputStream&amp;FileOutputStream。
作者:泥沙砖瓦浆木匠网站:http://blog.csdn.net/jeffli1993个人签名:打算起手不凡写出鸿篇巨作的人,往往坚持不了完成第一章节。交流QQ群:【编程之美 365234583】http://qm.qq.com/cgi-bin/qm/qr?k=FhFAoaWwjP29_Aonqz
本文目录 线程与多线程 线程的运行与创建 线程的状态 1 线程与多线程 线程是什么? 线程(Thread)是一个对象(Object)。用来干什么?Java 线程(也称 JVM 线程)是 Java 进程内允许多个同时进行的任务。该进程内并发的任务成为线程(Thread),一个进程里至少一个线程。 Ja
Writer :BYSocket(泥沙砖瓦浆木匠)微 博:BYSocket豆 瓣:BYSocketFaceBook:BYSocketTwitter :BYSocket在面向对象编程中,编程人员应该在意“资源”。比如?1String hello = &quot;hello&quot;; 在代码中,我们
摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 这是泥瓦匠的第103篇原创 《程序兵法:Java String 源码的排序算法(一)》 文章工程:* JDK 1.8* 工程名:algorithm-core-le
摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 目录 一、父子类变量名相同会咋样? 有个小故事,今天群里面有个人问下面如图输出什么? 我回答:60。但这是错的,答案结果是 40 。我知错能改,然后说了下父子类变
作者:泥瓦匠 出处:https://www.bysocket.com/2021-10-26/mac-create-files-from-the-root-directory.html Mac 操作系统挺适合开发者进行写代码,最近碰到了一个问题,问题是如何在 macOS 根目录创建文件夹。不同的 ma
作者:李强强上一篇,泥瓦匠基础地讲了下Java I/O : Bit Operation 位运算。这一讲,泥瓦匠带你走进Java中的进制详解。一、引子在Java世界里,99%的工作都是处理这高层。那么二进制,字节码这些会在哪里用到呢?自问自答:在跨平台的时候,就凸显神功了。比如说文件读写,数据通信,还
1 线程中断 1.1 什么是线程中断? 线程中断是线程的标志位属性。而不是真正终止线程,和线程的状态无关。线程中断过程表示一个运行中的线程,通过其他线程调用了该线程的 方法,使得该线程中断标志位属性改变。 深入思考下,线程中断不是去中断了线程,恰恰是用来通知该线程应该被中断了。具体是一个标志位属性,
Writer:BYSocket(泥沙砖瓦浆木匠)微博:BYSocket豆瓣:BYSocketReprint it anywhere u want需求 项目在设计表的时候,要处理并发多的一些数据,类似订单号不能重复,要保持唯一。原本以为来个时间戳,精确到毫秒应该不错了。后来觉得是错了,测试环境下很多一
纯技术交流群 每日推荐 - 技术干货推送 跟着泥瓦匠,一起问答交流 扫一扫,我邀请你入群 纯技术交流群 每日推荐 - 技术干货推送 跟着泥瓦匠,一起问答交流 扫一扫,我邀请你入群 加微信:bysocket01
Writer:BYSocket(泥沙砖瓦浆木匠)微博:BYSocket豆瓣:BYSocketReprint it anywhere u want.文章Points:1、介绍RESTful架构风格2、Spring配置CXF3、三层初设计,实现WebService接口层4、撰写HTTPClient 客户
Writer :BYSocket(泥沙砖瓦浆木匠)什么是回调?今天傻傻地截了张图问了下,然后被陈大牛回答道“就一个回调…”。此时千万个草泥马飞奔而过(逃哈哈,看着源码,享受着这种回调在代码上的作用,真是美哉。不妨总结总结。一、什么是回调回调,回调。要先有调用,才有调用者和被调用者之间的回调。所以在百
Writer :BYSocket(泥沙砖瓦浆木匠)一、什么大小端?大小端在计算机业界,Endian表示数据在存储器中的存放顺序。百度百科如下叙述之:大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加
What is a programming language? Before introducing compilation and decompilation, let&#39;s briefly introduce the Programming Language. Programming la
Writer :BYSocket(泥沙砖瓦浆木匠)微 博:BYSocket豆 瓣:BYSocketFaceBook:BYSocketTwitter :BYSocket泥瓦匠喜欢Java,文章总是扯扯Java。 I/O 基础,就是二进制,也就是Bit。一、Bit与二进制什么是Bit(位)呢?位是CPU
Writer:BYSocket(泥沙砖瓦浆木匠)微博:BYSocket豆瓣:BYSocket一、前言 泥瓦匠最近被项目搞的天昏地暗。发现有些要给自己一些目标,关于技术的目标:专注很重要。专注Java 基础 + H5(学习) 其他操作系统,算法,数据结构当成课外书博览。有时候,就是那样你越是专注方面越