avatar

目录
Java8新特性

参考:itheima

我的代码:https://gitee.com/machine4869/example-code/tree/master/note_java8new

概述

课程介绍

Code
1
2
3
4
5
Java8(2014年3月发布),更新力度很大,代表性为Lambda(函数式编程)
Java9(2017年9月),Jigsaw(模块化)
- Lambda表达式、函数式接口(Lamda的基础)
- 方法引用、常用函数式接口
- Stream流式处理API、模块化系统(Java9)

Java版本特性更新历史

版本号 年份/代号 新特性(部分举例)
1.0 1996
1.1 1997 JDBC
1.2 1998, Playground 集合、字符串常量池
1.3 2000, Kestrel 性能优化
1.4 2004, Merlin xml、正则、JDBC3.0、断言(Assert)、NIO
5.0 2004, Tiger 泛型、注解、可变参数、枚举
6.0 2006, Mustang 脚本、JDBC4.0
7.0 2011, Dolphin NIO.2、try-with-resources
8.0 2014.03 接口更新、Lamda表达式、方法引用、Stream API、函数式接口、Hashorn、JavaFX、DateTime
9.0 2017.09 Jigsaw(模块化)、JShell、接口小更新

函数式编程思想(Lambda)

Lamda表达式

面向对象的Runnable接口写法

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//在某些情况下,面向对象语法复杂
public class Demo01Runnable {

public static void main(String[] args) {
// 匿名内部类
Runnable task = new Runnable() {
public void run() {
System.out.println("多线程任务执行啦~");
}
};

new Thread(task).start();
}
}

编程思想转换,使用Lambda

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* 1、面向对象强调“一切皆对象”,要做事需要先找对象
* 2、函数式编程思想强调“做什么”,而不是怎么做
*/
public class Demo02Lambda {
public static void main(String[] args) {
new Thread(() -> System.out.println("多线程任务执行啦~")).start();
}
}
/*
* () -> System.out.println("多线程任务执行啦~")
* 1. ()代表不需要任何参数条件,即可执行
* 2. 箭头指向后面要做的事情
* 3. 箭头后面就是方法体大括号,代表具体要做的内容
*
* Lambda表达式的标准格式
* (参数类型 参数名称) -> {一些代码}
* 1. 参数有多个,逗号分隔;参数没有,留空
*/

带参数和返回值

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Demo05SortLamda {
public static void main(String[] args) {
Person[] array = {
new Person("Tony", 20),
new Person("Jay", 18),
new Person("Mary", 19)
};

System.out.println("排序前:" + Arrays.toString(array));

Arrays.sort(array, (Person p1, Person p2) -> {
return p1.getAge() - p2.getAge();
});

System.out.println("排序后:" + Arrays.toString(array));
}
}

Lambda表达式的省略格式

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* Lambda表达式省略规则:
* 1. 参数类型可以省略(只能同时省略所有参数类型)
* 2. 如果有且仅有一个参数,小括号可以省略
* 3. 如果大括号内语句有且仅有一个,那么无论是否有返回值,return、大括号、分号,都可以省略
*/
public class Demo06LambdaFormat {
public static void main(String[] args) {
method( (a,b) -> a+b);

}

public static void method(Calculator calculator){
int result = calculator.sum(111, 222);
System.out.println("结果:"+result);
}
}

Lambda的使用前提

Code
1
2
1. 一个接口,有且仅有一个抽象方法
2. 必须具有上下文环境,才能推导

函数式接口

定义

java
1
2
3
4
5
6
7
8
9
10
11
12
/**
* 函数式接口:接口中有且仅有一个抽象方法
* @FunctionalInterface注解:用来检测一个接口是不是函数式接口
* 编译时,写上这个注解:
* 1. 如果是函数式接口,则编译通过
* 2. 如果不是,则编译失败
* @FunctionalInterface是可选的,和@Overise类似,他是编译时用于检错的注解
*/
@FunctionalInterface
public interface MyInterface {
void method();
}

使用

java
1
2
3
4
5
6
7
8
9
public class Demo01FunctionalInterfaceUsage {
public static void main(String[] args) {
//函数式接口,使用Lambda表达式
MyInterface myInterface = () -> System.out.println("Lambda表达式");

myInterface.method();

}
}

