Java8的Stream API使用
前言
这次想介绍一下Java Stream的API使用,最近在做一个新的项目,然后终于可以从老项目的祖传代码坑里跳出来了。项目用公司自己的框架搭建完成后,我就想着把JDK版本也升级一下吧(之前的项目,最高就能用JDK7),但是后来发现公司的项目部署打包平台最高只支持到JDK8。那好吧,既然就支持到JDK8,也能满足日常需求了(要啥自行车),升级到JDK8后,在搭建完项目架构后,就开始写一些基础逻辑。其中就用到了一些JDK8的Stream。但是我的同事在看我的代码的时候表示看不懂。确实,这个我也承认,Lambda表达式虽然代码简洁,但是不会用的人会觉得它的可读性不是太好。所以这次就结合自己使用经验来介绍一下Java Stream的一些功能。
从遍历到Stream操作
Oracle 公司于 2014 年 3 月 18 日发布 Java 8,Java8主要是在原来面向对象的基础上增加了函数式编程的能力。这样就出现了在Java中使用Lambda表达式,将一个函数作为方法的参数来进行传递。Java8的Stream就是典型的例子,Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。
例子:
List numbers = new ArrayList<>();
numbers.add(3);
numbers.add(4);
numbers.add(8);
numbers.add(16);
numbers.add(19);
numbers.add(27);
numbers.add(23);
numbers.add(99);
numbers.add(15);
numbers.add(32);
numbers.add(5);
numbers.add(232);
numbers.add(56);
int count = 0;
for(Integer i:numbers){
if(i>20){
count++;
}
}
System.out.println("count:"+count);
如上遍历的代码转换成使用Stream的API来实现如下:
long count = numbers.stream().filter(i->i>20).count();
System.out.println("count:"+count);
正常的遍历用Stream一行就可以实现了。
下面是一个使用了Stream API实现的流程图。
转换成Java代码就是
Integer transactionsIds =
roomList.stream()
.filter(b -> b.getLength() == 10)
.sorted((x,y) -> x.getHigh() - y.getHigh())
.mapToInt(Room::getWidth).sum();
创建Stream
Arrays.stream()
当在日常编程中面对的是一个数组,也可以使用Arrays.stream()方法来使用Stream
Integer[] array = new Integer[]{3,4,8,16,19,27,23,99,76,232,33,96};
long count = Arrays.stream(array).filter(i->i>20).count();
Stream.of()
当面对数组时除了可以使用Arrays.stream()方法外,还可以使用Stream将需要的数组转成Stream。这个方法不但支持传入数组,将数组转成Stream,也支持传入多个参数,将参数最终转成Stream
Integer[] array = new Integer[]{3,4,8,16,19,27,23,99,76,232,33,96};
long count = Stream.of(array).filter(i->i>20).count();
long sum = Stream.of(12,77,59,3,654).filter(i->i>20).mapToInt(Integer::intValue).sum();
System.out.println("count:"+count+",sum:"+sum);
其实Stream.of()也是调用的Stream.of()方法来实现的。
Stream.generate()
Stream接口有两个用来创建无限Stream的静态方法。generate()方法接受一个参数函数,可以使用类似如下代码来创建一个你需要的Stream。
Stream stream = Stream.generate(() -> "test").limit(10);
String[] strArr = stream.toArray(String[]::new);
System.out.println(Arrays.toString(strArr));
运行结果
[test, test, test, test, test, test, test, test, test, test]
Stream.iterate()
Stream接口的另一用来创建无限Stream的静态方法就是iterate()方法。iterate()方法也是接受一个参数函数,可以用类似如下代码来创建一个你需要的Stream。
Stream bigIntStream = Stream.iterate(BigInteger.ZERO, n -> n.add(BigInteger.TEN)).limit(10);
BigInteger[] bigIntArr = bigIntStream.toArray(BigInteger[]::new);
System.out.println(Arrays.toString(bigIntArr));
运行结果
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
Collection.stream()
这个就是最常见的Stream了。因为Collection是Java中集合接口的父接口,Java中的集合都继承或实现了此接口。所以Java中的集合都可以使用此方法来创建一个Stream;
/**
* @see Set
* @see List
* @see Map
* @see SortedSet
* @see SortedMap
* @see HashSet
* @see TreeSet
* @see ArrayList
* @see LinkedList
* @see Vector
* @see Collections
* @see Arrays
* @see AbstractCollection
* @since 1.2
*/
public interface Collection extends Iterable {
default Stream stream() {
return StreamSupport.stream(spliterator(), false);
}
}
例子
List numbers = new ArrayList<>();
numbers.add(3);
numbers.add(4);
numbers.add(8);
numbers.add(16);
numbers.stream().forEach(number->{
System.out.println(number);
});
StreamSupport.stream()
通过查看Collection.stream()的方法,我们可以看出来,Colleciton.stream()其实是调用了StreamSupport.stream()来实现的。所以我们也可以使用StreamSupport.stream()来创建一个Stream。当我们面对的是一个迭代器的时候,使用StreamSupport.stream()就可以创建一个Stream。第一个参数是传入一个迭代器,第二个参数是true代表使用并行来进行处理。false代表串行来处理Stream。
List numbers = new ArrayList<>();
numbers.add(3);
numbers.add(4);
numbers.add(8);
numbers.add(16);
numbers.add(19);
numbers.add(27);
numbers.add(23);
Spliterator integers = numbers.spliterator();
StreamSupport.stream(integers,false).forEach(number->{
System.out.println(number);
});
流的转换
filter方法
从名字上就能看出来,这是一个Stream的过滤转换,此方法会生成一个新的流,其中包含符合某个特定条件的所有元素。
List integerList = Lists.newArrayList();
integerList.add(15);
integerList.add(32);
integerList.add(5);
integerList.add(232);
integerList.add(56);
List after = integerList.stream()
.filter(i->i>50)
.collect(Collectors.toList());
System.out.println(after);
运行结果:
[232, 56]
map方法
map方法指对一个流中的值进行某种形式的转换。需要传递给它一个转换的函数作为参数。
List integerList = Lists.newArrayList();
integerList.add(15);
integerList.add(32);
integerList.add(5);
integerList.add(232);
integerList.add(56);
//将Integer类型转换成String类型
List afterString = integerList.stream()
.map(i->String.valueOf(i)).collect(Collectors.toList());
System.out.println(afterString);
flatMap方法
上面用map方法进行流转换的时候,是对每个元素应用一个函数,并将返回的值收集到一个新的流中。但是如果有一个函数,它返回的不是一个值,而是一个包含多个值的流。但是你需要的是一个包含多个流中的元素的集合。
例如
List oneList = Lists.newArrayList(),
twoList = Lists.newArrayList();
oneList.add(34);
oneList.add(23);
oneList.add(87);
twoList.add(29);
twoList.add(48);
twoList.add(92);
Map<String,List> testMap = Maps.newHashMap();
testMap.put("1",oneList);
testMap.put("2",twoList);
//返回的是一个流的集合,但是我需要的是List这样一个集合
List<Stream> testList = testMap.values().stream()
.map(number->number.stream()).collect(Collectors.toList());
这个时候就应该使用flatMap将多个流进行合并,然后再收集到一个集合中。
List<Integer> testList = testMap.values().stream()
.flatMap(number->number.stream()).collect(Collectors.toList());
limit方法和skip方法
limit(n)方法会返回一个包含n个元素的新的流(若总长小于n则返回原始流)。
List myList = Lists.newArrayList();
myList.add(1);
myList.add(2);
myList.add(3);
myList.add(4);
myList.add(5);
myList.add(6);
List afterLimit = myList.stream().limit(4).collect(Collectors.toList());
System.out.println("afterLimit:"+afterLimit);
skip(n)方法正好相反,它会丢弃掉前面的n个元素。
List afterSkip = myList.stream().skip(4).collect(Collectors.toList());
System.out.println("afterSkip:"+afterSkip);
运行结果:
afterLimit:[1, 2, 3, 4]
afterSkip:[5, 6]
用limit和skip方法一起使用就可以实现日常的分页功能:
List pageList = myList.stream()
.skip(pageNumber*pageSize)
.limit(pageSize).collect(Collectors.toList());
distinct方法和sorted方法
上面介绍的流的转换方法都是无状态的。即从一个已经转换的流中取某个元素时,结果并不依赖于之前的元素。除此之外还有两个方法在转换流时是需要依赖于之前流中的元素的。一个是distinct方法一个是sorted方法。
distinct方法会根据原始流中的元素返回一个具有相同顺序、去除了重复元素的流,这个操作显然是需要记住之前读取的元素。
List myTestList = Lists.newArrayList();
myTestList.add(10);
myTestList.add(39);
myTestList.add(10);
myTestList.add(78);
myTestList.add(10);
List distinctList = myTestList.stream()
.distinct().collect(Collectors.toList());
System.out.println("distinctList:"+distinctList);
运行结果:
distinctList:[10, 39, 78]
sorted方法是需要遍历整个流的,并在产生任何元素之前对它进行排序。因为有可能排序后集合的第一个元素会在未排序集合的最后一位。
List myTestList = Lists.newArrayList();
myTestList.add(39);
myTestList.add(78);
myTestList.add(10);
myTestList.add(22);
myTestList.add(56);
List sortList = myTestList.stream()
.sorted(Integer::compareTo).collect(Collectors.toList());
System.out.println("sortList:"+sortList);
运行结果:
sortList:[10, 22, 39, 56, 78]
聚合操作
前面已经介绍了流的创建和转换,下面介绍流的聚合,聚合是指将流汇聚为一个值,以便在程序中使用。聚合方法都是终止操作。
max方法和min方法
在前面的代码例子中使用的count方法和sum方法都属于流从聚合方法。还有两个聚合方法是max方法和min方法,分别返回流中最大值和最小值。
List hearList = Lists.newArrayList();
hearList.add(15);
hearList.add(32);
hearList.add(5);
hearList.add(232);
hearList.add(56);
hearList.add(29);
hearList.add(94);
Integer maxItem = hearList.stream().max(Integer::compareTo).get();
Integer minItem = hearList.stream().min(Integer::compareTo).get();
System.out.println("max:"+maxItem+",min:"+minItem);
运行结果:
max:232,min:5
findFirst方法
findFirst方法返回非空集合中的第一个值,它通常与filter方法结合起来使用。
List hearList = Lists.newArrayList();
hearList.add(15);
hearList.add(32);
hearList.add(5);
hearList.add(232);
hearList.add(56);
hearList.add(29);
hearList.add(104);
Integer first = hearList.stream().filter(i->i>100).findFirst().get();
findAny方法
findAny方法可以在集合中只要找到任何一个所匹配的元素,就返回,此方法在对流并行执行时十分有效(任何片段中发现第一个匹配元素都会结束计算,串行流中和findFirst返回一样)。
Integer anyItem = hearList.parallelStream().filter(i->i>100).findAny().get();
anyMatch方法
anyMatch方法可以判定集合中是否还有匹配的元素。返回结果是一个boolean类型值。
boolean isHas = hearList.parallelStream().anyMatch(i->i>100);
allMatch方法和noneMatch方法
allMatch方法和noneMatch方法,分别在所有元素匹配和没有元素匹配时返回true。
boolean allHas = hearList.parallelStream().allMatch(i->i>100);
boolean noHas = hearList.parallelStream().noneMatch(i->i>100);
虽然这些方法总是会检查整个流,但是仍然可以通过并行执行来提高速度。
reduce方法
reduce方法是将流中的元素进行进一步计算的方法。
List hearList = Lists.newArrayList();
hearList.add(15);
hearList.add(32);
hearList.add(5);
hearList.add(232);
hearList.add(56);
hearList.add(29);
hearList.add(104);
//求和
Integer sum = hearList.stream().reduce((x,y)->x+y).get();
System.out.println("sum:"+sum);
//简化一下,求和
sum = hearList.stream().reduce(Integer::sum).get();
System.out.println("sum:"+sum);
//含有初始标识的,求和
sum = hearList.stream().reduce(0,(x,y)->x+y);
System.out.println("sum:"+sum);
//对元素的长度进行求和( (total,y)->total+y.toString().length(),类似于一个累加器,会被重复调用)
sum = hearList.stream().reduce(0,(total,y)->total+y.toString().length(),(total1,total2)->total1+total2);
System.out.println("sum:"+sum);
//简化一下,对元素长度进行求和。
sum = hearList.stream().map(Objects::toString).mapToInt(String::length).sum();
System.out.println("sum:"+sum);
运行结果
sum:473
sum:473
sum:473
sum:15
sum:15
收集结果
当处理完流之后,通常是想查看一下结果,而不是将他们聚合为一个值。Collectorts类为我们提供了常用的收集类的各个工厂方法。
收集到集合
例如前面的例子用的要将一个流收集到一个List中,只需要这样写就可以。
List thereList = hereList.stream().collect(Collectors.toList());
收集到Set中可以这样用
Set thereSet = hereList.stream().collect(Collectors.toSet());
收集到Set时,控制Set的类型,可以这样。
TreeSet treeSet = hereList.stream()
.collect(Collectors.toCollection(TreeSet::new));
拼接
将字流中的字符串连接并收集起来。
String resultString = stringList.stream().collect(Collectors.joining());
在将流中的字符串连接并收集起来时,想在元素中介添加分隔符,传递个joining方法即可。
String resultString = stringList.stream().collect(Collectors.joining(","));
当流中的元素不是字符串时,需要先将流转成字符串流再进行拼接。
String hereResultString = hereList.stream()
.map(String::valueOf).collect(Collectors.joining(","));
收集聚合
分别收集流的总和、平均值、最大值或者最小值。
List hereList = Lists.newArrayList();
hereList.add(15);
hereList.add(32);
hereList.add(5);
hereList.add(232);
hereList.add(56);
hereList.add(29);
hereList.add(104);
//总和、平均值,最大值,最小值
int sum = hereList.stream().collect(Collectors.summingInt(Integer::intValue));
Double ave = hereList.stream().collect(Collectors.averagingInt(Integer::intValue));
Integer max = hereList.stream().collect(Collectors.maxBy(Integer::compare)).get();
Integer min = hereList.stream().collect(Collectors.minBy(Integer::compare)).get();
System.out.println("sum:"+sum+",ave:"+ave+",max:"+max+",min:"+min);
运行结果:
sum:473,ave:67.57142857142857,max:232,min:5
一次性收集流中的结果,聚合为一个总和,平均值,最大值或最小值的对象。
IntSummaryStatistics summaryStatistics = hereList.stream()
.collect(Collectors.summarizingInt(Integer::intValue));
System.out.println(summaryStatistics);
运行结果:
IntSummaryStatistics{count=7, sum=473, min=5, average=67.571429, max=232}
将结果集收集到Map
当我们希望将集合中的元素收集到Map中时,可以使用Collectors.toMap方法。这个方法有两个参数,用来生成Map的key和value。
例如将一个Room对象的high作为键width作为值
Map<Integer,Integer> hwMap = roomList.stream()
.collect(Collectors.toMap(Room::getHigh, Room::getWidth));
但是通常还是以具体元素作为值的情况多,可以使用Function.identity()来获取实际元素。
Map<Integer,Room> roomMap = roomList.stream()
.collect(Collectors.toMap(Room::getHigh, Function.identity()));
如果多个元素拥有相同的键,在收集结果时会抛出java.lang.IllegalStateException异常。可以使用第三个参数来解决,第三个参数用来确定当出现键冲突时,该如何处理结果,如果当出现键冲突时只保留一个并且是保留已经存在的值时,就是如下方式。
Map<Integer,Room> rMap = roomList.stream()
.collect(Collectors.toMap(Room::getHigh, Function.identity(),(nowValue,newValue)->nowValue));
如果想指定生成的Map类型,则还需要第三个参数。
TreeMap<Integer,Room> roomTreeMap = roomList.stream()
.collect(Collectors.toMap(Room::getHigh,
Function.identity(),(nowValue,newValue)->newValue,TreeMap::new));
注意:每个toMap方法,都会有一个对应的toConCurrentMap方法,用来生成一个并发Map。
分组分片
在一个集合中,对具有相同特性的值进行分组是一个很常见的功能,在Stream的API中也提供了相应的方法。
分组
还是上面的例子,将一个Room对象集合按照高度分组。
List roomList = Lists.newArrayList(
new Room(11,23,56),
new Room(11,84,48),
new Room(22,46,112),
new Room(22,75,62),
new Room(22,56,75),
new Room(33,92,224));
Map<Integer,List> groupMap = roomList.stream().collect(Collectors.groupingBy(Room::getHigh));
System.out.println("groupMap:"+groupMap);
运行结果:
groupMap:{33=[Room(high=33, width=92, length=224)],
22=[Room(high=22, width=46, length=112), Room(high=22, width=75, length=62), Room(high=22, width=56, length=75)],
11=[Room(high=11, width=23, length=56), Room(high=11, width=84, length=48)]}
分片
当分类函数是一个返回布尔值的函数时,流元素会被分为两组列表:一组是返回true的元素集合,另一组是返回false的元素集合。这种情况适用partitoningBy方法会比groupingBy更有效率。
例如我们将房间集合分为两组,一组是高度为22的房间,另一组是其他房间。
Map<Boolean,List> partitionMap = roomList.stream()
.collect(Collectors.partitioningBy(room->room.getHigh()==22));
运行结果:
partitionMap:{false=[Room(high=11, width=23, length=56), Room(high=11, width=84, length=48), Room(high=33, width=92, length=224)],
true=[Room(high=22, width=46, length=112), Room(high=22, width=75, length=62), Room(high=22, width=56, length=75)]}
扩展功能
下面要介绍的这些方法功能,无论是groupingBy方法还是partitioningBy方法都是支持的。
counting方法会返回收集元素的总个数。
Map<Integer,Long> countMap = roomList.stream()
.collect(Collectors.groupingBy(Room::getHigh,Collectors.counting()));
summing(Int|Long|Double)方法接受一个取值函数作为参数,来计算总和。
Map<Integer,Integer> sumMap = roomList.stream().
collect(Collectors.groupingBy(Room::getHigh,Collectors.summingInt(Room::getWidth)));
maxBy方法和minBy方法接受比较器作为参数来计算最大值和最小值。
取出分组中宽度最大和最小的房间。
Map<Integer, Optional> maxMap = roomList.stream().
collect(Collectors.groupingBy(Room::getHigh,
Collectors.maxBy(Comparator.comparing(Room::getWidth))
));
Map<Integer, Optional> minMap = roomList.stream().
collect(Collectors.groupingBy(Room::getHigh,
Collectors.maxBy(Comparator.comparing(Room::getWidth))
));
System.out.println("maxMap:"+ JSON.toJSONString(maxMap));
System.out.println("minMap:"+JSON.toJSONString(minMap));
运行结果:
maxMap:{33:{"high":33,"length":224,"width":92},22:{"high":22,"length":62,"width":75},11:{"high":11,"length":48,"width":84}}
minMap:{33:{"high":33,"length":224,"width":92},22:{"high":22,"length":62,"width":75},11:{"high":11,"length":48,"width":84}}
mapping方法会将结果应用到另一个收集器上。
取出分组中宽度最大的房间的宽度。
Map<Integer, Optional> collect = roomList.stream().collect(Collectors.groupingBy(Room::getHigh,
Collectors.mapping(Room::getWidth,
Collectors.maxBy(Comparator.comparing(Integer::valueOf)))));
System.out.println("collect:"+JSON.toJSONString(collect));
运行结果:
collect:{33:92,22:75,11:84}
无论groupingBy或是mapping函数,如果返回类型是int、long、double都可以将元素收集到一个summarystatistics对象中,然后从每组的summarystatistics对象中取出函数值的总和、平均值、总数、最大值和最小值。
Map<Integer,IntSummaryStatistics> summaryStatisticsMap = roomList.stream()
.collect(Collectors.groupingBy(Room::getHigh,
Collectors.summarizingInt(Room::getWidth)));
System.out.println("summaryStatisticsMap:"+summaryStatisticsMap);
运行结果:
summaryStatisticsMap:{33=IntSummaryStatistics{count=1, sum=92, min=92, average=92.000000, max=92},
22=IntSummaryStatistics{count=3, sum=177, min=46, average=59.000000, max=75},
11=IntSummaryStatistics{count=2, sum=107, min=23, average=53.500000, max=84}}
多级分组
上面的例子我们都是按一个条件进行的一级分组,其实groupingBy是支持多级分组的。
例如第一级我们将房间按照高度分组,第二级按照宽度分组。
Map<Integer,Map<Integer,List>> multistageMap = roomList.stream().collect(
Collectors.groupingBy(Room::getHigh,Collectors.groupingBy(Room::getWidth)));
System.out.println("multistageMap:"+JSON.toJSONString(multistageMap));
运行结果:
{
"11": {
"23": [
{"high": 11,"length": 56,"width": 23}
],
"84": [
{"high": 11,"length": 48,"width": 84}
]
},
"22": {
"46": [
{"high": 22,"length": 112,"width": 46}
],
"56": [
{"high": 22,"length": 75,"width": 56}
],
"75": [
{"high": 22,"length": 62,"width": 75}
]
},
"33": {
"92": [
{"high": 33,"length": 224,"width": 92}
]
}
}
并行流
Stream的建立,使得并行计算变得容易,但是并行流在使用的时候也是需要注意的。
首先,必须是一个并行流,只要在终止方法执行时,流处于并行模式,那么所有的流操作就都会并行执行。
Stream.of(roomList).parallel();
parallel方法可以将任意的串行流转换为一个并行流。
其次要确保传递给并行流操作的函数是线程安全的。
int[] words = new int[23];
Stream.of(roomList).parallel().forEach(s->{
if(s.size()<10){
words[s.size()]++;
}
});
上面这个例子中的代码就是错误的,传递给并行流的操作并不是线程安全的。可以改为AtomicInteger的对象数组来作为计数器。
我们使在处理集合数据量较大的时候才能体现出并行流的优势,并且目的是为了在保证线程安全的情况下,提升效率,利用多核CPU的资源。
小扩展
使用Stream的API时,在遍历或处理流的过程中当引用外部变量的时候会默认的将变量当成fianl变量来处理。所以有些同学就会觉得在遍历的过程中取不出来集合的索引。其实可以换一种思想可以只遍历集合索引,然后在遍历中取值。
IntStream.range(0,roomList.size()).forEach(i->{
System.out.println(roomList.get(i));
});
Java8的Stream API使用的更多相关文章
- 【Java8新特性】关于Java8的Stream API,看这一篇就够了!!
写在前面 Java8中有两大最为重要的改变.第一个是 Lambda 表达式:另外一个则是 Stream API(java.util.stream.*) ,那什么是Stream API呢?Java8中的 ...
- Java8的Stream API确实很牛,但性能究竟如何?
Stream Performance 已经对 Stream API 的用法鼓吹够多了,用起简洁直观,但性能到底怎么样呢?会不会有很高的性能损失?本节我们对 Stream API 的性能一探究竟. 为保 ...
- 如何用Java8 Stream API找到心仪的女朋友
传统的的Java 集合操作是有些啰嗦的,当我们需要对结合元素进行过滤,排序等操作的时候,通常需要写好几行代码以及定义临时变量. 而Java8 Stream API 可以极大简化这一操作,代码行数少,且 ...
- Spring WebFlux 学习笔记 - (一) 前传:学习Java 8 Stream Api (1) - 创建 Stream
影子 在学习Spring WebFlux之前,我们先来了解JDK的Stream,虽然他们之间没有直接的关系,有趣的是 Spring Web Flux 基于 Reactive Stream,他们中都带了 ...
- 十分钟学会Java8的lambda表达式和Stream API
01:前言一直在用JDK8 ,却从未用过Stream,为了对数组或集合进行一些排序.过滤或数据处理,只会写for循环或者foreach,这就是我曾经的一个写照. 刚开始写写是打基础,但写的多了,各种乏 ...
- Java8新特性之三:Stream API
Java8的两个重大改变,一个是Lambda表达式,另一个就是本节要讲的Stream API表达式.Stream 是Java8中处理集合的关键抽象概念,它可以对集合进行非常复杂的查找.过滤.筛选等操作 ...
- java8中Lambda表达式和Stream API
一.Lambda表达式 1.语法格式 Lambda是匿名函数,可以传递代码.使用“->”操作符,改操作符将lambda分成两部分: 左侧:指定了 Lambda 表达式需要的所有参数 右侧:指定了 ...
- 十分钟学会Java8:lambda表达式和Stream API
Java8 的新特性:Lambda表达式.强大的 Stream API.全新时间日期 API.ConcurrentHashMap.MetaSpace.总得来说,Java8 的新特性使 Java 的运行 ...
- Java8中的 lambda 和Stream API
前言 由于项目中用到了比较多有关于 Java8 中新的东西,一开始自己只是会写,但是写起来不太顺,然后就在网上找到了一个很好的关于Java8新特性的视频,所以就进行了学习了一下,以下是自己对 la ...
随机推荐
- 【Gamma阶段】第七次Scrum Meeting
冰多多团队-Gamma阶段第七次Scrum会议 工作情况 团队成员 已完成任务 待完成任务 卓培锦 编辑器风格切换(添加夜间模式) UI界面手势切换 牛雅哲 语音输入shell应用:基于pytorch ...
- 【WebTerminal】gotty工具
./gotty -w -p 8888 --permit-arguments /bin/sh ./gotty -w -p 8888 --permit-arguments docker exec -ti ...
- 【操作系统之三】Linux下进程间通信-IPC(Inter-Process Communication)
管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信:信号(Sign ...
- Linux查看端口使用情况
1.netstat -tunlp,查看已使用的端口 2.netstat -tunlp | grep 8080,查询指定端口使用情况 3.netstat命令无法使用需要安装net-tools yum i ...
- 设计高性能大并发WEB系统架构注意点
设计高性能大并发WEB系统架构注意点 第01:大型架构的演进之路第02(上):分布式缓存第02(下):分布式缓存第03:分布式消息队列第04:分布式数据存储第05:分布式服务框架第06:高性能系统架构 ...
- 依赖注入之unity(winform方式)
依赖注入之unity(winform方式) 要讲unity就必须先了解DI和IOC及DIP,如下链接提供DI和IOC的基础:https://www.cnblogs.com/zlp520/p/12015 ...
- hive 批量添加,删除分区
一.批量添加分区: use bigdata; alter table siebel_member add if not exists partition(dt='20180401') locati ...
- Python3版本号比较代码实现
一.版本号比较的困难 不能直接以字符串形式进行比较:对于1.3和1.4直接以字符串进行比较是可以正确得出1.4比1.3大:但如果是1.3和1.14还直接进字符串比较那就是1.3比1.14大那就不对了. ...
- Java利用IText导出PDF(更新)
我很久以前写的还是上大学的时候写的:https://www.cnblogs.com/LUA123/p/5108007.html ,今天心血来潮决定更新一波. 看了下官网(https://itextpd ...
- centos下 yum快速安装maven
wget http://repos.fedorapeople.org/repos/dchen/apache-maven/epel-apache-maven.repo -O /etc/yum.repos ...