# 重复性管理——从泛值到泛型以及泛函（中）

2017/05/17 22:46

## 从高斯的求和故事说起

/** 求普通和 */
public static int sum() {
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
}
return sum;
}

## 更多的求和

/** 求平方和 */
public static int sum() {
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i * i;
}
return sum;
}

/** 求立方和 */
public static int sum() {
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i * i * i;
}
return sum;
}

## 去重的初步设想

public static void main(String[] args) {
sum(i);
sum(i * i);
sum(i * i * i);
}

public static int sum(Object exp) {
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += exp;
}
return sum;
}

public static int sum(Function f) {
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += f(i);
}
return sum;
}

public static int identity(int i) {
return i;
}

public static int square(int i) {
return i * i;
}

public static int cube(int i) {
return i * i * i;
}

public static void main(String[] args) {
sum(identity);
sum(square);
sum(cube);
}

## 传统的解决方案

### if-else， naive 的方式

public static void main(String[] args) {
int idSum = sum("identity");
int sqSum = sum("square");
int cbSum = sum("cube");

System.out.print(idSum + " " + sqSum + " " + cbSum);
}

public static int sum(String type) {
int sum = 0;
for (int i = 1; i <= 100; i++) {
int temp = 0;
if ("identity".equals(type)) {
temp = i;
} else if ("square".equals(type)) {
temp = i * i;
} else if ("cube".equals(type)){
temp = i * i * i;
} else {
// TODO error
}
sum += temp;
}
return sum;
}

### 多态策略（Polymorphism）

if-else 的方式很容易想到，但弊端也很明显，我们需要更好的解决方案。

public interface MyFunction {
public int apply(int i);
}

public static int sum(MyFunction f) {
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += f.apply(i);
}
return sum;
}

class Identity implements MyFunction {
@Override
public int apply(int i) {
return i;
}
}

class Square implements MyFunction {
@Override
public int apply(int i) {
return i * i;
}
}

class Cube implements MyFunction {
@Override
public int apply(int i) {
return i * i * i;
}
}

public static void main(String[] args) {
int idSum = sum(new Identity());
int sqSum = sum(new Square());
int cbSum = sum(new Cube());

System.out.println(idSum + " " + sqSum + " " + cbSum);
}

GoF: gang of four，就是写《设计模式》一书的四个家伙（四人帮）

### 匿名内部类（Anonymous Inner Class）

public static void main(String[] args) {
// 匿名类方式
int idSum = sum(new MyFunction() {
@Override
public int apply(int i) {
return i;
}
});

int sqSum = sum(new MyFunction() {
@Override
public int apply(int i) {
return i * i;
}
});

int cbSum = sum(new MyFunction() {
@Override
public int apply(int i) {
return i * i * i;
}
});

System.out.println(idSum + " " + sqSum + " " + cbSum);
}

### 反射方式（Reflection）

public class MathUtil {
public static int identity(int i) {
return i;
}

public static int square(int i) {
return i * i;
}

public static int cube(int i) {
return i * i * i;
}
}

Java 并不直接支持传递函数引用，但通过反射的方式，也还是能够间接得做到这一点的。我们来看下：

public static void main(String[] args) throws Exception {
// int.class 表示方法参数的类型
int idSum = sum(MathUtil.class.getMethod("identity", int.class));
int sqSum = sum(MathUtil.class.getMethod("square", int.class));
int cbSum = sum(MathUtil.class.getMethod("cube", int.class));

System.out.print(idSum + " " + sqSum + " " + cbSum);
}

public static int sum(Method m) throws Exception {
int sum = 0;
for (int i = 1; i <= 100; i++) {
// 第一个参数为 null 表示为静态方法，没有对象与之关联
// 返回值为 Object 类型，所以需要强制类型转换
sum += (int)m.invoke(null, i);
}
return sum;
}

JCP 社区的大佬们似乎也听到了群众的呼声，推出的 JDK 8.0 总算是在这个问题上有了交待。

• 可以用变量命名；
• 可以提供给过程作为参数；
• 可以由过程作为结果返回；
• 可以包含在数据结构中。

## 泛函的解决方案（lambda 式）

public static int sum(Function<Integer, Integer> f) {
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += f.apply(i);
}
return sum;
}

public static void main(String[] args) {
int idSum = sum(MathUtil::identity);
int sqSum = sum(MathUtil::square);
int cbSum = sum(MathUtil::cube);
}

int idSum = sum(i -> i);// 求普通和
int sqSum = sum(i -> i * i);// 求平方和
int cbSum = sum(i -> i * i * i);// 求立方和

int dbSum = sum(i -> 2 * i);// 求两倍和
int qrSum = sum(i -> i * i * i * i);// 求四次方和

double sinSum = sumf(Math::sin);

public static double sumf(Function<Double, Double> f) {
double sum = 0;
for (int i = 1; i <= 100; i++) {
sum += f.apply((double) i);
}
return sum;
}

double sqSum2 = sumf(i -> Math.pow(i, 2));
double cbSum2 = sumf(i -> Math.pow(i, 3));

4
32 收藏

6 评论
32 收藏
4