If you still don’t know how to use the Consumer interface, come to the company and I will tell you face to face

background

That's right, I'm still working on the XXXX project, and I'm still connecting with third parties. The difference is that this time I'm dealing with my own business logic.

During the development process, I encountered such a problem:

Table structure:
a main table A, an associated table B, and table A stores the status of table B records.

Scenario:
The first step is to create the main table data and insert into table A; the second step is to call a third-party interface to insert into table B and update the status of table A. At this point, everyone should think that the idempotency of the data needs to be done well when performing the second step. In this case, the following situations will exist:

1. There is no data associated with table A in table B. At this time, it is necessary to call a third-party interface to insert into table B and update the status of table A;

2. There is data associated with table A in table B;

  1. The status in table A is processing: directly return the word processing;
  2. The status in table A is processing successfully: directly return the words of success;
  3. The status in table A is processing failure: at this time, you need to call the third-party interface to update table B and update the status of table A at the same time;

Code

First I wrote the pseudocode like this

B b = this.baseMapper.selectOne(queryWrapper);
if (b != null) {
    
    
	String status = b.getStatus();
	if (Objects.equals(Constants.STATUS_ING, status)){
    
    
		return "处理中";
	} else if (Objects.equals(Constants.STATUS_SUCCESS, status)){
    
    
		return "处理成功";
	}
	//失败的操作
	//请求第三方接口并解析响应结果
	......
	if (ReturnInfoEnum.SUCCESS.getCode().equals(parse.getCode())) {
    
    
        ......
        //更新B表操作
		bb.setStatus(Constants.STATUS_ING);
		mapper.updateById(bb);

		//更新A表的状态
		a.setStatus(Constants.STATUS_ING);
		aMapper.updateById(a);
	}
	
} else {
    
    
	//请求第三方接口并解析响应结果
	......
	if (ReturnInfoEnum.SUCCESS.getCode().equals(parse.getCode())) {
    
    
        ......
        //插入B表操作
		bb.setStatus(Constants.STATUS_ING);
		mapper.insert(bb);

		//更新A表的状态
		a.setStatus(Constants.STATUS_ING);
		aMapper.updateById(a);
	}
}

I don't know if the careful friends have found that the case where there is a record in table B and the status is "failure" and the case where there is no table B, except for the operation of inserting or updating table B, the rest of the operations are the same.

If we want to extract the common parts and find that they are scattered, it is better not to extract, but there are a lot of repeated codes without extracting codes that do not conform to my style. So I reached out to the Consumer interface.

Pseudocode after changes

B b = this.baseMapper.selectOne(queryWrapper);
if (b != null) {
    
    
	String status = b.getStatus();
	if (Objects.equals(Constants.STATUS_ING, status)){
    
    
		return "处理中";
	} else if (Objects.equals(Constants.STATUS_SUCCESS, status)){
    
    
		return "处理成功";
	}
	//失败的操作
	getResponse(dto, response, s -> mapper.updateById(s));
} else {
    
    
	getResponse(dto, response, s -> mapper.updateById(s));
}

public void getResponse(DTO dto, Response response, Consumer<B> consumer){
    
    
	//请求第三方接口并解析响应结果
	......
	if (ReturnInfoEnum.SUCCESS.getCode().equals(parse.getCode())) {
    
    
        ......
		bb.setStatus(Constants.STATUS_ING);
	
		consumer.accept(bb);

		//更新A表的状态
		a.setStatus(Constants.STATUS_ING);
		aMapper.updateById(a);
	}
}

Seeing this, if everyone has understood it, then congratulations, it means that you have mastered the use of Consumer. If you still have the slightest doubt, then read on, we will introduce four common functional interfaces.

functional interface

