Java双冒号(::)运算符使用详解

目录
  • 1.说明
  • 2.先来说下@FunctionalInterface
  • 3. 下面来讲讲这个 "::"是干嘛的
  • 4. 建立一个Person类
  • 4:构建多个person对象,放入数组中,然后对数组中的person重新排序
  • 5:揭秘 "::"符号
  • 6.0 方法引用的支持如下

1.说明

之前没用过::这个东西,今天看flink的时候发现官网有个例子用到了这个符号, 本着求知欲去百度查了一番,没找到能说到我心里去的解释,本着求知欲的态度,我去了官网看了看. java ::

2.先来说下@FunctionalInterface

java8 lambda 内部接口需要@FunctionalInterface这个注解,这个注解是一个说明性质的注解,被@FunctionalInterface注解的接口只能由一个抽象方法,@FunctionalInterface只能用于注解接口而不能用在class以及枚举上.
被@FunctionalInterface注解的符合规则的接口,可以用lambda表达式. 下面举一个例子:

public class Main {
    public static void pr(String s){
        System.out.println(s);
    }
    public static void main(String[] args) throws Exception {

        List<String> list = Arrays.asList("aaaa", "bbbb", "cccc");
        list.forEach(s -> System.out.println(s));

    }
}

所以说,@FunctionalInterface用于lambda样式说明.

3. 下面来讲讲这个 "::"是干嘛的

"::"官网对这个符号的解释是方法引用,也就是引用一个方法的意思,英文名称Method References
lambda expressions 可以用来创建一匿名的方法, 这个匿名的方式你需要自己实现.

   1. list.forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });
   2. list.forEach(s -> System.out.println(s));

上面两种写法是一样的,下面就是lambda表达式.

上面说了lambda表达式你需要自己实现,但是有些时候这不是必要的,比如你的项目里某个地方存在了一个符合当前逻辑的lambda表达式的方法, 那么我是否可以直接拿来用?, 答案是可以, 程序追求的就是不重复极简的思想, 既有则拿来用即可,为什么还要自己实现呢. Method References 就是用来做这件事的.

在看下面的例子之前读者需要知道java 比较器,否则看不懂代码.

4. 建立一个Person类

public class Person implements Comparable<Person>{
    public String name;
    public int age;

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public static int compareByAge(Person a, Person b) {
        return a.compareTo(b);
    }

    @Override
    public int compareTo(Person o) {
        if (this.age > o.age){
            return -1;
        }else{
            return 1;
        }
    }
}

4:构建多个person对象,放入数组中,然后对数组中的person重新排序

public class Test {

    //编写Comparator,Person的age
    private static final Comparator<Person> COMPARATOR = new Comparator<Person>() {
        public int compare(Person a, Person b) {
            return a.compareTo(b);//运用User类的compareTo方法比较两个对象
        }
    };

    public static void main(String[] args) {
        Person one = new Person("张三",50);
        Person two = new Person("李四",100);
        ArrayList<Person> array = new ArrayList<>();
        array.add(one);
        array.add(two);
        Collections.sort(array,COMPARATOR);
        System.out.println(array);
    }
}
//输出结果:
//[Person{name='李四', age=100}
//Person{name='张三', age=50}]

仔细看上面的代码,重点在Collections.sort(array,COMPARATOR);这一行,sort接收两个参数,第一个是要被排序的数组,第二个是一个比较器对象Comparator,其源码如下,我只粘贴了必要的部分.

**@FunctionalInterface**
public interface Comparator<T> {
    int compare(T o1, T o2);
}

@FunctionalInterface我们知道,被这个注解修饰的接口可以用lambda表达式的.

所以我们将class Test改成下面的样子:

public class Test {
    public static void main(String[] args) {
        Person one = new Person("张三",50);
        Person two = new Person("李四",100);
        ArrayList<Person> array = new ArrayList<>();
        array.add(one);
        array.add(two);
        Collections.sort(array, (a, b) -> a.compareTo(b));
        System.out.println(array);
    }

}

注意:下面是lambda写法,和正常传统写法

Collections.sort(array, (a, b) -> a.compareTo(b));
和下面的等效
Collections.sort(array, new Comparator() {
@Override
public int compare(Person a, Person b) {
return a.compareTo(b);
}
});

5:揭秘 "::"符号

到这里其实我们上面的功能已经完成了,我们来分析一下代码.
1:构造了两个对象
2:把对象放入了数组
3:Collection.sort(array,Comparator<T>) 对数组进行排序

关键点在于:Comparator<T> 比较器,它是一个被@FunctionalInterface修饰的接口,我们一般成为函数式接口.
因此,Collection.sort(array,Comparator<T>) ,对于第二个参数Comparator<T>,我们可以传入一个匿名实现类,然后实现里面的 int compare(T o1, T o2) 方法,也可以写成lambda表达式的样子,到这里如果你都懂了,那么接下来就好说了,如果没明白,回头接着看,相信自己骚年. 下面我们重点看lambda方式的写法,这和"::"息息相关

