java8(二)方法引用

方法引用让你可以重复使用现有的方法定义,并像 Lambda 一样进行传递。

方法引用可以被看作仅仅调用特定方法的 Lambda 的一种快捷写法。

事实上,方法引用就是让你根据已有的方法实现来创建 Lambda 表达式。

例:

@Test
public void test1() {
    Chat chat = (content) -> System.out.println(content);
    chat.say("hello!");
}

@Test
public void test2() {
    Chat chat = System.out::println;
    chat.say("hello!");
}

interface Chat {
    void say(String word);
}

test1是 Lambda 表达式写法,通过调用 println 方法输出 content。test2 是方法引用,这里看起来方法引用更加的简洁明了。看完例子,再来看看语法。

语法

这里把方法引用分为5种

1.静态方法引用:ClassName::staticMethod

2.特定类的任意对象的方法引用:ClassName::instanceMethod

3.特定对象的方法引用:instance::instanceMethod

4.构造器引用:ClassName::new

5.数组引用:ClassName[]::new

举例

语法没看懂,没关系,我们举例来说明-_-

1.静态方法引用

@Test
public void test3() {
    // Function<T,R> 接受一个输入参数,返回一个结果。(java8定义的函数式接口)
    Function<Integer, String> f1 = (s) -> String.valueOf(s); // 将传入的类型转换成String
    System.out.println(f1.apply(100) + 200); // 输出100200

    Function<Integer, String> f2 = String::valueOf; // 将传入的类型转换成String
    System.out.println(f2.apply(100) + 200); // 输出100200
}

2.特定类的任意对象的方法引用

@Test
public void test4() {
    // Function<T,R> 接受一个输入参数,返回一个结果。(java8定义的函数式接口)
    Function<String, Integer> f1 = (s) -> s.length(); // 返回字符串长度
    System.out.println(f1.apply("hello")); // 输出5

    Function<String, Integer> f2 = String::length; // 返回字符串长度
    System.out.println(f2.apply("hello")); // 输出5
}

3.特定对象的方法引用

@Test
public void test5() {
    String s = "hello";
    // IntSupplier 无参数,返回一个int类型结果。(java8定义的函数式接口)
    IntSupplier intSupplier1 = () -> s.length(); // 返回字符串长度
    System.out.println(intSupplier1.getAsInt()); // 输出5

    IntSupplier intSupplier2 = s::length; // 返回字符串长度
    System.out.println(intSupplier2.getAsInt()); // 输出5
}

4.构造器引用

@Test
public void test6() {
    // Supplier<T> 无参数,返回一个结果。(java8定义的函数式接口)
    List list1 = this.getList(() -> new ArrayList());

    List list2 = this.getList(ArrayList::new);
}

public static List getList(Supplier<List> s){
    return s.get();
}

5.数组引用

@Test
public void test7() {
    // Function<T,R> 接受一个输入参数,返回一个结果。(java8定义的函数式接口)
    Function<Integer, String[]> f1 = length -> new String[length];
    String[] strs = f1.apply(10);
    System.out.println(strs.length); // 输出10

    Function<Integer,String[]> f2 = String[]::new;
    strs = f2.apply(10);
    System.out.println(strs.length); // 输出10
}

参考资料

  1. http://how2j.cn/p/2807
  2. 《Java 8函数式编程》
  3. 《Java 8实战》