Lambda与匿名内部类的区别

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Lambda表达式并不是匿名内部类的“语法糖”
语法糖:代码更简洁,但其实原理不变
例如:
1)方法中的可变参数(底层仍然是数组)
2)增强for循环(底层仍然是迭代器)
3)自动装箱\拆箱(底层仍然是new对象)

但是!Lambda表达式和匿名内部类存在根本区别

------------------------------------------------

1. 所需类型不同
2. 使用限制不同
Lamda表达式必须要求函数式接口,匿名内部类可以是普通接口、抽象类、普通类

3. 实现原理不同
匿名内部类:其实就是一个类,编译后产生单独的.class文件(XXX$1.class、XXX$2.class)
Lamda表达式:编译后没有单独.class文件,对应的字节码会在运行的时候才会动态生成

接口的组成更新

Code
1
2
3
4
5
6
接口组成部分:
1. 常量(public static final)
2. 抽象方法
3. 默认方法(Java 8)
4. 静态方法(Java 8)
5. 私有方法(Java 9)

接口默认方法

定义

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* 接口升级:本来是2个抽象方法,升级变成3个
* 问题出现:那么已实现且投入使用的类会报错,因为必须实现全部接口
* 解决:
* 1. 设计模式中的开闭原则:对扩展开放,对修改关闭
* 2. 从java 8开始,接口中允许定义default默认方法
* 常量修饰符:public static final(都可省略)
* 抽象方法修饰符:public abstract(都可省略)
* 默认方法修饰符:public default(public可以省略,default不能省)
*
* 默认方法可以有方法体实现
* 默认方法可以不重写,也可以进行覆盖重写
*/
public interface MyInterface {
void method1();
void method2();

//升级后的新接口
//void methodNew();
default void methodNew(){
System.out.println("接口的默认方法执行");
}

}

MyInterfaceImplA

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class MyInterfaceImplA implements MyInterface {
@Override
public void method1() {

}

@Override
public void method2() {

}

@Override
public void methodNew() {
System.out.println("可以重写接口的默认方法");
}
}

使用:

java
1
2
3
4
5
6
7
8
public class Demo01Usage {
public static void main(String[] args) {
MyInterface objA = new MyInterfaceImplA();
objA.method1();
//会继承默认方法
objA.methodNew();
}
}

接口静态方法

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
Java 8开始,接口允许定义静态方法:
修饰符:public static(public可以省略)
ps: public abstract都可以省略

应用场合:
静态方法起到接口屏蔽的作用,当实现类变化(cat变dog)时,只需要改接口,
不需要改动具体的使用类 Animal animal = Animal.getAnimal();
"工厂模式":让main方法和Cat,Dog解耦

*/
public interface Animal {

void eat();

static Animal getAnimal(){
return new Cat();
}
}
java
1
2
3
4
5
6
7
public class Cat implements Animal {

@Override
public void eat() {
System.out.println("猫吃XX");
}
}
java
1
2
3
4
5
6
7
8
9
10
11
/*
左边是接口类型,我只关心Animal,不关心是猫是狗
*/
public class Demo01Animal {
public static void main(String[] args) {
// Animal animal = new Cat();
// animal.eat();
Animal animal = Animal.getAnimal();
animal.eat();
}
}

接口私有方法

是java9引入的,见java9

方法引用

通过方法引用改进代码

java
1
2
3
4
5
6
7
8
9
10
11
12
/**
* --通过方法引用改进代码
* Java 8引入了全新运算符,方法引用符("::")
* 方法引用的本质和Lambda完全一样,目的就是为了简化Lambda的写法
*
* 可推导即可省略:lambda的参数拿到之后,原封不动的给了方法调用,那该lambda就是多余的,于是lambda可以省去
*
* Lambda: s -> System.out.println(s)
* 方法引用写法: System.out::println
* 2种方法等效
*
*/

常见的方法引用

java
1
2
3
4
5
6
7
8
9
10
/*
* --常见的方法引用写法:
* 1、通过对象名引用成员方法 对象名称::方法名称
* 2、通过类名称引用静态方法
* 3、通过super引用父类方法 super::父类方法名称
* 4、通过this引用本类方法 this::本类方法名称
* 5、构造器引用 类名称::new
* 6、数组的构造器引用 元素类型::new
*
*/

