当前位置:网站首页>The solution to the complexity brought by lambda expression
The solution to the complexity brought by lambda expression
2022-07-02 04:17:00 【Mingmingruyue senior】
One 、 background
Java 8 Of Lambda The expression is no longer “ New characteristics ”.
Many people once resisted Lambda expression , Now it's almost standard .
The most common in actual development is , Many people use Stream To handle collection classes .
But because of Lambda Expression abuse , The code becomes less readable , So how to solve ?
This article will discuss this problem , And give some solutions .
Two 、 view
about Lambda Expression or Stream They have different views .
2.1 Support
(1) Use Lambda Expressions can reduce the creation of classes or methods , It's simple to write .
Such as :
import java.util.HashMap;
import java.util.Map;
public class LambdaMapDemo {
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<>();
for (int i = 0; i < 10; i++) {
map.put(i, String.valueOf(i));
}
// It was written in the original way
for (Map.Entry<Integer, String> entry : map.entrySet()) {
System.out.println("k:" + entry.getKey() + " -> v:" + entry.getValue());
}
}
Use Lambda Writing
map.forEach((k, v) -> {
System.out.println("k:" + k + " -> v:" + v);
});
}
(2) Use Stream You can enjoy chain programming .
(3) Some people see others using , There seems to be some high-end , Or worry about being eliminated and use it a lot .
2.2 against
Some people are right lambda The expression disagrees .
(1) They think a lot of lambda The expression is written The code is not easy to understand .
(2) There are many old people in the team , It's not easy to accept new things , The use of Lambda expression .

