如何用方法引用替代Lambda满足SonarQube规则squid:S1612?
解决SonarQube规则
squid:S1612的方法引用问题,同时保证每次生成新实例 你遇到的这个问题很典型——直接用new Person()::id确实会踩坑,因为这个写法本质是先创建一个固定的Person实例,然后引用它的id方法,所以每次调用apply时都是在同一个实例上修改并返回,自然所有调用结果都是同一个对象,导致测试失败。
正确的解决方案:新增静态工厂方法(推荐)
最清晰且符合规则的方式是在Person类中新增一个静态工厂方法,把Lambda里的逻辑封装进去,然后直接引用这个静态方法:
public class Person { Integer id; String name; // 原有方法... public Person id(Integer id) { setId(id); return this; } public Person name(String name) { setName(name); return this; } /* 构造方法、getter、setter等... */ // 新增静态工厂方法 public static Person createWithId(Integer id) { return new Person().id(id); } }
然后在Simplifiers类中修改PERSON_1的定义:
public class Simplifiers { // 现在符合squid:S1612规则,且每次调用都会生成新实例 public static final Simplifier<Person> PERSON_1 = new Simplifier<>(Person::createWithId); public static final Simplifier<Person> PERSON_2 = new Simplifier<>( id -> { final Person action2 = new Person(); return action2.id(id); }); }
这样修改后,每次调用PERSON_1.simplify(id)都会调用Person.createWithId,而这个方法每次都会创建新的Person实例并设置id,完全满足测试要求,同时SonarQube的规则检查也会通过。
为什么new Person()::id不行?
再拆解一下这个写法的本质:
new Person()会立即创建一个Person实例,这个实例是固定的::id引用的是这个固定实例的id方法,方法签名是Person id(Integer id)- 当把这个方法引用作为
Function<Integer, Person>传递给Simplifier时,每次调用apply(id)都是在同一个实例上执行id(id),然后返回这个实例,所以所有调用返回的都是同一个对象,这就是测试失败的原因。
另一种不新增方法的写法(不推荐,可读性差)
如果不想新增静态方法,其实很难绕开Lambda实现纯方法引用(因为需要动态接收id参数并创建新实例),强行组合的写法可读性极差,比如:
// 这种写法看似用了方法引用,但本质还是嵌套Lambda,不符合规则要求 public static final Simplifier<Person> PERSON_1 = new Simplifier<>( id -> ((Supplier<Person>) Person::new).get().id(id) );
所以这种方式完全没必要,还是新增静态工厂方法更靠谱。
内容的提问来源于stack exchange,提问作者zolv
相关产品推荐
相关产品推荐