demo

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public class Demo01Printer extends PrinterSuper{
public static void main(String[] args) {

// lambda表达式的写法
method((s) -> System.out.println(s) , "hello");

/*
* 使用方法引用符
* System.out是一个对象, println是方法,不用println(String str)参数,因为参数可推导(void print(String str);)
*/
method(System.out::println,"hello");

// 1、通过对象名引用成员方法
StrPrinter sp = new StrPrinter();
method(sp::printStrUper,"hello world");

// 2、通过类名称引用静态方法
//method( (str -> StrPrinter.staticMethod(str)),"hello"); //lambda写法
method(StrPrinter::staticMethod,"hello");

//3、通过super引用父类方法
Demo01Printer dp = new Demo01Printer();
dp.sayHello();

//4、通过this引用本类方法
dp.beHappy();

//5、构造器引用
//method( (str -> new Person(str)),"Tony");
method(Person::new,"Tony");

}

public void beHappy(){
//method( (str -> this.buy(str)),"hello");
method( this::buy,"hello");
}

public void sayHello(){
//method( (str -> super.fatherMathod(str)),"hello"); //lambda
method(super::fatherMathod ,"hello");
}

public void buy(String str){
System.out.println("本类方法-"+str);
}

public static void method(Printer printer,String str){
printer.print(str);
}
}
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.mxx.methodref;

/**
* 6、数组的构造器引用
* 数组也是一个对象,他有构造器
*/
public class Demo02MethodRefArray {

public static void main(String[] args) {
//method((length -> new int[length]));
method(int[]::new);

}

private static void method(ArrayBuilder arrayBuilder){
int[] array = arrayBuilder.build(10);
System.out.println("数组长度为:"+array.length);
}
}

Lambda的延迟执行

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* Lambda的延迟执行
* 使用场景:日志性能浪费
*/
public class Demo03Logger {

public static void main(String[] args) {
String msgA = "hello";
String msgB = "world";
String msgC = "java";

logger(1,() -> {
//如果level==2,那么此lambda表达式不会执行,省去了msgA+msgB+msgC的计算浪费
//只有执行抽象方法msgBuilder.buildMsg()时,此处才会触发执行
System.out.println("lambda执行啦");
return msgA+msgB+msgC;
});
}

private static void logger(int level, MsgBuilder msgBuilder){
if(level == 1){
System.out.println(msgBuilder.buildMsg());
}
}
}

使用Lambda作为方法参数/返回值

使用Lambda作为方法参数=使用函数式接口作为参数

java
1
2
3
4
5
6
// method((s) -> System.out.println(s) , "hello");
method(System.out::println,"hello");

public static void method(Printer printer,String str){
printer.print(str);
}

使用Lambda作为方法返回值=使用函数式接口作为方法返回值

java
1
2
3
4
5
6
7
8
9
10
11
12
13
public class Demo04LambdaReturn {
public static void main(String[] args) {
String[] array = {"11","111","1"};

//Arrays.sort(array,(s1, s2) -> s1.length()-s2.length());

//lambda表达式是一个接口实例
Comparator<String> comp = (s1, s2) -> s1.length() - s2.length();
Arrays.sort(array,comp);

System.out.println(Arrays.toString(array));
}
}

Lambda使用局部变量的要求

Code
1
2
如果lambda需要使用外部局部变量,局部变量必须是有效final的。(和匿名内部类要求一样)
可以不写final,但该变量不能发生改变
java
1
2
3
4
5
6
7
8
String msgA = "hello";
String msgB = "world";
String msgC = "java";

//不能改变
//msgC=null;

logger(1,() -> msgA+msgB+msgC);

JDK常用函数式接口

Supplier接口

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import java.util.function.Supplier;
/*
JDK内置了很多函数式接口,在java.util.function包
java.util.function.Supplier<T> : 向外提供一个数据
*/
public class Demo01Supplier {
public static void main(String[] args) {
method(() -> "hello");
}

private static void method(Supplier<String> supplier){
String str = supplier.get();
System.out.println("内容:"+str);
}
}

Supplier接口源码

java
1
2
3
4
5
@FunctionalInterface
public interface Supplier<T> {

T get();
}

