java 函数接口Consumer简介与示例【函数式编程】【Stream】

发布于:2024-08-20 ⋅ 阅读:(128) ⋅ 点赞:(0)

Java 8 中的 消费者接口Consumer 是一个函数接口,它可以接受一个泛型 类型参数,它属于java.util.function包。我们来看看Java函数接口库中的定义:

@FunctionalInterface
public interface Consumer<T> {

  /**
   * Performs this operation on the given argument.
   *
   * @param t the input argument
   */
  void accept(T t); //抽象方法
  /***下面是一个默认方法***/
  default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}

accept(T) 方法:是 Consumer 函数式接口的惟一抽象方法,传入单个输入参数,无返回值,可以用于 Lambda 表达式和方法引用。
andThen(Consumer) 方法:是默认方法。上面是这个默认方法的源代码。它可以传入一个 Consumer ,返回组合了两个 Consumer 后的 Consumer ,传入的 Consumer 不能为 null,否则会得到 NullPointerException 。

你可以使用 Consumer 来执行某个动作,比如打印操作,该动作接受一个参数并且不返回任何值。

我们先来看两个例程:

import java.util.function.Consumer;
public class ConsumerTest {
	
	public static void test() {
        Consumer<String> first = x -> System.out.println("1."+x.toLowerCase());
        Consumer<String> second = y -> System.out.println("2." + y);
        System.out.println("开始");
        Consumer<String> consume = first.andThen(second);
        //调用了accept 时,会先执行 first 的代码,再执行 second 的代码
        consume.accept("World");
	}
	public static void main(String[] args) {
        test();
	}
}

consume调用accept 方法时,会先执行 first 里的代码,再执行 second 里的代码
测试结果:
在这里插入图片描述

第二个例程:

package function;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
public class ConsumerTest {
	//Consumer接口的匿名实现类版本
	public static void test1() {
	    List<String> list = Arrays.asList("我","爱","北京天安门");
	    list.forEach( new Consumer<String>() {
	      @Override
	      public void accept(String string) {
	        System.out.println(string);
	      }
	    }  );
	}
	
	public static void main(String[] args) {
		test1();
	}
}

这段程序很简单,首先初始化一个String类型的集合List,然后向控制台输出集合中每个元素。其中我们注意到forEach方法,它就是Java8中新增加的默认方法。

集合框架中的集合类都实现了迭代接口,forEach方法是Iterable接口的默认方法,被关键字default修饰。这样任何实现该接口的集合都继承forEach方法。Iterable接口的源码如下:

public interface Iterable<T> {
  .
  .省略
  .
  default void forEach(Consumer<? super T> action) {
    Objects.requireNonNull(action);
    for (T t : this) {
      action.accept(t);
    }
  }
}

forEach方法的输入参数就是一个Consumer类型的参数action。本例中方法test1()是Java7以前版本的老式写法,传入的是一个Consumer接口的匿名实现类:

new Consumer<String>() {
	@Override
	public void accept(String string) {
	    System.out.println(string);
	}
}

在Java8以后版本,可以使用Lambda表达式,这个Consumer接口的匿名实现类可简写成:
string->System.out.println(string)
因此,方法test1()就可以改写为如下的Lambda表达式版本:

	//Lambda表达式版本
	public static void test1() {
	    List<String> list = Arrays.asList("我","爱","北京天安门");
	    list.forEach( string->System.out.println(string) );
	}

Lambda表达式:string->System.out.println(string)
还可改写为方法引用 : System.out::println
这二种写法是等效。
所以,我们还可以改写为如下的方法引用的版本:

	//方法引用的版本
	public static void test1() {
	    List<String> list = Arrays.asList("我","爱","北京天安门");
	    list.forEach( System.out::println );
	}

改写后版本的效果与前面的Consumer接口的匿名实现类版本完全等价。

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Stream;
public class ConsumerTest {

	public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        Consumer <String> consumer  = x -> {
            if (x.startsWith("a")){
                list.add(x);
            }
        };
        Stream.of( "aa","bb","cac","abd","ee" ).forEach(consumer);
        list.forEach(System.out::println);
	}
}

测试结果:
在这里插入图片描述
未完待续


网站公告

今日签到

点亮在社区的每一天
去签到