Java Stream来写算法——利用函数式接口写通用的性能测试代码

16 篇文章 0 订阅
16 篇文章 0 订阅

前言

写好了一种排序算法,想要测试一下其性能,代码无怪乎:先记录一下开始时间,然后执行算法,再记录一下结束时间,把结束时间与开始想减,就可以得出算法运行时间,通过这个时间值,可以估算一下算法运行效率。

面对的问题

  • 写不同的算法,可能使用不同的类
  • 不同的类中的算法代码,比如排序方法名,也可能各不相同
  • 所以为了能统计不同算法的运行效率,可能需要对不同类,不同的方法,写大量重复代码,尤其是反复写记录开始、结束时间,以及两者相减值的代码

解决方案

  • 可以使用反射机制来写通用代码,但这个有点复杂,暂不讨论
  • 使用函数式接口来处理,直接看代码

代码:排序的辅助类

import java.util.function.BiFunction;
import java.util.function.Consumer;

public class SortingHelper {
   // 不让在外部生成实例,可以不用此构造器,有也不影响什么
   private SortingHelper() {
   }

   // 这是一个奇葩的方法,是用来检查排序之后的数组,是否每一个元素都按照指定顺序排列好
   public static <E extends Comparable<E>> boolean isSorted(E[] arr) {
       for (int i = 1; i < arr.length; i++)
           if (arr[i - 1].compareTo(arr[i]) > 0)
               return false;
       return true;
   }
   // 排序的核心代码,用来交换不同索引值中的数据内容的
   public static <E> void swap(E[] arr, int position, int i) {
       if (position == i) return;
       E temp = arr[i];
       arr[i] = arr[position];
       arr[position] = temp;
   }
   /**
    * 核心逻辑方法
    * @param n:表示生成数组的长度,与生成数据的范围,比如5,数组长度是5,数据值为不超过5
    * @param biFunction:是生成数组的函数式接口,通过这个引用,可以生成有序的数组,或乱序的数组
    * @param consumer:调用排序算法
    * @param errInfo:提示信息,可以告诉当前调用算法的名称等
    * @param <E>
    */
   public static <E extends Comparable<E>> void showExerciseTime
           (int n, BiFunction<Integer, Integer, Integer[]> biFunction, Consumer<Integer[]> consumer, String info) {
       Integer[] integers = biFunction.apply(n, n);// 这里进行了简化,只生成Integer类型的数组
       long startTime = System.nanoTime();// 记录开始时间
       consumer.accept(integers);// 调用排序算法
       long endTime = System.nanoTime();// 记录结束时间
       double time = (endTime - startTime) / 1_000_000_000.0;// 计算耗时
       if (!isSorted(integers)) {// 如果发现没有按照指定顺序排列好数组,就报异常
           throw new RuntimeException(info);
       }
       System.out.printf("%s: Data length: %d, Time: %fs\n", info, n, time);// 显示信息,包括数组长度、耗时,算法名称
   }
}

代码:数组生成类

import java.util.Arrays;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.IntStream;

public class ArrayGenerator {
    private ArrayGenerator() {
    }

    public static Integer[] generateRandomArray(int len, int bound) {
        return IntStream.generate(() -> Double.valueOf(Math.random() * bound).intValue()).distinct()
                .limit(len).boxed().toArray(Integer[]::new);
    }


    public static Function<Integer, Integer[]> arrayGenerator = len ->
            IntStream.iterate(1, v -> v + 1).limit(len).boxed().toArray(Integer[]::new);
    public static Function<Integer, Integer[]> arrayGeneratorWithASCOrder = len ->
            IntStream.rangeClosed(0, len).boxed().toArray(Integer[]::new);
    public static BiFunction<Integer, Integer, Integer[]> arrayGeneratorWithRandomElement = (len, bound) ->
            IntStream.generate(() -> Double.valueOf(Math.random() * bound).intValue()).distinct().limit(len).boxed()
                    .toArray(Integer[]::new);

    public static void main(String[] args) {// main方法测试用
        System.out.println(Arrays.toString(ArrayGenerator.arrayGenerator.apply(5)));
        System.out.println(Arrays.toString(ArrayGenerator.arrayGeneratorWithRandomElement.apply(10, 15)));
        System.out.println(Arrays.toString(ArrayGenerator.arrayGeneratorWithASCOrder.apply(10)));
    }
}

代码:排序类

// 选择排序类
import com.tyhj.codecamp.algorithm.ArrayGenerator;
import com.tyhj.codecamp.algorithm.SortingHelper;

import java.util.Arrays;
import java.util.stream.IntStream;

public class SelectionSort {
    private SelectionSort() {
    }
    // 排序方法
    public static <E extends Comparable<E>> void sort(E[] arr) {
        for (int i = 0; i < arr.length; i++) {
            int position = i;
            for (int j = i; j < arr.length; j++) {
                if (arr[position].compareTo(arr[j]) > 0) {
                    position = j;
                }
            }
            SortingHelper.swap(arr, position, i);
        }
    }
    public static void main(String[] args) {
        IntStream.of(10_000, 100_000).forEach(v -> SortingHelper.showExerciseTime(v,
                ArrayGenerator::generateRandomArray, SelectionSort::sort, "Selection sort"));
    }
}
import com.tyhj.codecamp.algorithm.ArrayGenerator;
import com.tyhj.codecamp.algorithm.SortingHelper;

import java.util.stream.IntStream;
// 插入排序
public class InsertionSort {
    private InsertionSort() {
    }

    public static <E extends Comparable<E>> void sort(E[] arr) {
        System.out.println("Insertion Sort:");
        for (int i = 0; i < arr.length; i++)
            for (int j = i; j - 1 >= 0 && arr[j].compareTo(arr[j - 1]) < 0; j--)
                SortingHelper.swap(arr, j, j - 1);
    }
    public static void main(String[] args) {// 测试类
        IntStream.of(10_000, 100_000).forEach(v -> SortingHelper.showExerciseTime(v,
                ArrayGenerator::generateRandomArray, InsertionSort::sort, "Insertion sort"));
    }
}

小结

  1. 通过以上代码,本质上与自定义一个接口,然后让所有的算法来实现这个接口,最后在测试代码中使用这个接口中的方法来调用不同的实现,从而实现代码的简化与统一
  2. 现在这个自定义接口,可以使用Java官方提供的接口来统一实现,这是接口方式的一种统一的趋势。意义在于,可能未来不需要大量定义接口了,使用官方的统一接口,可以让代码可共享度有进一步的提升,是接口书写方法诸侯分治转为大一统的开始(当然这是一种自愿的,不愿意的,自己依然可以编写自己的接口规范,而希望更通用者,可采取这种统一的方式)
  3. 函数式接口的出现,带来另一个好处是,可以放弃编写大量的方法了,用类属性就可以实现方法级的实现,这在本文中“数组生成类”中就有鲜明的应用
  4. 流式的代码书写方式,真的是一种非常有趣的体验,把以前必须要使用for、while语句才能实现,而改用Stream流式写法来完成,真是一种妙不可言的体验
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值