你的位置:首页 > 信息动态 > 新闻中心
信息动态
联系我们

java1.8 流式计算:利用接口的函数式编程 + 链式编程

2021/12/8 2:06:39

java1.8 流式计算:利用接口的函数式编程 + 链式编程

文章目录

    • java1.8 流式计算:利用接口的函数式编程 + 链式编程
      • 1、流式计算
        • 1)ArrayList和Stream关联的底层解析(Collection的default方法)
        • 2)Stream流计算
      • 2、四大函数式接口(流计算的核心)
        • 1)@FunctionalInterface注解 & "::"符号
        • 2)Function
        • 3)Predicate
        • 4)Consumer (无返回)
        • 5)Supplier(有返回)
      • 3、例子

1、流式计算

参考

  • Java - Stream 流式计算_DJun的博客-CSDN博客
  • java接口中的default方法

1)ArrayList和Stream关联的底层解析(Collection的default方法)

在java的流式计算中,以list集合为例,由于ArraylistLinkedList实现List接口,而List接口则继承Collection接口,并且Collection接口中有default关键字修饰的Stream()方法(接口中可以对方法进行实现),因此实现类ArrayList继承了Collectiondefault方法(stream()等),并且可以通过a_list.stream()获取返回的Stream对象

//List接口
public interface List<E> extends Collection<E> {
    ...
}

//ArrayList类
public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    ...
}

//Collection接口
public interface Collection<E> extends Iterable<E> {
    ...
    @Override
    default Spliterator<E> spliterator() {
        return Spliterators.spliterator(this, 0);
    }
    
    default Stream<E> stream() {
        return StreamSupport.stream(spliterator(), false);
    }
}

在这里插入图片描述

这里有点绕口,要细品,且注意两个知识点:

  • 由于集合中加入的对象类型不确定,这里都使用了泛型来表示,使得待会获得的Stream对象类型也带泛型。

  • 实现类会继承接口中的default方法,比如:https://blog.csdn.net/wf13265/article/details/79363522

    public interface A {
    	public default void a(){
    		System.out.println("这是A");
    	}
    }
    public class Test implements A{
    	
    }
    
    public class Main {
    	public static void main(String[] args) {
    		Test t = new Test();
    		t.a();  //执行接口A中默认的方法
    	}
    }
    

这里还是补充一下:

  • 集合对象是通过Collection接口中的default stream()方法获取Stream对象的。

  • 而Stream毕竟是一个接口,需要有个实现类,这里很明确的是,Stream的实现类只有一个ReferencePipeline

在这里插入图片描述

该类对象主要是在Collection接口中的default stream()中,通过StreamSupport静态方法来创建:

public final class StreamSupport {
    public static <T> Stream<T> stream(Spliterator<T> spliterator, boolean parallel) {
        Objects.requireNonNull(spliterator);
        return new ReferencePipeline.Head<>(spliterator,
                                            StreamOpFlag.fromCharacteristics(spliterator),
                                            parallel);
    }
}

2)Stream流计算

​ 集合对象通过Collection默认的stream()获取Stream对象,接着通过Stream的filter等函数,通过传入不同类型的四种函数式接口@FunctionalInterface注解过的接口),并实现其中唯一的方法,来实现链式编程,完成集合对象的过滤(stream),排序,映射最终结果(T)的输出等。

public interface Stream<T> extends BaseStream<T, Stream<T>> {

    Stream<T> filter(Predicate<? super T> predicate);
    
    <R> Stream<R> map(Function<? super T, ? extends R> mapper);
    
    Stream<T> limit(long maxSize);
    
    void forEach(Consumer<? super T> action);
}

Java 8 引入了流式操作(Stream),通过该操作可以实现对集合(Collection)的并行处理和函数式操作。用周阳大神的话说就是:SQL就是JAVA,JAVA就是SQL。使用java.util.stream包中的Stream接口即可完成SQL中的计算、order by、where等操作。

