Java8 Consumer、Supplier、Predicate、Function
今天我们还讲讲Consumer、Supplier、Predicate、Function这几个接口的用法,在 Java8 的用法当中,这几个接口虽然没有明目张胆的使用,但是,却是润物细无声的。为什么这么说呢?这几个接口都在 java.util.function 包下的,分别是Consumer(消费型)、supplier(供给型)、predicate(谓词型)、function(功能性),相信有了后面的解释,你应该非常清楚这个接口的功能了。那么,下面,我们从具体的应用场景来讲讲这个接口的用法!
vConsumer
Java Consumer接口来自Java 8中引入的 java.util.function包。
Consumer是一个功能接口,用来作为lambda表达式或方法引用的任务目标(传递一个参数执行指定的方法)。
Consumer的功能接口是一个接受单一参数并且不返回任何结果的操作。
Consumer的功能方法是accept(T t)。
Consumer具有以下方法。
1. accept : 这是Consumer功能接口的功能方法。accept 方法对给定的参数进行这一操作。
2. andThen : 此方法返回一个组合的Consumer,该Consumer先执行原始的Consumer操作,然后按照从左到右的顺序执行给定的andThen操作。
功能方法:accept
功能方法accept
在功能接口Consumer
中的定义
void accept(T t)
使用示例
ConsumerAccept.java
import java.util.function.Consumer; public class ConsumerAccept { public static void main(String[] args) { Consumer<String> nameConsumer = s -> System.out.println(s); nameConsumer.accept("Mahesh"); nameConsumer.accept("Krishna"); } }
输出
Mahesh
Krishna
使用Lambda表达式创建Consumer
可以使用lambda表达式创建Consumer。
例1 基础类型操作
在我们的示例中,我们将使用lambda表达式在此处创建两个Consumer。
一个用于将数字添加到列表的方法,如果数字为奇数,则将添加到具有奇数的列表中;如果数字为偶数,则将其添加到具有偶数的另一个列表中。
ConsumerLambda1.java
import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; public class ConsumerLambda1 { public static void main(String[] args) { List<Integer> oddList = new ArrayList<>(); List<Integer> evenList = new ArrayList<>(); Consumer<Integer> storeNumber = n -> { if (n % 2 == 0) { evenList.add(n); } else { oddList.add(n); } }; Consumer<List<Integer>> printList = list -> list.forEach(n -> System.out.println(n)); storeNumber.accept(10); storeNumber.accept(15); storeNumber.accept(25); storeNumber.accept(30); System.out.println("--- Odd number ---"); printList.accept(oddList); System.out.println("--- Even number ---"); printList.accept(evenList); } }
输出结果
--- Odd number --- 15 25 --- Even number --- 10 30
例2 对象类型操作
我们将使用lambda
表达式创建一个Consumer
,它将决定并显示一个公民在选举中是否可以投票的数据。
ConsumerLambda2.java
import java.util.function.Consumer; public class ConsumerLambda2 { public static void main(String[] args) { Consumer<Citizen> electionConsumer = c -> { if (c.getAge() < 18) { System.out.println(c.getName() + " is not eligible to vote."); } else { System.out.println(c.getName() + " can vote."); } }; electionConsumer.accept(new Citizen("Ritesh", 15)); electionConsumer.accept(new Citizen("Shreya", 20)); } } class Citizen { private String name; private int age; public Citizen(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } }
输出结果
Ritesh is not eligible to vote.
Shreya can vote.
使用方法引用创建Consumer
Consumer可以使用方法引用来创建。
在我们的例子中,我们有一个有两个方法的实用类Utility,其中一个方法将替换Map中的值,第二个方法显示Map中的数据。我们将使用方法引用来创建Consumer。
ConsumerMethodRef.java
import java.util.HashMap; import java.util.Map; import java.util.function.Consumer; public class ConsumerMethodRef { public static void main(String[] args) { Map<Integer, String> persons = new HashMap<Integer, String>(); persons.put(101, "Mahesh"); persons.put(102, "Krishna"); Consumer<Map<Integer, String>> updatePersons = Utility::updateData; Consumer<Map<Integer, String>> displayPersons = Utility::displayData; updatePersons.accept(persons); displayPersons.accept(persons); } } class Utility { static void updateData(Map<Integer, String> persons) { persons.replaceAll((k, v) -> "Shree ".concat(v)); } static void displayData(Map<Integer, String> persons) { for (Map.Entry<Integer, String> entry : persons.entrySet()) { System.out.println(entry.getKey() + " - " + entry.getValue()); } } }
输出结果
101 - Shree Mahesh
102 - Shree Krishna
使用andThen方法
在Java
文档中andThen
方法声明。
default Consumer<T> andThen(Consumer<? super T> after)
- 这个方法返回一个组合的
Consumer
,先执行当前Consumer
操作,然后再执行after
的Consumer
操作。 - 如果在此操作或操作之后有异常,则将其中继到当前组合操作。
- 如果这个操作出现异常,那么后面的操作将不会被执行。
例1 简单拼接Consumer
我们的示例中有两个Consumer
。
首先将执行squareConsumer
,然后将执行printConsumer
。
ConsumerAndThen1.java
import java.util.Arrays; import java.util.List; import java.util.function.Consumer; public class ConsumerAndThen1 { public static void main(String[] args) { List<Integer> numList = Arrays.asList(3, 4, 5, 6); Consumer<List<Integer>> squareConsumer = list -> { for (int i = 0; i < list.size(); i++) { list.set(i, list.get(i) * list.get(i)); } }; Consumer<List<Integer>> printConsumer = list -> list.forEach(n -> System.out.println(n)); squareConsumer.andThen(printConsumer).accept(numList); } }
输出
9 16 25 36
例2 多个拼接Consumer
我们多次使用andThen
。首先将执行oddNumConsumer
,然后将执行evenNumConsumer
,然后将执行taskFinishConsumer
。
ConsumerAndThen2.java
import java.util.Arrays; import java.util.List; import java.util.function.Consumer; public class ConsumerAndThen2 { public static void main(String[] args) { List<Integer> list = Arrays.asList(12, 13, 14, 15, 16, 17); Consumer<List<Integer>> oddNumConsumer = MyNumber::printOddNum; Consumer<List<Integer>> evenNumConsumer = MyNumber::printEvenNum; Consumer<List<Integer>> taskFinishConsumer = MyNumber::taskFinishMsg; oddNumConsumer.andThen(evenNumConsumer).andThen(taskFinishConsumer).accept(list); } } class MyNumber { static void printOddNum(List<Integer> myNumbers) { System.out.println("--- odd numbers ---"); myNumbers.forEach(n -> { if (n % 2 == 1) { System.out.print(n + " "); } }); } static void printEvenNum(List<Integer> myNumbers) { System.out.println("\n--- even numbers ---"); myNumbers.forEach(n -> { if (n % 2 == 0) { System.out.print(n + " "); } }); } static void taskFinishMsg(List<Integer> myNumbers) { System.out.println("\nTotal " + myNumbers.size() + " number processed."); } }
输出结果
--- odd numbers ---
13 15 17
--- even numbers ---
12 14 16
Total 6 number processed.
vSupplier
Java 8引入了函数式接口 Supplier 是一个无参数的函数式接口,它不接受任何输入参数,但可以返回一个结果。它定义了一个名为 get() 的抽象方法,用于获取结果。
下面是Supplier<T>接口的定义:
@FunctionalInterface public interface Supplier<T> { T get(); }
在函数式编程中, Supplier 接口常用于延迟计算或惰性求值。它可以用来表示一个供应商或提供者,用于生成或获取数据。当需要获取数据时,可以调用 Supplier 的 get() 方法来获取结果。使用 Supplier 接口的主要优势之一是它可以与Java 8的新特性lambda表达式结合使用。通过lambda表达式,可以以更简洁和易读的方式定义 Supplier 对象。
下面是一个使用Supplier接口的示例:
import java.util.function.Supplier; public class SupplierExample { public static void main(String[] args) { // 使用lambda表达式创建Supplier对象 Supplier<String> supplier = () -> "你好,世界!"; String result = supplier.get(); // 调用get()方法获取结果 System.out.println(result); } } // 输出:你好,世界!
在上面的示例中,我们使用lambda表达式创建了一个返回字符串"Hello, World!"的 Supplier 对象。然后,我们调用了 get() 方法来获取结果,并将其打印到控制台上。
除了简单的返回固定值之外, Supplier 接口还可以用于生成随机数、读取文件、从数据库中获取数据等各种场景。通过实现 Supplier 接口的自定义类,我们可以根据具体需求来生成或获取数据。
以下是其他常见用法示例:
1. 提供随机数生成器:
Supplier<Integer> randomGenerator = () -> new Random().nextInt(); int randomNumber = randomGenerator.get();
2. 延迟加载资源:
Supplier<DatabaseConnection> connectionSupplier = () -> new DatabaseConnection(); DatabaseConnection connection = connectionSupplier.get();
3. 惰性初始化对象:
Supplier<ExpensiveObject> lazyInitializer = ExpensiveObject::new; ExpensiveObject object = lazyInitializer.get();
总结一下,Java 8的函数式接口 Supplier 用于表示一个供应商或提供者,它不接受任何输入参数,但可以返回一个结果。它可以与lambda表达式结合使用,用于延迟计算或惰性求值。
vPredicate
Java 8中引入了Predicate功能接口。Java Predicate表示一个参数的谓词。Predicate是一个布尔值的函数。Java Predicate是一个功能接口,属于java.util.function包。Predicate的功能方法是test(T t)。Predicate的其他方法是isEqual、and、or、negate和not。not方法在Java 11中被引入。
Predicate<Integer> predicate = new Predicate<Integer>() { @Override public boolean test(Integer integer) { if(integer > 5){ return true; }else{ return false; } } }; System.out.println(predicate.test(6)); // true Predicate<Integer> predicate2 = (t) -> t > 5; System.out.println(predicate2.test(1)); // false Predicate<String> isUserNameValid = u -> u != null && u.length() > 5 && u.length() < 10; System.out.println(isUserNameValid.test("Mahesh")); // true
vFunction
函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。且用@Function标签标记的接口。Java8 新增加的函数接口在 java.util.function 包下,它包含了很多类,用来支持 Java 的函数式编程。
函数产生给定数据类型的结果,并接受一个参数作为给定数据类型,T参数类型,R是结果类型。Function 接口是一个功能型接口,它的一个作用就是转换作用,将输入数据转换成另一种形式的输出数据。
Function<Integer,String> ob = f1 -> "Age:"+f1; System.out.println(ob.apply(20)); // 输出:Age:20
Function<String, Integer> function = new Function<String, Integer>() { @Override public Integer apply(String s) { return s.length();//获取每个字符串的长度,并且返回 } }; Stream<String> stream = Stream.of("qqq", "wwwww", "eeeeee"); Stream<Integer> stream1 = stream.map(function); stream1.forEach(System.out::println);
其他参考/学习资料:
- https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/function/Consumer.html
- https://www.concretepage.com/java/java-8/java-consumer
- https://blog.csdn.net/qq_31635851/article/details/116207886
v源码地址
https://github.com/toutouge/javademosecond/tree/master/hellolearn
作 者:请叫我头头哥
出 处:http://www.cnblogs.com/toutou/
关于作者:专注于基础平台的项目开发。如有问题或建议,请多多赐教!
版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信我
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是作者坚持原创和持续写作的最大动力!