So what is a functional interface? A functional interface is an interface that has only one abstract method (except Object's method), but can have multiple non-abstract methods, and it expresses a logical single function.

@FunctionalInterface

@FunctionalInterfaceThe annotation is used to indicate that the interface is a functional interface. It helps in early detection of inappropriate method declarations present in functional interfaces or inherited by interfaces.

If an interface is annotated with this annotation but is not actually a functional interface, an error will be reported at compile time.

Consumer

We generally call this a "consumer", which represents an operation that accepts a single input parameter but does not return a result. Unlike other functional interfaces, Consumer is expected to operate through side effects.

So what are the side effects? Let me talk about side effects as I understand them. Side effects are actually whether a function will modify resources outside its scope. If so, it is called side effects, otherwise it is called no side effects. Such as modifying global variables, modifying objects referenced by input parameters, etc.

@FunctionalInterface
public interface Consumer<T> {
    
    

    /**
     *  对给定的参数执行此操作。
     */
    void accept(T t);

    /**
     * 
     *  返回一个组合的 Consumer ,依次执行此操作,然后执行after操作。
     *  如果执行任一操作会抛出异常,它将被转发到组合操作的调用者。
     *  如果执行此操作会引发异常,则不会执行after操作。
     */
    default Consumer<T> andThen(Consumer<? super T> after) {
    
    
        Objects.requireNonNull(after);
        return (T t) -> {
    
     accept(t); after.accept(t); };
    }
}

Just like the scenario encountered in our case, we only need to pass in the logical method to be executedgetResponse() as a parameter , and then execute the method in this method accept()for consumption. If you still don't understand it, we can convert it to the calling method of an anonymous inner class.

 getResponse(dto, response, new Consumer<B>() {
    
    
    @Override
    public void accept(B bb) {
    
    
      mapper.insert(bb);
    }
});

When the method is called, accept()the method of the anonymous inner class will be called, which is the getResponse()logical method we pass in.

Supplier

We generally call it "producer", which has no parameter input, but can return the result, and is the provider of the result.

@FunctionalInterface
public interface Supplier<T> {
    
    

    /**
     *  获取一个结果
     */
    T get();
}

You can give a simple example to feel:

Optional<Double> optional = Optional.empty();
optional.orElseGet(()->Math.random() );

//orElseGet 方法的源码,里边用到了 get 方法
public T orElseGet(Supplier<? extends T> other) {
    
       
    return value != null ? value : other.get();
}

Function

I call it a "converter", which means a function that receives a parameter and returns a result after processing it.

@FunctionalInterface
public interface Function<T, R> {
    
    

    /**
     *  将 T 类型的参数传入,经过函数表达式的计算,返回 R 类型的结果
     */
    R apply(T t);

    /**
     * 返回一个组合函数,先将参数应用于 before 函数,然后将结果应用于当前函数,返回最终结果。
     * 如果对任一函数的求值引发异常,则会将其转发给组合函数的调用方。
     */
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
    
    
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }

    /**
     * 返回一个组合函数,先将参数应用与当前函数,然后将结果应用于 after 函数,返回最终的结果。
     * 如果对任一函数的求值引发异常,则会将其转发给组合函数的调用方。 
     */
    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
    
    
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }

    /**
     *  返回始终返回其输入参数的函数。
     */
    static <T> Function<T, T> identity() {
    
    
        return t -> t;
    }
}

We have a lot of applications in lambda expressions, so let's briefly demonstrate:

@Data
@AllArgsConstructor
public class Teacher {
    
    
    private String name;
    private int age;
}

public class TeacherTest {
    
    
    public static void main(String[] args) {
    
    
       List<Teacher> list = Arrays.asList(
            new Teacher("张三",25),
            new Teacher("李四",28),
            new Teacher("王五",18));
      List<String> collect = list.stream().map(item -> item.getName()).collect(Collectors.toList());
      System.out.println(collect);
    }
}

Among them, the parameter received by map is the Function type, item is the incoming parameter, and item.getName()returns the processing result, and the final output result is

[张三, 李四, 王五]

Predicate

We call it a "judger", which returns a boolean result by receiving a parameter T.

@FunctionalInterface
public interface Predicate<T> {
    
    

    /**
     *  接收一个参数, 判断这个参数是否匹配某种规则, 匹配成功返回true, 匹配失败则返回false
     */
    boolean test(T t);

    /**
     *  接收一个 Predicate 类型的参数,用当前函数和 other 函数逻辑与判断参数 t 是否匹配规则,成功返回true,失败返回 false 
     *  如果当前函数返回 false,则 other 函数不进行计算
     * 在评估 Predicate 期间引发的任何异常都会转发给调用方
     */
    default Predicate<T> and(Predicate<? super T> other) {
    
    
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }

    /**
     *  返回当前Predicate取反操作之后的Predicate
     */
    default Predicate<T> negate() {
    
    
        return (t) -> !test(t);
    }

    /**
     *  接收一个 Predicate 类型的参数,用当前函数和 other 函数 逻辑或 判断参数 t 是否匹配规则,成功返回true,失败返回 false 
     *  如果当前函数返回 true,则 other 函数不进行计算
     * 在评估 Predicate 期间引发的任何异常都会转发给调用方
     */
    default Predicate<T> or(Predicate<? super T> other) {
    
    
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }

    /**
     *  静态方法:传入一个参数,用来生成一个 Predicate,调用test() 方法时调的 object -> targetRef.equals(object) 函数式
     *
     */
    static <T> Predicate<T> isEqual(Object targetRef) {
    
    
        return (null == targetRef)
                ? Objects::isNull
                : object -> targetRef.equals(object);
    }
}

I believe that you often encounter this functional interface in the coding process. Let's give an example:

public static void main(String[] args) {
    
    
    List<Teacher> list = Arrays.asList(
        new Teacher("张三",25),
        new Teacher("李四",28),
        new Teacher("王五",18));

    list = list.stream().filter(item -> item.getAge()>25).collect(Collectors.toList());
    list.stream().forEach(item->System.out.println(item.getName()));
}

Among filter()them, the parameter of is Predicateof type, and the return result is: Li Si

Seeing this, we have introduced the four common functional interfaces. To be honest, I've seen functional interfaces several times, especially Consumerand Supplier. At that time, I just learned it in my head, and didn't apply it to specific projects. When I met it next time, I still looked confused. I don't know if you have this feeling.

So we need to sum up the experience and lessons, we must understand the principles of the code, and then type it a few times, and try to apply it to our own projects to improve our coding ability.

The above is all the content of today. If you have different opinions or better ideas idea, please contact Ah Q. Add Ah Q to join the technical exchange group to participate in the discussion!

Guess you like

Origin blog.csdn.net/Qingai521/article/details/121530023