Collections.sort(array, (a, b) -> a.compareTo(b));

  1. **(a, b) -> a.compareTo(b)**这个其实就是匿名函数, 该函数的参数分别是Person a, Person b
  2. a.compareTo(b) 是该匿名函数的逻辑,

也即是说我们写出来的这个匿名函数有两个参数,以及一个调用compareTo的函数体,到这里其实结束了,一开始我们就说了,符号"::"的意义就是用一个已经存在的函数代替我们lambda表达式中的函数体,只要这个存在的函数和lambda函数体的函数格式一致就行了. 格式其实就是参数个数,和参数类型下面是新的class Test揭示了答案

public class Test {
    public static void main(String[] args) {
        Person one = new Person("张三",50);
        Person two = new Person("李四",100);
        ArrayList<Person> array = new ArrayList<>();
        array.add(one);
        array.add(two);
        Collections.sort(array, Person::compareByAge);//写法一
     // Collections.sort(array, one::entyMethod);//写法二
       System.out.println(array);
    }
}

附官网的一句话:
Because this lambda expression
invokes an existing method,
you can use a method reference
**instead of** a lambda expression

 Collections.sort(array, Person::compareByAge);
 Collections.sort(array, one::entyMethod);

这两种写法都是可行的.

6.0 方法引用的支持如下

我们上面讲了静态方法,和类方法的代替方式,至于其他的这里不讲了,主要是我要去吃饭了.