根据操作返回的结果不同,流式操作分为中间操作和最终操作两种最终操作返回一特定类型的结果,而中间操作返回流本身,这样就可以将多个操作依次串联起来。根据流的并发性,流又可以分为串行和并行两种。流式操作实现了集合的过滤、排序、映射等功能

参考Java 8之流式计算_阳阳的博客-CSDN博客_java流式计算

这里再啰嗦一句:Stream是一个接口,而Stream只有一个实现类,即ReferencePipeline

一个案例搞清楚 Stream 的计算方式

按以下条件筛选:

1、ID 为偶数

2、age>23

3、name转为大写字母

4、按用户名字母倒叙排列

5、只输出一个用户

public void streamCalcDemo() {
    User user1 = new User(1, 18, "lisa");
    User user2 = new User(2, 19, "pika");
    User user3 = new User(3, 20, "sandy");
    User user4 = new User(4, 35, "alice");
    User user5 = new User(6, 24, "flask");
    List<User> list = Arrays.asList(user1, user2, user3, user4, user5);

    list.stream()
    .filter(u -> {return u.getId() % 2 == 0;})   //filter参数是
    .filter(u -> {return u.getAge() > 23; })
    .map((u) -> {
        u.setName(u.getName().toUpperCase(Locale.ROOT));
        return u;
    })
    // String 类中自带 compareTo() 方法
    // 不是很复杂的排序都不需要实现Comparator接口
    .sorted((u1,u2)->{return u2.getName().compareTo(u2.getName());})
    .limit(1)
    .forEach(item->{
        System.out.println(item.toString());
    });
}

@Data
@ToString
@AllArgsConstructor
class User {
    private int id;
    private int age;
    private String name;
}

2、四大函数式接口(流计算的核心)

参考

  • Java - Stream 流式计算_DJun的博客-CSDN博客
  • Java 8之流式计算_阳阳的博客-CSDN博客_java流式计算
  • Java双冒号(::)运算符详解

1)@FunctionalInterface注解 & "::"符号

java8 lambda 内部接口需要@FunctionalInterface这个注解,这个注解是一个说明性质的注解

  • @FunctionalInterface注解的接口只能有一个抽象方法
  • @FunctionalInterface只能用于注解接口而不能用在class以及枚举上.
  • @FunctionalInterface注解的符合规则的接口, 可以用lambda表达式.
public class Main {
    public static void main(String[] args) throws Exception {

        List<String> list = Arrays.asList("aaaa", "bbbb", "cccc");
        list.forEach(s -> System.out.println(s));  //forEach传入的是consumer接口(入参,无返回)
    }
}

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

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

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

参考java8获取list对象中某个字段最大值的对象 - Mark_ZSQ - 简书,

@Test
public void test() {
    List<Sensor> sensorMongoList = Lists.newArrayList();
    Sensor sensor = new Sensor();
    sensor.setId("123123");
    sensor.setNum("1");
    sensorMongoList.add(sensor);

    Sensor sensorTwo = new Sensor();
    sensorTwo.setId("3423423");
    sensorTwo.setNum("2");
    sensorMongoList.add(sensorTwo);

    Sensor sensor1 = sensorMongoList.stream().max(Comparator.comparing(Sensor::getNum)).get();
    String num = sensor1.getNum();
    num = String.valueOf(Integer.parseInt(num) + 1);
    System.err.println(num);

}

这里的comparing函数的参数是Function接口

public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
            Function<? super T, ? extends U> keyExtractor){
    Objects.requireNonNull(keyExtractor);
        return (Comparator<T> & Serializable)
            (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
}

Sensor::getNum表示Sensor类中的getNum方法

2)Function

函数型接口:有入参,有返回值

//@detail
@FunctionalInterface
public interface Function<T, R> {