Consumer接口

接口源码

java
1
2
3
4
5
6
7
8
9
10
11
12
//默认方法不会影响抽象方法的唯一性
@FunctionalInterface
public interface Consumer<T> {

void accept(T t);

//前后拼接2个lambda
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}

抽象方法使用

java
1
2
3
4
5
6
7
8
9
10
11
12
import java.util.function.Consumer;
public class Demo02Consumer {
public static void main(String[] args) {
//method((s) -> System.out.println(s));
method(System.out::println);
}

private static void method(Consumer<String> consumer){
//消费一个对象
consumer.accept("hello");
}
}

默认方法使用

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import java.util.function.Consumer;
//函数模型拼接
public class Demo03ConsumerAndThen {
public static void main(String[] args) {

//先打印大写,再打印小写,消费的是同一个数据
method((s) -> System.out.println(s.toUpperCase()),
(s) -> System.out.println(s.toLowerCase()));
}

private static void method(Consumer<String> one, Consumer<String> two){
//先做one,再做two操作 : 函数模型拼接
//one先消费"hello",two再消费"hello",消费的是同一个"hello"
one.andThen(two).accept("Hello");
}
}

Predicate接口

接口源码

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@FunctionalInterface
public interface Predicate<T> {

boolean test(T t);

default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}

default Predicate<T> negate() {
return (t) -> !test(t);
}

default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}

static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}

抽象方法使用

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import java.util.function.Predicate;

/*
java.util.function.Predicate<T>
作用:对指定类型对象进行操作,得到一个boolean值。条件判断
*/
public class Demo04Predicate {
public static void main(String[] args) {
//判断字符串长度
method(s -> s.length() > 10);
}

private static void method(Predicate<String> predicate){
boolean hello = predicate.test("hello");
System.out.println("判断结果:"+hello);
}
}

默认方法使用

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/*
Predicate接口有3个常用默认方法(函数模型拼接)
and or negate(去反)

只有调用test,拼接好的模型才会执行:lambda延迟执行
*/
public class Demo05PredicateDefault {
public static void main(String[] args) {

// and
methodAnd(s -> s.contains("H"),
s -> s.contains("w"));
// or
methodOr(s -> s.contains("H"),
s -> s.contains("w"));
// negate
methodNegate(s -> s.contains("H"));
}

private static void methodAnd(Predicate<String> one, Predicate<String> two){
boolean ret = one.and(two).test("HelloWorld");
System.out.println("判断结果:"+ret);
}

private static void methodOr(Predicate<String> one, Predicate<String> two){
boolean ret = one.or(two).test("HelloWorld");
System.out.println("判断结果:"+ret);
}
private static void methodNegate(Predicate<String> predicate){
boolean ret = predicate.negate().test("HelloWorld");
System.out.println("判断结果:"+ret);
}
}

Function接口

接口源码

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@FunctionalInterface
public interface Function<T, R> {

R apply(T t);

default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}

default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}

static <T> Function<T, T> identity() {
return t -> t;
}
}

抽象方法使用

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import java.util.function.Function;
/*
java.util.function.Function<T,R>
T:代表参数类型
R:代表返回值类型
*/
public class Demo06Function {
public static void main(String[] args) {
//判断字符串长度
method(Integer::parseInt);
}

//数据类型转换
private static void method(Function<String,Integer> function){
int num = function.apply("20");
num+=30;
System.out.println("计算结果:"+num);
}
}

默认方法使用

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import java.util.function.Function;

/*
Function接口有2个默认方法:

andThen: 先做自己,再做其他
compose: 先做其他,再做自己

应用场景:
String --> split --> String --> Integer.parseInt --> int
"大王,20" "20" 20

*/
public class Demo07FunctionDefault {
public static void main(String[] args) {
//判断字符串长度
methodAndThen(s -> s.split(",")[1],
Integer::parseInt);

methodCompose(s -> s.split(",")[1],
Integer::parseInt);
}

//one做split , two做parseInt
private static void methodAndThen(Function<String, String> one, Function<String, Integer> two) {
int age = one.andThen(two).apply("大王,20");
age += 1;
System.out.println("年龄:" + age);
}

private static void methodCompose(Function<String, String> one, Function<String, Integer> two) {
int age = two.compose(one).apply("大王,20");
age += 1;
System.out.println("年龄:" + age);
}
}