Such as :Stream The widespread use of has brought many template methods .
List<String> tom = dogs.stream().filter(dog -> dog.getName().startsWith("tom")).map(dog -> dog.getName().toLowerCase()).collect(Collectors.toList());
Even often someone will be in Stream Of map Write a lot of conversion code in functions .
import lombok.Data;
@Data
public class DogDO {
private String name;
private String nickname;
private String address;
private String owner;
}
DogVO and DogDO Structure is the same .
List<DogVO> result = dogs.stream().filter(dog -> dog.getName().startsWith("tom")).map(dog -> {
DogVO dogVO = new DogVO();
dogVO.setName(dog.getName());
dogVO.setAddress(dog.getAddress());
dogVO.setOwner(dog.getOwner());
return dogVO;
}).collect(Collectors.toList());
What's more, the whole Stream The expression result is passed into the method as a parameter :
result.addAll(dogs.stream().filter(dog -> dog.getName().startsWith("tom")).map(dog -> {
DogVO dogVO = new DogVO();
dogVO.setName(dog.getName());
dogVO.setAddress(dog.getAddress());
dogVO.setOwner(dog.getOwner());
return dogVO;
}).collect(Collectors.toList()));
When a large number of the above phenomena occur in a method , The code can't be read .
(3) Some people are worried about Stream It will bring some side effects .
2.3 My opinion
Lambda It's a double-edged sword , When using, you need to grasp the degree .
How to decode Lambda The complexity of expressions , Look at part four .
3、 ... and 、 Underlying principle
See my other article
《 In depth understanding of Lambda expression 》
Four 、 Suggest
Lambda It simplifies the code , But grasp the degree , If abused lambda expression , Code readability can be poor .
4.1 Use method reference
List<String> names = new LinkedList<>();
names.addAll(users.stream().map(user -> user.getName()).filter(userName -> userName != null).collect(Collectors.toList()));
names.addAll(users.stream().map(user -> user.getNickname()).filter(nickname -> nickname != null).collect(Collectors.toList()));
It can be optimized to :
List<String> names = new LinkedList<>();
names.addAll(users.stream().map(User::getName).filter(Objects::nonNull).collect(Collectors.toList()));
names.addAll(users.stream().map(User::getNickname).filter(Objects::nonNull).collect(Collectors.toList()));
4.2 Extract complex code
For some complex logic 、 For some logic that needs to be reused , It is recommended to encapsulate into a separate class .
Such as Stream Commonly used in parameters java.util.function Under bag Predicate 、Function 、Consumer Classes and Comparator etc. .
result.addAll(dogs.stream().filter(dog -> dog.getName().startsWith("tom")).map(dog -> {
DogVO dogVO = new DogVO();
dogVO.setName(dog.getName());
dogVO.setAddress(dog.getAddress());
dogVO.setOwner(dog.getOwner());
return dogVO;
}).collect(Collectors.toList()));
The transformation is as follows :
import java.util.function.Function;
public class DogDO2VOConverter implements Function<DogDO, DogVO> {
@Override
public DogVO apply(DogDO dogDO) {
DogVO dogVO = new DogVO();
dogVO.setName(dogDO.getName());
dogVO.setAddress(dogDO.getAddress());
dogVO.setOwner(dogDO.getOwner());
return dogVO;
}
}
reform
result.addAll(dogs.stream().filter(dog -> dog.getName().startsWith("tom")).map(new DogDO2VOConverter()).collect(Collectors.toList()));
Or define static methods
public class DogDO2VOConverter {
public static DogVO toVo(DogDO dogDO) {
DogVO dogVO = new DogVO();
dogVO.setName(dogDO.getName());
dogVO.setAddress(dogDO.getAddress());
dogVO.setOwner(dogDO.getOwner());
return dogVO;
}
}
Just use method calls directly
result.addAll(dogs.stream().filter(dog -> dog.getName().startsWith("tom")).map(DogDO2VOConverter::toVo).collect(Collectors.toList()));
4.3 Don't put stream Put the operation in the method parameter
Just like the code above
result.addAll(dogs.stream().filter(dog -> dog.getName().startsWith("tom")).map(DogDO2VOConverter::toVo).collect(Collectors.toList()));
Many people write code , Like to be Stream Operations are placed in method parameters to save a local variable .
Personally, I am very opposed to this kind of behavior , This greatly reduces the readability of the code .
We should have Stream The operation of defines a return value with clear meaning , And then use .
Such as :
List<DogVO> toms = dogs.stream().filter(dog -> dog.getName().startsWith("tom")).map(DogDO2VOConverter::toVo).collect(Collectors.toList());
result.addAll(toms);
4.4 Lambda The expression should not be too long
Many people taste the sweetness of chain programming , Always like to write long code .
Such as :
Optional.ofNullable(dogs).orElse(new ArrayList<>()).stream().filter(dog -> dog.getName().startsWith("tom")).map(DogDO2VOConverter::toVo).collect(Collectors.toList()));
But it's hard to look at this code , When a lot of this code appears in a function , I'm spitting blood .
For this long Lambda Expression writing , It is recommended to split it as much as possible .
List<Dog> dogs = Optional.ofNullable(dogs).orElse(new ArrayList<>());
List<String> toms = dogs.stream().filter(dog -> dog.getName().startsWith("tom")).map(DogDO2VOConverter::toVo).collect(Collectors.toList()))
And then further dogs.stream This part of the logic is encapsulated into sub functions .
List<String> toms = getDogNamesStartWithTom(dogs)
4.5 Template methods use generic encapsulation
If you find a lot of use in your project Lambda, And the logic of many codes is very similar , Consider using generic wrapper classes to simplify your code .
Here are two simple examples .
4.5.1 Stream Object conversion
In the actual development, there are a lot of code like filtering before conversion :
List<DogVO> vos = dogs.stream().map(DogDO2VOConverter::toVo).collect(Collectors.toList())
In fact, this kind of writing is used to , But if a method appears many times, it is very unreadable .
After being encapsulated into a tool class, it is more concise :
List<DogVO> vos = MyCollectionUtils.convert(dogs,DogDO2VOConverter::toVo);
Tool class :
public class MyCollectionUtils {
public static <S, T> List<T> convert(List<S> source, Function<S, T> function) {
if (CollectionUtils.isEmpty(source)) {
return new ArrayList<>();
}
return source.stream().map(function).collect(Collectors.toList());
}
public static <S, T> List<T> convert(List<S> source, Predicate<S> predicate, Function<S, T> function) {
if (CollectionUtils.isEmpty(source)) {
return new ArrayList<>();
}
return source.stream().filter(predicate).map(function).collect(Collectors.toList());
}
}
By encapsulating common template methods into tool classes , It can greatly simplify the code when using .
4.5.2 Spring Strategic model cases
Such as 《 Skillfully use Spring Automatic injection implementation policy mode upgrade 》 I mentioned , The following cases :
Defining interfaces
public interface Handler {
String getType();
void someThing();
}
VIP User implementation :
import org.springframework.stereotype.Component;
@Component
public class VipHandler implements Handler{
@Override
public String getType() {
return "Vip";
}
@Override
public void someThing() {
System.out.println("Vip user , Take the logic here ");
}
}
Ordinary users realize :
@Component
public class CommonHandler implements Handler{
@Override
public String getType() {
return "Common";
}
@Override
public void someThing() {
System.out.println(" Ordinary users , Take the logic here ");
}
}
simulation Service Use in :
@Service
public class DemoService implements ApplicationContextAware {
private Map<String, List<Handler>> type2HandlersMap;
public void test(){
String type ="Vip";
for(Handler handler : type2HandlersMap.get(type)){
handler.someThing();;
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
Map<String, Handler> beansOfType = applicationContext.getBeansOfType(Handler.class);
beansOfType.forEach((k,v)->{
type2HandlersMap = new HashMap<>();
String type =v.getType();
type2HandlersMap.putIfAbsent(type,new ArrayList<>());
type2HandlersMap.get(type).add(v);
});
}
}
among setApplicationContext The code inside is very similar .
You can write tool classes
import org.apache.commons.collections4.MapUtils;
import org.springframework.context.ApplicationContext;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
public class BeanStrategyUtils {
// structure type To more than one bean Mapping
public static <K,B> Map<K, List<B>> buildTypeBeansMap(ApplicationContext applicationContext, Class<B> beanClass, Function<B,K> keyFunc) {
Map<K, List<B>> result = new HashMap<>();
Map<String, B> beansOfType = applicationContext.getBeansOfType(beanClass);
if(MapUtils.isEmpty(beansOfType)){
return result;
}
for(B bean : beansOfType.values()){
K type = keyFunc.apply(bean);
result.putIfAbsent(type,new ArrayList<>());
result.get(type).add(bean);
}
return result;
}
// structure type To single bean Mapping
public static <K,B> Map<K, B> buildType2BeanMap(ApplicationContext applicationContext, Class<B> beanClass, Function<B,K> keyFunc) {
Map<K, B> result = new HashMap<>();
Map<String, B> beansOfType = applicationContext.getBeansOfType(beanClass);
if(MapUtils.isEmpty(beansOfType)){
return result;
}
for(B bean : beansOfType.values()){
K type = keyFunc.apply(bean);
result.put(type,bean);
}
return result;
}
}
After transformation
@Service
public class DemoService implements ApplicationContextAware {
private Map<String, List<Handler>> type2HandlersMap;
public void test(){
String type ="Vip";
for(Handler handler : type2HandlersMap.get(type)){
handler.someThing();;
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
type2HandlersMap = BeanStrategyUtils.buildTypeBeansMap(applicationContext,Handler.class, Handler::getType);
}
}
A lot of people would say , Writing tools is also time-consuming .
however , After writing the tool method , Code repetition rate is reduced ; The code is more concise , Readability improvement ; Subsequent similar logic can realize code reuse , Development efficiency has also improved ; Fully staffed .
4.6 Use the reinforcement package
We talked about , You can reduce... By encapsulating tool classes Lambda The complexity of the code .
Besides , We can also consider using some enhancement packages to solve this problem .
4.6.1 StreamEx
Such as StreamEx
Maven rely on
https://mvnrepository.com/artifact/one.util/streamex
<!-- https://mvnrepository.com/artifact/one.util/streamex -->
<dependency>
<groupId>one.util</groupId>
<artifactId>streamex</artifactId>
<version>0.8.0</version>
</dependency>
Java 8 How to write it
Map<Role, List<User>> role2users = users.stream().collect(Collectors.groupingBy(User::getRole));
StreamEx How to write it :
Map<Role, List<User>> role2users = StreamEx.of(users).groupingBy(User::getRole);
The previous case
List<DogVO> vos = dogs.stream().map(DogDO2VOConverter::toVo).collect(Collectors.toList())
It can be changed to
List<DogVO> vos = StreamEx.of(dogs).map(DogDO2VOConverter::toVo).toList();
4.6.2 vavr
User documentation :https://docs.vavr.io/
Maven rely on
https://mvnrepository.com/artifact/io.vavr/vavr
<!-- https://mvnrepository.com/artifact/io.vavr/vavr -->
<dependency>
<groupId>io.vavr</groupId>
<artifactId>vavr</artifactId>
<version>1.0.0-alpha-4</version>
</dependency>
Java 8 Writing in Chinese :
// = ["1", "2", "3"] in Java 8
Arrays.asList(1, 2, 3)
.stream()
.map(Object::toString)
.collect(Collectors.toList())
vavr Writing in Chinese :
// = Stream("1", "2", "3") in Vavr
Stream.of(1, 2, 3).map(Object::toString)
4.7 Add notes to each step
If you use chain programming , If there are many steps , It is recommended to add notes to each step , It's easier to understand .
4.8 Some scenes don't have to Lambda expression
If you find that... Is used in a function Lambda Too much time ( In practice , You'll find that more than half of a function is lambda expression , A great headache ), You can consider some things that are not easy to understand Lambda Change the writing to normal , Usually readability will be greatly improved .
List<String> names = new LinkedList<>();
names.addAll(users.stream().map(User::getName).filter(Objects::nonNull).collect(Collectors.toList()));
names.addAll(users.stream().map(User::getNickname).filter(Objects::nonNull).collect(Collectors.toList()));
Optimize to
List<String> names = new LinkedList<>();
for(User user : users) {
String name = user.getName();
if(name!= null ){
names.add(name);
}
String nickname = user.getNickname();
if(nickname != null){
names.add(nickname);
}
}
Although the code is longer , But it's easier to understand .
You can also encapsulate this part of the logic into a sub function and give a meaningful name .
/** * Get name and nickname */
private List<String> getNamesAndNickNames(List<User> users) {
List<String> names = new LinkedList<>();
for (User user : users) {
String name = user.getName();
if (name != null) {
names.add(name);
}
String nickname = user.getNickname();
if (nickname != null) {
names.add(nickname);
}
}
return names;
}
Call directly when using :
List<String> names = getNamesAndNickNames(users);
In this way, the outer function can clearly know the intention of this part of logic , You don't need to look at so much code at all , Readability is greatly improved .
5、 ... and 、 reflection
Too much of a good thing , We use Lambda When the expression , Be sure not to ignore readability .
Lambda There is nothing wrong with the expression , The fault is that many people abuse Lambda expression .
We should pay attention to making trade-offs in the coding process , Master the degree .
This paper briefly discusses Lambda The pros and cons of expressions , Give yourself some ways to crack .
Hopefully that helped .
Of course , There may be many solutions , Welcome to add your comments. .
I hope you can strive to be a programmer with pursuit .
It's not easy to create , If this article helps you , Welcome to thumb up 、 Collection and attention , Your support and encouragement , It's the biggest driving force of my creation .
边栏推荐
- [live broadcast review] the first 8 live broadcasts of battle code Pioneer have come to a perfect end. Please look forward to the next one!
- Hands on deep learning (II) -- multi layer perceptron
- Playing with concurrency: what are the ways of communication between threads?
- [tips] use Matlab GUI to read files in dialog mode
- Wechat applet map annotation
- SQL:常用的 SQL 命令
- How to model noise data? Hong Kong Baptist University's latest review paper on "label noise representation learning" comprehensively expounds the data, objective function and optimization strategy of
- BiShe cinema ticket purchasing system based on SSM
- 蓝湖的安装及使用
- [untitled]
猜你喜欢

Actual combat | use composite material 3 in application

Delete the code you wrote? Sentenced to 10 months!

Recently, the weather has been extremely hot, so collect the weather data of Beijing, Shanghai, Guangzhou and Shenzhen last year, and make a visual map
![[source code analysis] NVIDIA hugectr, GPU version parameter server - (1)](/img/e1/620443dbc6ea8b326e1242f25d6d74.jpg)
[source code analysis] NVIDIA hugectr, GPU version parameter server - (1)

Installation et utilisation du lac bleu

C语言:逻辑运算和判断选择结构例题

【leetcode】74. Search 2D matrix

Typescript practice for SAP ui5

Spring moves are coming. Watch the gods fight

2022-07-01: at the annual meeting of a company, everyone is going to play a game of giving bonuses. There are a total of N employees. Each employee has construction points and trouble points. They nee
随机推荐
Target free or target specific: a simple and effective zero sample position detection comparative learning method
Li Kou interview question 02.08 Loop detection
Learn more about materialapp and common attribute parsing in fluent
First acquaintance with P4 language
A thorough understanding of the development of scorecards - the determination of Y (Vintage analysis, rolling rate analysis, etc.)
Pytorch-Yolov5从0运行Bug解决:
The first practical project of software tester: web side (video tutorial + document + use case library)
Opencv learning example code 3.2.4 LUT
Pytorch---使用Pytorch实现U-Net进行语义分割
《动手学深度学习》(二)-- 多层感知机
Www2022 | know your way back: self training method of graph neural network under distribution and migration
[C language] Dynamic Planning --- from entry to standing up
【毕业季·进击的技术er】年少有梦,何惧彷徨
Raspberry pie GPIO pin controls traffic light and buzzer
Wechat applet pull-down loading more waterfall flow loading
Monkey test
Pandora IOT development board learning (HAL Library) - Experiment 2 buzzer experiment (learning notes)
WPViewPDF Delphi 和 .NET 的 PDF 查看组件
蓝湖的安装及使用
First acquaintance with string+ simple usage (II)
