Java8-lambda

问题

之前写了一个小的燃烧计算程序,其中有一部分是为了计算混合组分的特性参数,用了下面的一些代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public interface ComponentCal extends Map<String, Double> {
public double getDensity();

public double getQd();

public double getQg();

public double getL_O2();

public double getCp(double temperature);

public double getC();

public double getH();
}

其中各get方法是读取各成分各自的特性参数,然后计算成混合组分的参数。

方法一

最开始写的时候用最苯的方法,用是for-each方法读取每个,然后sum方法求和。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class GasComponent extends HashMap<String, Double> implements ComponentCal {

private PropertyRepository propertyRepository;

@Inject
public void setPropertyRepository(PropertyRepository propertyRepository) {
this.propertyRepository = propertyRepository;
}

public double getDensity() {
double sum = 0.0;
for (Entry<String, Double> item : this.entrySet()) {
sum += propertyRepository.getByName(item.getKey()).getDensity() * item.getValue();
}
return sum * 0.01;
}

public double getQd() {
double sum = 0.0;
for (Entry<String, Double> item : this.entrySet()) {
sum += propertyRepository.getByName(item.getKey()).getQd() * item.getValue();
}
return sum;
}

/*
...
*/
}

方法二

lambda取代for-each,这个感觉和C#的LINQ很像哦。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class GasComponent extends HashMap<String, Double> implements ComponentCal {

private PropertyRepository propertyRepository;

@Inject
public void setPropertyRepository(PropertyRepository propertyRepository) {
this.propertyRepository = propertyRepository;
}

public double getDensity() {
return this.entrySet().stream().mapToDouble(item -> propertyRepository.getByName(item.getKey()).getDensity() * item.getValue()).sum() * 0.01;
}

public double getQd() {
return this.entrySet().stream().mapToDouble(item -> propertyRepository.getByName(item.getKey()).getQd() * item.getValue()).sum();
}

/*
...
*/
}

方法三

上面GasComponent实现ComponentCal各个get方法时,只是有一点点不同,于是想应该可以把其简化,最开始想到的就是用反射,方法名用String来代替,调用的时候传递一个String就行了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public class GasComponent extends HashMap<String, Double> implements ComponentCal {
private PropertyRepository propertyRepository;

@Inject
public void setPropertyRepository(PropertyRepository propertyRepository) {
this.propertyRepository = propertyRepository;
}

private double getPropertySum(String methodName, double factor) throws NoSuchMethodException, SecurityException {
Method method;
method = Property.class.getMethod(methodName);
return this.entrySet().stream().mapToDouble(item -> {
try {
return Double.parseDouble(method.invoke(propertyRepository.getByName(item.getKey())).toString()) * item.getValue();
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return 0.0;
}).sum() * factor;
}

public double getDensity() {
double sum = 0.0;
try {
sum = getPropertySum("getDensity", 0.01);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
return sum;
}

public double getQd() {
double sum = 0.0;
try {
sum = getPropertySum("getQd", 1.0);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
return sum;
}

/*
...
*/
}

方法四

我去,看着反射方法里面的各种try-catch好烦啊,正好前段时间在学习Java8 In Action,于是想到了函数式编程里讲到的东东。试试吧。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class GasComponent extends HashMap<String, Double> implements ComponentCal {

private PropertyRepository propertyRepository;

@Inject
public void setPropertyRepository(PropertyRepository propertyRepository) {
this.propertyRepository = propertyRepository;
}

@FunctionalInterface
private interface Functional {
double getProperty(Property property);
}

private Functional fDensity = p->p.getDensity();
private Functional fQd = p->p.getQd();
private Functional fQg = p->p.getQg();
private Functional fL_O2 = p->p.getL_O2();
private Functional fC = p->p.getC();
private Functional fH = p->p.getH();

private double getPropertySum(Functional f, double factor) {
return this.entrySet().stream().mapToDouble(item -> f.getProperty(propertyRepository.getByName(item.getKey())) * item.getValue()).sum() * factor;
}

public double getDensity() {
return getPropertySum(fDensity, 0.01);
}

public double getQd() {
return getPropertySum(fQd, 1.0);
}

/*
...
*/
}

哈哈哈,各种清爽啊。发现其实可以直接把labmda表达式用参数形式传过去嘛。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class GasComponent extends HashMap<String, Double> implements ComponentCal {

private PropertyRepository propertyRepository;

@Inject
public void setPropertyRepository(PropertyRepository propertyRepository) {
this.propertyRepository = propertyRepository;
}

@FunctionalInterface
private interface Functional {
double getProperty(Property property);
}

private double getPropertySum(Functional f, double factor) {
return this.entrySet().stream().mapToDouble(item -> f.getProperty(propertyRepository.getByName(item.getKey())) * item.getValue()).sum() * factor;
}

public double getDensity() {
return getPropertySum(p -> p.getDensity(), 0.01);
}

public double getQd() {
return getPropertySum(p -> p.getQd(), 1.0);
}

/*
...
*/
}

Yeah,搞定,终于清爽了。 :)