Stream API

概况

Code
1
2
3
java 8中Lambda的衍生物
和IO流无关。IO流:数据流
Stream:跟集合相关,流式处理思想

体验Stream的更优写法

传统集合的多步循环遍历及其弊端

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class Demo01Collection {

//把姓张的三字答应出来
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("赵一");
list.add("钱一");
list.add("孙一");
list.add("李一");
list.add("张一");
list.add("张二二");
list.add("张三二");

//使用for做过滤语义不好:for循环是形式不是目的(是how不是what)
for (String name : list){
if (name != null && name.length() == 3 && name.startsWith("张")){
System.out.println(name);
}
}

//语义优化:可以拆3步,用三个for:1、过滤三字 2、过滤姓张 3、打印
//这样容易理解,但是代码很多


}
}

体验Stream的更优写法

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/*
流式思想概述:理解为流水线
将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。
+--------------------+ +------+ +------+ +---+ +-------+
| stream of elements +-----> |filter+-> |sorted+-> |map+-> |collect|
+--------------------+ +------+ +------+ +---+ +-------+
*/
public class Demo03Stream {

//把姓张的三字答应出来
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("赵一");
list.add("钱一");
list.add("孙一");
list.add("李一");
list.add("张一");
list.add("张二二");
list.add("张三二");

//1、过滤三字 2、过滤姓张 3、打印
list.stream()
.filter(s -> s.length() ==3)
.filter(s -> s.startsWith("张"))
//void forEach(Consumer<? super T> action);
.forEach(System.out::println);

}
}

获取流的多种方式

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import java.util.stream.IntStream;
import java.util.stream.Stream;
/*
java 8 Stream API核心接口:
java.util.stream.Stream<T>

获取流的常用3种方式
1. 通过Collection
2. 通过Map :不能直接获取,转成集合后再湖区
3. 通过数组 :Arrays.stream(array) 或 Stream.of(array)
*/
public class Demo03GetStream {
public static void main(String[] args) {
//1. 通过Collection
Collection<String> collection = new ArrayList<>();
//...
Stream<String> stream1 = collection.stream();

//2. 通过Map
Map<String,Integer> map = new HashMap<>();
//...
//获取所有key对应的流
Stream<String> streamKey = map.keySet().stream();
//获取所有value对应的流
Stream<Integer> streamValue = map.values().stream();
//获取所有key/value键值对对应的流
Stream<Map.Entry<String, Integer>> streamEntry = map.entrySet().stream();


//3. 通过数组
String[] array = {"王1","王2","王3"};
//推荐使用
Stream<String> streamArray = Arrays.stream(array);

Stream<String> streamArray2 = Stream.of(array);

//是基本类型数组,不是对象数组
int[] arrayInt = new int[3];
IntStream streamInt = Arrays.stream(arrayInt);



}
}

Stream的常用方法:

过滤filter

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/*
每次调用方法后都返回一个全新的Stream接口实例
filter方法:按条件过滤元素
参数:Predicate<T>
返回:Stream<T>
*/
public class Demo04StreamFilter {

public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("hello1");
list.add("world");
list.add("java");

//Stream<String> stream = list.stream();
// Stream<T> filter(Predicate<? super T> predicate);
//Stream<String> streamResult = stream.filter(s -> s.contains("o"));
//stream只能使用一次
// java.lang.IllegalStateException: stream has already been operated upon or closed
//Stream<String> streamResult2 = stream.filter(s -> s.contains("o"));

//使用链式写法
Stream<String> stream = list.stream().filter(s -> s.contains("o")).filter(s -> s.length() == 5);
}
}

统计个数count

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* count方法:Stream中统计元素个数,返回一个数字
*/
public class Demo05StreamCount {

public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("hello1");
list.add("world");
list.add("java");


long count = list.stream().filter(s -> s.length() <= 5).count();
System.out.println(count);
}
}