到此这篇关于Java双冒号(::)运算符使用详解的文章就介绍到这了,更多相关Java双冒号(::)内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java 位运算符>>与>>>区别案例详解

    下图是java教程中对于>>和>>>区别的解释,但是介绍的并不详细,因为这两种运算符是以补码二进制进行运算的. 1.学习过计算机原理的都知道,数字是以补码的形式在计算机中存储的,那么源码,反码,补码之间的关系是如下所示: **正整数**的原码.反码和补码都一样: **负数部分**: 1.原码和反码的相互转换:符号位不变,数值位按位取反 2.原码和补码的相互转换:符号位不变,数值位按位取反,末位再加1 3.已知补码,求原码的负数的补码:符号位和数值位都取反,末位再加1 2.了解

  • Java运算符从见过到掌握下

    目录 一.前言 二.运算符 赋值运算符 自增自减运算符 前置和后置的区别: 后置++--示例图 代码: 前置++--代码示例: 代码: 三元运算符 三元表达式的示例: 代码: 一.前言 前面我们介绍了运算符的一部分运算符,现在我们把剩余的他介绍完全来 二.运算符 赋值运算符 所谓赋值,就是一个等于号连接的两个如int a=10;double f=3.14之类的 自增自减运算符 自增自减就是形如++ ,--,具体又分为前置后置++和前置后置--. 前置和后置的区别: 后置++就是先使用再自增,后置

  • 一篇文章带你入门java算术运算符(加减乘除余,字符连接)

    目录 概念 实例 注意点 1.除法不能整除时 2.类型的提升 3.字符的(+)操作 4.字符串的(+)操作 实例1 实例2 实例3 实例4 总结 概念 算术运算符用在数学表达式中,它们的作用和在数学中的作用一样. 运算符 描述 实例 + 加法 - 相加运算符两侧的值 20+10=30 - 减法 - 左操作数减去右操作数 20-10=10 * 乘法 - 相乘操作符两侧的值 20*10=200 / 除法 - 左操作数除以右操作数 20/10=2 % 取余 - 左操作数除以右操作数的余数 20%10=

  • Java运算符从见过到掌握上

    目录 一.前言 二.运算符: 1.算术运算符: 模的运算特点: 除的特点: 字符的+号操作 连接符+号演示图: 代码: 2.关系运算符 关系运算演示图 : 代码: 3.逻辑运算符: 逻辑演示图: 代码: &&和||逻辑逻辑运算符的运算规则 一.前言 前面我们讲了Java的入门知识,相信许多小伙伴对Java基础有一个大概的认识了,这也为我 们后续的学习打下了基础,所以我们可以继续学习之后的知识了(Java前几章的知识基本和 c语言知识一样). 二.运算符: 算术运算符 赋值运算符 自增自减运

  • Java双冒号(::)运算符使用详解

    目录 1.说明 2.先来说下@FunctionalInterface 3. 下面来讲讲这个 "::"是干嘛的 4. 建立一个Person类 4:构建多个person对象,放入数组中,然后对数组中的person重新排序 5:揭秘 "::"符号 6.0 方法引用的支持如下 1.说明 之前没用过::这个东西,今天看flink的时候发现官网有个例子用到了这个符号, 本着求知欲去百度查了一番,没找到能说到我心里去的解释,本着求知欲的态度,我去了官网看了看. java :: 2

  • C++中双冒号::用法案例详解

    C++中的双冒号 :: 第一种,类作用域,用来标明类的变量.函数 Human::setName(char* name); 第二种,命名空间作用域,用来注明所使用的类.函数属于哪一个命名空间的 std::cout << "Hello World" << std::endl; 第三种,全局作用域,用来区分局部.全局的.最容易被忽视的一种,很多时候写了一个全局函数或者想要调用一个全局函数,却发现IDE或者Editor找不到该函数,原因是因为局部函数与想要调用的全局函数

  • 在docker中部署tomcat并且部署java应用程序的步骤详解

    先给大家简单说下Docker的概念 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化.容器是完全使用沙箱机制,相互之间不会有任何接口. 1.先说如何在docker中部署tomcat 第一步:root用户登录在系统根目录下创建文件夹tomcat7,命令如:mkdir tomcat7,并且切换到该目录下:cd tomcat7: 第二步:创建Dockerfile,命令如:touch Docker

  • Java 8 lambda表达式引入详解及实例

    Java 8 lambda表达式引入详解及实例 eclipse 下载安装 Help -> EclipseMarketplace -> 搜索Java 8 Kepler ->Java 8 support for eclipse Kepler SR2 安装完成后需要重启 Android Studio 在project的build.gradle文件中添加 buildscript { dependencies { classpath 'me.tatarka:gradle-retrolambda:3

  • Java枚举的使用方法详解

     Java枚举的使用方法详解 前言  你代码中的flag和status,都应该用枚举来替代 很多人都说,枚举在实际开发中很少用到,甚至就没用到.因为,他们的代码往往是这样子的: public class Constant { /* * 以下几个变量表示英雄的状态 */ public final static int STATUS_WALKING = 0;//走 public final static int STATUS_RUNNINGING = 1;//跑 public final stati

  • java 中的instanceof用法详解及instanceof是什么意思(推荐)

    好,应大家的要求先给大家说下在JAVA程序中instanceof是什么意思 instanceof是Java的一个二元操作符,和==,>,<是同一类东东.由于它是由字母组成的,所以也是Java的保留关键字.它的作用是测试它左边的对象是否是它右边的类的实例,返回boolean类型的数据. instanceof运算符用法 运算符是双目运算符,左面的操作元是一个对象实例,右面是一个类.当左面的对象是右面的类创建的对象时,该运算符运算的结果是true,否则是false 说明: (1).一个类的实例包括本

  • Java 中Flyway的使用详解

    Flyway的使用 环境:SpringBoot 2.0.4.RELEASE 为什么要用Flyway? 开发人员在合作的时候经常遇到以下场景: 1.开发人员A在自己的本地数据库做了一些表结构的改动,并根据这些改动调整了DAO层的代码,然后将代码上传到svn或git等版本控制服务器上.此时如果开发人员B拉取了A的代码改动,在运行项目的时候很可能会报错,因为B的本地SQL数据库并没有修改. 2.在项目上线的时候,当服务器拉取的版本控制服务器的最新修改后,必须同时运行SQL数据库的修改脚本,如果忘了跑数

  • Java基础之Object类详解

    object类的介绍 object是所有类的直接父类或者是间接父类,为什么这么说呢? 可以查询java8的API帮助文档: 可见在这样的一个类树中,所有的类的根还是Object类 在IDEA中新建一个类,系统会默认继承Object类 public class Pet extends Object{ } 那么Dog继承了Pet类的属性和行为方法,还会继承Object类的属性和行为方法了吗?这一点是肯定的,Pet类作为Object类的子类,Dog类作为Pet类的子类,所以说Object是Dog类的间

  • java短路逻辑运算符实例用法详解

    1.说明 逻辑操作符执行短路求值.所谓短路,就是当一个参与运算的操作数足以推断该表达式的值时,另一个操作数(可能是表达式)就不会执行. 在使用逻辑操作符时,当两个操作数都是true时,结果是true,但当第一个操作是false时,结果必须是false,此时不再判断第二个操作. 2.实例 public static void main(String[] args) { int a = 5;//定义一个变量: boolean b = (a < 4) && (a++ < 10); /

  • Java源码解析之详解ReentrantLock

    ReentrantLock ReentrantLock是一种可重入的互斥锁,它的行为和作用与关键字synchronized有些类似,在并发场景下可以让多个线程按照一定的顺序访问同一资源.相比synchronized,ReentrantLock多了可扩展的能力,比如我们可以创建一个名为MyReentrantLock的类继承ReentrantLock,并重写部分方法使其更加高效. 当一个线程调用ReentrantLock.lock()方法时,如果ReentrantLock没有被其他线程持有,且不存在

随机推荐