    /**
     * Applies this function to the given argument.
     *
     * @param t the function argument
     * @return the function result
     */
    R apply(T t);
}
public void testFunction() {
    // JDK1.8之前的写法
    Function<String, String> f1 = new Function<String, String>() {
        @Override
        public String apply(String s) {
            return s;
        }
    };
    // 替换Lambda写法
    Function<String, String> f2 = (str) -> {return str;};
    // 精简写法
    Function<String, String> f3 = str -> str;
    
    System.out.println(f1.apply("hello"));
    System.out.println(f2.apply("hello"));
    System.out.println(f3.apply("hello"));
}
---
hello
hello
hello    

3)Predicate

断定型接口有入参,返回布尔值

//@detail
@FunctionalInterface
public interface Predicate<T> {

    /**
     * Evaluates this predicate on the given argument.
     *
     * @param t the input argument
     * @return {@code true} if the input argument matches the predicate,
     * otherwise {@code false}
     */
    boolean test(T t);
}
public void testPredicate() {
    Predicate<String> predicate = s -> s.contains("abc");
    System.out.println(predicate.test("helloabc"));
}
---
true

4)Consumer (无返回)

消费型接口:有入参,没有返回值

@FunctionalInterface
public interface Consumer<T> {

    /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
    void accept(T t);
}
public void testConsumer() {
    Consumer<String> consumer = s -> System.out.println(s);
    consumer.accept("hello");
}
---
hello    

5)Supplier(有返回)

供给型接口:没有参数,只有返回值

@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}

public void testSupplier() {
    Supplier<String> supplier = () -> "hello";
    System.out.println(supplier.get());
}
---
hello

3、例子

/**在多个最优解中按照其他策略进行排序,选择得分最高的*/
    public OptimalSolWithStrategies getBestInOptimalSols(List<OptimalSolWithStrategies>os_list, List<Integer> cl_list) {

        List<Job> optimalSol = new ArrayList<Job>();
        //从第二个策略开始级联过滤
        for(int i=1; i < cl_list.size();i++) {
            if(cl_list.get(i) == 0){
                float max_val = os_list.stream().max(Comparator.comparing(OptimalSolWithStrategies::getPriorityPer)).get().getPriorityPer();
                List<OptimalSolWithStrategies> temp_list = new ArrayList<OptimalSolWithStrategies>();
                os_list.stream().filter(p->{return p.getPriorityPer() >= max_val;}).forEach(p-> {temp_list.add(p);});//小于max_val的最优解存在temp_list中
                os_list = temp_list;
            }
            else if(cl_list.get(i) == 1){
                float max_val = os_list.stream().max(Comparator.comparing(OptimalSolWithStrategies::getNumPer)).get().getNumPer();
                List<OptimalSolWithStrategies> temp_list = new ArrayList<OptimalSolWithStrategies>();
                os_list.stream().filter(p->{return p.getNumPer() >= max_val;}).forEach(p-> {temp_list.add(p);});//小于max_val的最优解存在temp_list中
                os_list = temp_list;
            }
            else if(cl_list.get(i) == 2){
                float max_val = os_list.stream().max(Comparator.comparing(OptimalSolWithStrategies::getTimePer)).get().getTimePer();
                List<OptimalSolWithStrategies> temp_list = new ArrayList<OptimalSolWithStrategies>();
                os_list.stream().filter(p->{return p.getTimePer() >= max_val;}).forEach(p-> {temp_list.add(p);});//小于max_val的最优解存在temp_list中
                os_list = temp_list;
            }
            else if(cl_list.get(i) == 3){
                float max_val = os_list.stream().max(Comparator.comparing(OptimalSolWithStrategies::getResolutionPer)).get().getResolutionPer();
                List<OptimalSolWithStrategies> temp_list = new ArrayList<OptimalSolWithStrategies>();
                os_list.stream().filter(p->{return p.getResolutionPer() >= max_val;}).forEach(p-> {temp_list.add(p);});//小于max_val的最优解存在temp_list中
                os_list = temp_list;
            }
        }
        return os_list.get(0);
    }