此文章用于记录代码优化相关方法
1.Java Optional(JDK8以上)
下面代码中的List放入了很多Person对象,其中有的对象是null的,如果不加校验调用Person的getXXX()方法肯定会报空指针错误,一般我们采取的方案就是加上if判断:
public class DemoUtils {
public static void main(String[] args) {
List<Person> personList = new ArrayList<>();
personList.add(new Person());
personList.add(null);
personList.add(new Person("小明",10));
personList.add(new Person("小红",12));
for (Person person : personList) {
//if判空逻辑
if (person != null) {
System.out.println(person.getName());
System.out.println(person.getAge());
}
}
}
static class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
}
上面方法虽实现目的,但是代码繁多,Java新特性Stream API 与 Optional 提供了更加优雅的方法:
利用Stream API 中的 filter将队列中的空对象过滤掉,filter(Objects::nonNull)的意思是,list中的每个元素执行Objects的nonNull()方法,返回false的元素被过滤掉,保留返回true的元素。
public static void main(String[] args) {
List<Person> personList = new ArrayList<>();
personList.add(new Person());
personList.add(null);
personList.add(new Person("小明",10));
personList.add(new Person("小红",12));
//剔除之前
log.info("剔除之前:{}", JSON.toJSONString(personList));
//剔除null数据
List<Person> collect = personList.stream().filter(Objects::nonNull).collect(Collectors.toList());
log.info("剔除之后:{}", JSON.toJSONString(collect));
}
示例中的personList本身也可能会null,如果业务逻辑中要求personList为null时打日志报警,可以用Optional优雅的实现:
public static void main(String[] args) {
Person pnull1 = null;
Person pnull2 = null;
Person ps = new Person("小明", 10);
//返回 {"age":10,"name":"小明"} 取is not null 的值 。
Person person = Optional.ofNullable(ps).orElse(pnull1);
//返回 null 取is not null 的值 。如果两个都 is null 返回 null
Person person1 = Optional.ofNullable(pnull1).orElse(pnull2);
//返回 Optional.empty 获取pnull2的name,如果pnull2 is null 返回 isPresent=false ,且没有值
Optional<String> listString = Optional.ofNullable(pnull2).map(Person::getName);
//返回 小明 获取ps的name,如果ps is not null返回 isPresent=true ,有值
Optional<String> listString2 = Optional.ofNullable(ps).map(Person::getName);
//返回 小明 获取ps中的name,如果为空返回一个默认值
String result = Optional.ofNullable(ps)
.map(c -> c.getName())
.orElse("default");
//返回 default 获取pnull2中的name,如果为空返回一个默认值
String result2 = Optional.ofNullable(pnull2)
.map(c -> c.getName())
.orElse("default");
log.info("person:{}", JSON.toJSONString(person));
log.info("person1:{}", JSON.toJSONString(person1));
log.info("isPresent:{};listString:{}", listString.isPresent(), listString);
log.info("isPresent:{};listString2:{}", listString2.isPresent(), listString2);
log.info("result:{}", result);
log.info("result2:{}", result2);
//如果有null 直接返回,且return
Optional.ofNullable(ps).orElseGet(() -> {
log.error("personList为null!");
return new ArrayList<>();
}).stream().filter(Objects::nonNull).forEach(person -> {
//不为空则打印结果
log.info(person.getName());
log.info(person.getAge());
});
}
2.Stream
首先创建一个Person对象作为后面测试使用
class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
可以先看一下Stream的作用:代码看上去简洁有美观
// import java.util.*;
// import java.util.stream.Collectors;
@Test
void Test01() {
List<Person> personList = new ArrayList<>();
personList.add(new Person("小明", 10));
personList.add(new Person("小皇", 20));
personList.add(new Person("小菜", 30));
personList.add(new Person("小红", 40));
//获取数据
List<String> personListOut = personList.stream()
.filter(x -> x.getAge() > 15) //获取age>0
.sorted(Comparator.comparing(Person::getAge).reversed()) //根据age排序 reversed倒序
.map(Person::getName) //只获取name
.collect(Collectors.toList()); //转化菜list
log.info("personListOut:{}", personListOut);
log.info("personListOut:{}", JSON.toJSONString(personListOut));
}
下面介绍一些常用的使用:
1创建数组
/**
* 创建数组
*/
@Test
public void TestArrayStream() {
//1.通过Arrays.stream
//1.1基本类型
int[] arr = new int[]{1, 2, 3, 4};
IntStream intStream = Arrays.stream(arr);
log.info("intStream:{}", JSON.toJSONString(intStream));
//1.2引用类型
Person[] personArray = new Person[]{new Person("a", 10), new Person("b", 20)};
Stream<Person> personStream = Arrays.stream(personArray);
personStream.forEach(c -> log.info("personStream:{}", JSON.toJSONString(c)));
//2.通过Stream.of
Stream<Integer> stream1 = Stream.of(10, 20, 30, 40);
stream1.forEach(c -> log.info("stream1:{}", c.toString()));
}
2大小写转化
/**
* map把一种类型的流转换为另外一种类型的流
*/
@Test
public void testMap() {
String[] arr = new String[]{"yes", "YES", "no", "NO"};
// 把所有大写全部转化为小写
List<String> collect = Arrays.stream(arr).map(x -> x.toLowerCase()).collect(Collectors.toList());
log.info("collect:{}", JSON.toJSONString(collect));
// 把所有小写全部转化为大写
List<String> collect2 = Arrays.stream(arr).map(x -> x.toUpperCase()).collect(Collectors.toList());
log.info("collect2:{}", JSON.toJSONString(collect2));
}
3filter:过滤流, 筛选数据
/**
* filter:过滤流, 筛选数据
*/
@Test
public void testFilter() {
Integer[] arr = new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
List<Integer> collect = Arrays.stream(arr).filter(x -> x > 4 && x < 9).collect(Collectors.toList());
log.info("collect:{}", collect);
}
4.fileMap
/**
* flapMap:多个list/数组合并为一个
*/
@Test
public void testFlapMap() {
String[] arr1 = {"a", "b", "c", "d"};
String[] arr2 = {"1", "2", "3", "4"};
List<String> collect = Stream.of(arr1, arr2).flatMap(Arrays::stream).collect(Collectors.toList());
List<String> strings = new ArrayList<>();
strings.add("1");
strings.add("2");
List<String> strings2 = new ArrayList<>();
strings2.add("a");
strings2.add("b");
strings2.add("a");
List<Object> collect1 = Stream.of(strings, strings2).flatMap(Collection::stream).collect(Collectors.toList());
log.info("collect:{}", collect);
log.info("size:{};collect1:{}", collect1.size(), collect1);
}
5.skip和limit
/**
* skip,跳过前n个数据;limit,限制从流中获得前n个数据
*/
@Test
public void testSkip() {
String[] arr = {"1", "22", "2233", "3", "5"};
List<String> collect = Arrays.stream(arr).skip(1).limit(3).collect(Collectors.toList());
log.info("collect:{}", collect);
}
6.聚合操作
/**
* 聚合操作
*/
@Test
public void polymerization() {
String[] arr = {"ax", "abb", "bccc", "cdddd"};
//获取最大值
Stream.of(arr).max(Comparator.comparing(String::length)).ifPresent(System.out::println);
//获取最小值
Stream.of(arr).min(Comparator.comparing(String::length)).ifPresent(System.out::println);
//获取数量
log.info("cunt:{}", Stream.of(arr).count());
//获取长度>1的第一个 如果没有符合条件的数据 就返回other
String str = Stream.of(arr).parallel().filter(x -> x.length() > 1).findFirst().orElse("other");
log.info("str:{}", str);
//findAny 找到所有匹配的元素,对并行流十分有效, 只要在任何片段发现了第一个匹配元素就会结束整个运算
Optional<String> any = Stream.of(arr).parallel().filter(x -> x.length() > 1).findAny();
log.info("any:{}", JSON.toJSONString(any));
//anyMatch 是否含有匹配元素
Boolean aBoolean = Stream.of(arr).anyMatch(x -> x.startsWith("a"));
log.info("aBoolean:{}", aBoolean);
}
7.聚合计算
/**
* 聚合计算
*/
@Test
public void calculation() {
List<Person> personList = new ArrayList<>();
personList.add(new Person("小明", 10));
personList.add(new Person("小皇", 20));
personList.add(new Person("小菜", 30));
personList.add(new Person("小红", 40));
IntSummaryStatistics summaryStatistics = personList.stream().collect(Collectors.summarizingInt(Person::getAge));
log.info("getAverage->{}", summaryStatistics.getAverage());//平均值
log.info("getMax->{}", summaryStatistics.getMax());//最大值
log.info("getMin->{}", summaryStatistics.getMin());//最小值
log.info("getCount->{}", summaryStatistics.getCount());//数量
log.info("getSum->{}", summaryStatistics.getSum());//累加
}
8.并行
在 Java 8 中, 集合接口有两个方法来生成流: stream() − 为集合创建串行流。 parallelStream() − 为集合创建并行流。
有时候parallelStream创建并行流失败 可以考虑使用一下方式
测试并发以及普通的效率(并且次数越多-差距越大)
/**
* 测试 并发 每个执行 99999999*4次
*/
@Test
public void parallel() {
List<Person> personList = new ArrayList<>();
personList.add(new Person("小明", 10));
personList.add(new Person("小皇", 20));
personList.add(new Person("小菜", 30));
personList.add(new Person("小红", 40));
List<Person> personListx = new ArrayList<>();
//region 并发
Long startTime = System.currentTimeMillis();
List<Object> collect = personList.stream().parallel().map(c -> {
for (int i = 0; i < 99999999; i++) {
String name = i + "";
new Person(name, i);
}
return null;
}).collect(Collectors.toList());
Long endTime = System.currentTimeMillis();
log.info("并发耗时:{}", endTime - startTime);
//endregion
//region 普通
Long startTime2 = System.currentTimeMillis();
for (Person person : personList) {
for (int i = 0; i < 99999999; i++) {
String name = i + "";
new Person(name, i);
}
}
Long endTime2 = System.currentTimeMillis();
log.info("普通耗时2:{}", endTime2 - startTime2);
//endregion
}
3.拓展
3.1除了lamda表达式筛选数据外,还有一种 不过感觉没有lamda简洁,此处只是作为了解一下
public List<Brand> list(Map<String, Object> searchMap) {
Example example = new Example(Brand.class);
//封装查询条件
Example.Criteria criteria = example.createCriteria();
if (searchMap!=null){
//品牌名称(模糊) like %
if (searchMap.get("name")!=null && !"".equals(searchMap.get("name"))){
criteria.andLike("name","%"+searchMap.get("name")+"%");
}
//按照品牌首字母进行查询(精确)
if (searchMap.get("letter")!=null && !"".equals(searchMap.get("letter"))){
criteria.andEqualTo("letter",searchMap.get("letter"));
}
}
List<Brand> brandList = brandMapper.selectByExample(example);
return brandList;
}