取用前几个limit

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* limit方法:Stream中只希望取前n个
* 参数:取用元素个数(前n个)
* 返回:Stream<>
*/
public class Demo06StreamLimit {

public static void main(String[] args) {
List<String> list = new ArrayList<>();
for (int i = 0; i < 100; i++) {
list.add("STR-"+i);
}

// long count = list.stream().limit(10).count();
// System.out.println(count);
list.stream().limit(10).forEach(System.out::println);
}
}

跳过前几个skip

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
skip方法:Stream中跳过前n个元素
参数:需要跳过的元素个数(前n个)
返回:Stream<>
*/
public class Demo05StreamSkip {

public static void main(String[] args) {
List<String> list = new ArrayList<>();
for (int i = 0; i < 100; i++) {
list.add("STR-"+i);
}

// long count = list.stream().skip(10).count();
// System.out.println(count);

list.stream().skip(10).forEach(System.out::println);
}
}

映射map

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.mxx.stream;

import java.util.ArrayList;
import java.util.List;

/**
* map方法:Stream中进行映射操作
* 参数:Function<T,R>
* 返回:Stream<>
*/
public class Demo08StreamMap {

//应用:数据类型转换
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("10");
list.add("20");
list.add("30");

//将"10"转成10,然后加1000,最终得到<Integer>
list.stream()
.map(Integer::parseInt)
.map(i -> i + 1000)
.forEach(System.out::println);

}
}

组合concat

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.mxx.stream;

import java.util.Arrays;
import java.util.stream.Stream;

/*
contact方法:将2个流合并为一个整体

contact方法是Stream中的静态方法,可以静态调用。
*/
public class Demo09StreamContact {

//应用:数据类型转换
public static void main(String[] args) {
String[] array1 = {"a","b","c"};

String[] array2 = {"d","e","f"};


Stream<String> stream1 = Arrays.stream(array1);
Stream<String> stream2 = Arrays.stream(array2);
Stream<String> stream = Stream.concat(stream1, stream2);
stream.forEach(System.out::println);


}
}

逐一消费forEach

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.mxx.stream;

import java.util.Arrays;
/*
forEach方法:对流中的元素进行逐一消费
参数:Consumer
*/
public class Demo10StreamForEach {

//应用:数据类型转换
public static void main(String[] args) {
String[] array = {"a","b","c"};

Arrays.stream(array).forEach(System.out::println);
Arrays.stream(array).forEach(Demo10StreamForEach::myPrint);

}

private static void myPrint(String str){

System.out.println("myPrint:"+str);
}
}

小节:链式方法与终结方法

java
1
2
3
4
5
6
7
8
9
/*
Stream中方法分两类:
1. 链式方法:返回Stream接口自身,支持链式调用,只是在进行函数模型拼接
2. 终结方法:返回值不再是Stream接口,不支持链式调用,会将所有操作全部触发执行

Stream不是集合,不存储任何元素,本身是一个函数模型
调用链式方法时,就是在拼接函数模型
Stream和Lambda一样,也有延迟执行的效果
*/

并发流

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
如何获取并发流:
1. 直接获取并发流: parallelStream
2. 先获取普通流,然后变成并发流 stream.parallel

并发流背后使用的是:Fork/Join框架
*/
public class Demo01ParallelStream {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
for (int i=0;i<100;++i){
list.add("STR-"+i);
}
//1. 直接获取并发流
//不会按序打印:线程抢着执行
// list.parallelStream().forEach(System.out::println);
//2. 先获取普通流,然后变成并发流
list.stream().parallel().forEach(System.out::println);
}
}

收集Stream结果

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Demo01StreamCollect {
public static void main(String[] args) {
//1、到数组

//泛型擦除,泛型是一个编译器工具,运行时是没有泛型的
Object[] array = Stream.of("AA", "BB", "CC").toArray();
//解决泛型数组的限制
String[] array1 = Stream.of("AA", "BB", "CC").toArray(String[]::new);

//2、到List
List<String> list = Stream.of("AA", "BB", "CC").collect(Collectors.toList());

//3、到Set
Set<String> set = Stream.of("AA", "BB", "CC").collect(Collectors.toSet());

//
}
}

??Java9

模块化思想

接口组成更新:私有方法

文章作者: Machine
文章链接: https://machine4869.gitee.io/2018/12/07/20181207190201298/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 哑舍
打赏
  • 微信
    微信
  • 支付宝
    支付宝

评论