<think>嗯,用户问的是Java中的方法引用,我得先回忆一下相关知识。方法引用Java 8引入的一个特性,和lambda表达式相关。可能用户已经了解lambda,但想更深入方法引用。 首先,我需要明确方法引用的基本概念。方法引用是用来直接引用已有方法构造器的语法糖,让代码更简洁。例如,用System.out::println来代替lambda表达式。不过得注意,方法引用和lambda一样,都是函数式接口的实例。 接下来,用户可能需要知道为什么使用方法引用。可能他们之前写过很多lambda,发现有些重复代码,或者想让代码更易读。这时候方法引用就派上用场了,可以简化代码,尤其是在处理集合或流操作时。 然后,方法引用的分类。四种类型:静态方法引用、实例方法引用、特定对象的实例方法引用构造引用。每个类型都需要举例说明。比如,静态方法引用可以用Math::max,实例方法可能用String::length,特定对象如System.out::println,构造引用如ArrayList::new。 需要区分实例方法引用中的不同情况。比如,String::compareToIgnoreCase是实例方法,但需要两个参数,第一个是调用者,第个是参数。这时候对应的函数式接口可能是BiFunction。这点容易混淆,要讲清楚。 可能用户会问什么时候适合使用方法引用,什么时候用lambda。一般来说,如果lambda仅仅是调用一个已有方法,那么用方法引用更简洁。但如果需要额外操作,还是得用lambda。 还需要注意方法引用的使用条件,即它们必须匹配函数式接口的参数列表和返回类型。例如,Comparator<String> c = String::compareToIgnoreCase; 这里compareToIgnoreCase的参数是String,而Comparator的compare方法需要两个String参数,所以可以匹配。 可能用户对方法引用的语法不太熟悉,比如双冒号::的使用,需要强调这个符号的位置,以及不同引用类型对应的写法差异。 另外,构造引用可能涉及到泛型,比如Supplier<List<String>> supplier = ArrayList::new; 这时候会根据上下文推断类型,生成对应的构造函数。 最后,应用场景举例,比如在Stream API中的使用,forEach方法中传入方法引用,让代码更简洁。比如list.forEach(System.out::println)。 需要检查是否有遗漏的类型或者常见错误,比如混淆静态方法和实例方法引用写法,或者参数不匹配的情况。同时,提醒用户方法引用不能用于重载方法的情况,需要显式指定类型。 可能用户的实际问题是在代码优化或重构时遇到重复的lambda,想用方法引用替换,所以需要给出清晰的例子和对比,突出方法引用的优势。 总之,结构上先介绍概念,然后四种类型分别讲解,给出示例,接着比较lambda和方法引用的适用场景,最后应用实例和注意事项。确保内容准确,例子易懂,帮助用户理解并应用方法引用。</think>Java中的方法引用(Method Reference)是Java 8引入的特性,用于简化Lambda表达式的语法。它允许开发者直接通过名称引用已有的方法构造器,使代码更简洁、易读。 --- ### 核心概念 方法引用是Lambda表达式的一种简写形式,**当Lambda仅用于调用某个已存在的方法时**,可以直接用方法名替代。例如: ```java // Lambda表达式 list.forEach(s -> System.out.println(s)); // 方法引用 list.forEach(System.out::println); // 效果完全相同,但更简洁 ``` --- ### 方法引用的类型 Java支持四种方法引用方式: #### 1. **静态方法引用** 语法:`类名::静态方法名` ```java // 原始Lambda表达式 Function<Integer, String> func1 = num -> String.valueOf(num); // 方法引用 Function<Integer, String> func2 = String::valueOf; // 引用静态方法 ``` #### 2. **实例方法引用(特定对象)** 语法:`对象::实例方法名` ```java List<String> list = Arrays.asList("A", "B", "C"); // 原始Lambda表达式 list.forEach(s -> System.out.println(s)); // 方法引用 list.forEach(System.out::println); // 引用System.out对象的println方法 ``` #### 3. **实例方法引用(任意对象)** 语法:`类名::实例方法名` 当Lambda参数是方法调用者时使用: ```java // 原始Lambda表达式 List<String> names = Arrays.asList("Alice", "Bob"); names.sort((s1, s2) -> s1.compareToIgnoreCase(s2)); // 方法引用 names.sort(String::compareToIgnoreCase); // 自动将s1作为调用者,s2作为参数 ``` #### 4. **构造引用** 语法:`类名::new` ```java // 原始Lambda表达式 Supplier<List<String>> supplier1 = () -> new ArrayList<>(); // 方法引用 Supplier<List<String>> supplier2 = ArrayList::new; // 引用无参构造器 // 带参数的构造引用 Function<Integer, ArrayList<String>> func = ArrayList::new; // 根据参数推断容量 ``` --- ### 适用场景 1. **简化Lambda表达式** 当Lambda仅调用一个方法时,优先用方法引用。 2. **提升可读性** 例如在流式编程中: ```java list.stream() .map(String::toUpperCase) // 引用实例方法 .forEach(System.out::println); ``` --- ### 注意事项 1. **方法签名必须匹配** 方法的参数和返回类型需与函数式接口一致: ```java // 错误示例:Math.max需要两个参数,但Comparator.compare需要两个参数(匹配) BiFunction<Integer, Integer, Integer> maxFunc = Math::max; // 正确 ``` 2. **无法用于重载方法** 需显式指定类型: ```java // 假设有重载方法:static void print(String s) 和 static void print(Integer i) Consumer<String> c = MyClass::print; // 需通过类型推断选择正确方法 ``` --- ### 总结 | 类型 | 语法 | 示例 | |--------------------|-----------------|--------------------------| | 静态方法引用 | `类名::静态方法` | `Math::sqrt` | | 实例方法(对象) | `对象::方法` | `System.out::println` | | 实例方法(类) | `类名::方法` | `String::compareTo` | | 构造引用 | `类名::new` | `ArrayList::new` | 方法引用通过减少冗余代码提升代码简洁性,是Java函数式编程的重要工具之一。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值