让Style帮你减少JAVA的错误
Style是一个java8的函数式工具集,但不仅仅包括函数式,还有许多常用类库的增强
首先给出Style工具集坐标
请在github中查看release
中文文档坐标1 坐标2
(如果好用请您点个星哦~)
本文通过java程序员常犯的10个错误这篇文章,以及本人平时编码中遭遇的失误,给出使用Style工具集后的解决方案
点击链接查看引用文章。后面给出的是部分译文
数组转换为数组列表
原文:
将数组转换为数组列表,开发者经常会这样做:
List list = Arrays.asList(arr);
Arrays.asList()将返回一个数组内部是私有静态类的ArrayList,这不是java.util.ArrayList类,java.util.Arrays.ArrayList类有set()、 get()、 contains()方法,但是没有任何加元素的方法,因此它的大小是固定的。你应该这么做来创建一个真正的数组:
ArrayList arrayList = new ArrayList(Arrays.asList(arr));
ArrayList的构造函数能够接受一个集合类型,这也是java.util.Arrays.ArrayList的超类。
Style的解法
这样构建无非是为了更可读,以及编写更少的代码。
Style提供更直观的方式:
例如:
List<String> list = $(new ArrayList<String>(), "apple", "banana", "coconut");
或者:
List<String> list=new ArrayList<>();
$(list).add("apple").add("banana").add("coconut");
检查一个数组包含一个值
原文:
开发者经常这么做:
Set set = new HashSet(Arrays.asList(arr)); return set.contains(targetValue);
代码可以工作,但是没有必要首先转换列表到Set,转换一个列表到一个Set需要额外的时间。因此你可以把它简化为:
Arrays.asList(arr).contains(targetValue);
或
for(String s: arr){ if(s.equals(targetValue)) return true; } return false;
第一个比第二个更具可读性
Style的解法
更加具有可读性的操作:
// 直接获取
$(arr).findOne(e->e.equals(targetValue));
// 或者使用比jdk1.8更多功能的foreach循环
$(arr).forEach(e->{
if(e.equals(targetValue))
BreakWithResult(true);
return false;
});
这两种增强不仅在数组上提供,在任何iterable对象上都提供。
这种方式也可进行更复杂的操作,比如判断元素的某个属性是否等于制定值等,一切都可以通过lambda自由掌控。
在一个循环中从一个列表里删除一个元素
原文:
考虑下面删除元素的代码在迭代中的结果:
ArrayList list = new ArrayList(Arrays.asList("a", "b", "c", "d")); for (int i = 0; i < list.size(); i++) { list.remove(i); } System.out.println(list);
输出是:
[b, d]
该方法有一个严重的问题,当一个元素被删除时,列表收缩的大小以及指针改变了。所以想要在循环内利用指针删除多个元素是无法正常进行的。
这种情况下使用迭代器才是正确的方法,foreach循环在Java中的工作像是一个迭代器,但实际上并不是,考虑下面的代码:ArrayList list = new ArrayList(Arrays.asList("a", "b", "c", "d")); for (String s : list) { if (s.equals("a")) list.remove(s); }
它会报出ConcurrentModificationException异常。
相反下面这个就可以正常工作。ArrayList list = new ArrayList(Arrays.asList("a", "b", "c", "d")); Iterator iter = list.iterator(); while (iter.hasNext()) { String s = iter.next(); if (s.equals("a")) { iter.remove(); } }
.next()必须在.remove()之前被调用。在foreach循环中,编译器将在删除元素操作之后调用.next(),这也是导致ConcurrentModificationException异常的原因。
Style的解法
无需使用iterator,通过增强的foreach即可完成
$(list).forEach(e->{
if(e.equals("a"))
Remove();
});
更加可读,而且节约了代码量。
Mutable VS Immutable
原文:
Immutable对象有很多优势,比如简单、安全等等。但它要求每一个不同的值都需要有一个不同的对象,而太多的对象可能会导致垃圾收集的高成本。所以对Mutable和Immutable的选择应该有一个平衡点。
一般来说,Mutable对象用于避免产生过多的中间对象,经典的例子是连接大量的字符串数。如果你使用Immutable字符串,那么会产生很多符合垃圾收集条件的对象。这对CPU是浪费时间和精力的,当其可以使用Mutable对象作为正确的解决方案。(如StringBuilder)String result=""; for(String s: arr){ result = result + s; }
这里还有一些其他Mutable对象可取的情况。例如mutable对象传递到方法中允许你在不跳过太多语法的情况下收集多个结果。另一个例子是排序和过滤,你可以构建一个带有原有集合的方法,并返回一个已排序的,不过这对大的集合来说会造成更大的浪费。
Style的解法
Style提供readOnly功能,可以轻松让一个带接口的对象变为只读对象。详情请见文档。
例如
List<String> readOnlyList=readOnly(list);
readOnlyList.get(0); // 可以正常执行
readOnlyList.add("durian"); // 将抛出异常
头疼的Null值
实际上,null值常常出现。一般来说我们可以先判断它是否为空,若为空则初始化这个变量。
比如
if(null==value)
value="hello world";
System.out.println(value);
Style的解法
Style提供avoidNull,你可以这样实现上述代码:
System.out.println(avoidNull(value, ()->"hello world");
// 也可以更直接一些,把后面的lambda表达式换成字符串"hello world"
其他
Style中所有表达式和循环都带有返回值,比如if, switch, for, for-to-step, while, forEach/forThose等。大部分情况下他们可以让程序变得更简洁。
此外还有数十个好用的功能等你去发现~