Java8新特性
Lambda表达式
概念
lambda表达式是一段可以传递的代码,它的核心思想是将面向对象中的传递数据变成传递行为
允许把函数作为一个方法的参数(函数作为参数传递进方法中)
作用:使用 Lambda 表达式可以使代码变的更加简洁紧凑。
AndroidStudio 支持Lambda表达式
android {
compileSdkVersion 26
defaultConfig {
applicationId "video.uf.com.java8test"
minSdkVersion 15
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
jackOptions.enabled = true //支持Java8 Lambda表达式配置
}
//支持Java8 Lambda表达式 配置
compileOptions{
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
语法
(Type1 param1, Type2 param2, ..., TypeN paramN) -> {
statment1;
statment2;
//.............
return statmentM;
}
- 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
- 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
- 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
- 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。
Button btn = new Button(this);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.e("sss","ssss");
}
});
btn.setOnClickListener(v -> Log.e("sss","ssss"));
变量作用域
lambda 表达式只能引用 final 局部变量,这就是说不能在 lambda 内部修改定义在域外的局部变量,否则会编译错误。
int count = 1;
btn.setOnClickListener(v -> {
count = 10;//编译错误
Log.e("sss","ssss")});
匿名类和Lambda表达式的区别
- 使用匿名类与 Lambda 表达式的一大区别在于关键词的使用。对于匿名类,关键词 this 解读为匿名类,而对于 Lambda 表达式,关键词 this 解读为写就 Lambda 的外部类。
- Lambda 表达式与匿名类的另一不同在于两者的编译方法。Java 编译器编译 Lambda 表达式并将他们转化为类里面的私有函数,它使用 Java 7 中新加的 invokedynamic 指令动态绑定该方法
class TestBean {
private TestInterface testInterface;
public TestBean(TestInterface testInterface) {
this.testInterface = testInterface;
}
public void test() {
if (testInterface != null) {
testInterface.test();
}
}
}
interface TestInterface {
void test();
}
private void tt() {
TestBean testBean = new TestBean(new TestInterface() {
@Override
public void test() {
System.out.println("AnonymousClass--->" + this.getClass().getName());//video.uf.com.java8test.Test2$1
}
});
testBean.test();
TestBean testBean1 = new TestBean(() -> System.out.println("Java8--->" + this.getClass().getName()));
//Java8--->video.uf.com.java8test.Test2
testBean1.test();
}
函数式接口
概念
函数式接口(Functional Interface)就是一个具有一个方法的普通接口。 @FunctionalInterface注解
特点
可以被隐式转换为lambda表达式
常用的函数式接口
java.lang.Runnable
例如:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Create Thread before Java8");
}
}).start();
new Thread(()->System.out.println("Java8-------->")).start();
java.util.Comparator
例如:
List list = new ArrayList<>();
list.add(3);
list.add(5);
list.add(4);
System.out.println("origin Data");
for(Integer item : list){
System.out.println("---->"+item);
}
System.out.println("Sorted Collection before Java8");
Collections.sort(list, new Comparator() {
@Override
public int compare(Integer o1, Integer o2) {
return o1-o2;
}
});
for(Integer item : list){
System.out.println("---->"+item);
}
list = new ArrayList<>();
list.add(3);
list.add(5);
list.add(4);
System.out.println("Sorted Collection By Java8");
Collections.sort(list, (item1,item2)->item1-item2);
for(Integer item : list){
System.out.println("---->"+item);
}
java.io.FileFilter
例如:
File files;
File[] file;
try{
files = new File("/Users/qinzongke/ShareProjects/Java8Studio/app");
file = files.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.isDirectory();
}
});
for (File item : file){
System.out.println("fileFiltertest---->"+item.getAbsolutePath());
}
file = files.listFiles(item->item.isFile());
for (File item : file){
System.out.println("fileFiltertest---->"+item.getAbsolutePath());
}
}catch (Exception e){
}
Java8新增的函数接口
java.util.function
主要分为以下几个基本类别
Function 函数型接口 输入参数为类型T, 输出为类型R, 记作 T -> R
Consumer 消费型接口 输入参数为类型T, 输出为void, 记作 T -> void
Supplier 供给型接口 没有输入参数, 输出为类型T, 记作 void -> T
Predicate 断言型接口 输入参数为类型T, 输出为类型boolean, 记作 T -> boolean
static class AddNewInterface{
private BiConsumer customer;
private BiFunction function;
public AddNewInterface(BiFunction function){
this.function =function;
}
public AddNewInterface(BiConsumer customer){
this.customer = customer;
}
public void getHandler1(int value1,int value2){
if(customer != null){
customer.accept(value1,value2);
}
}
public int getHandler2(int value1,int value2){
if(function != null){
return function.apply(value1,value2);
}
return 0;
}
private void addNewInterfaceTest(){
AddNewInterface interface1 = new AddNewInterface(new BiConsumer(){
@Override
public void accept(Integer t, Integer u) {
// TODO Auto-generated method stub
System.out.println("value1---->"+t);
System.out.println("value2---->"+u);
}
});
AddNewInterface interface2 = new AddNewInterface((value1,value2)->{
System.out.println("Java8--->value1="+value1);
System.out.println("Java8---->value2="+value2);
});
interface1.getHandler1(10,20);
interface2.getHandler1(30, 40);
AddNewInterface interface3 = new AddNewInterface(new BiFunction(){
@Override
public Integer apply(Integer t, Integer u) {
// TODO Auto-generated method stub
return t*u;
}
});
AddNewInterface interface4 = new AddNewInterface((value1,value2)->value1+value2);
int count1 = interface3.getHandler2(10,20);
System.out.println("count1---->"+count1);
int count2 = interface4.getHandler2(10,20);
System.out.println("count2---->"+count2);
}
默认方法
概念
默认方法就是接口可以有实现方法,而且不需要实现类去实现其方法。
我们只需在方法名前面加个default关键字即可实现默认方法。
默认方法也可以被重写
语法
例如:
interface TestInterface{
int add(int value1,int value2);
default void test2(String message){
System.out.println("TestInterface--->test2----->"+message);
}
default void test3(String message){
System.out.println("TestInterface--->test3----->"+message);
}
}
private void defaultMethodTest(){
TestInterface interface1 = (value1,value2)->value1+value2;
int count = interface1.add(10,20);
interface1.test2("aaaaa");
interface1.test3("bbbbb");
}
多个默认方法
一个类实现了多个接口,且这些接口有相同的默认方法
interface TestInterface{
int add(int value1,int value2);
default void test2(String message){
System.out.println("TestInterface--->test2----->"+message);
}
default void test3(String message){
System.out.println("TestInterface--->test3----->"+message);
}
}
interface TestInterface2{
int add(int value1,int value2);
default void test2(String message){
System.out.println("TestInterface2--->test2----->"+message);
}
default void test3(String message){
System.out.println("TestInterface2--->test3----->"+message);
}
}
class TestInterfaceClass implements TestInterface,TestInterface2{
@Override
public int add(int value1, int value2) {
return value1+value2;
}
@Override
public void test2(String message) {
//方法1:创建自己的默认方法,来覆盖重写接口的默认方法
System.out.println("TestInterfaceClass---->"+message);
}
@Override
public void test3(String message) {
//方法2:使用 super 来调用指定接口的默认方法
TestInterface2.super.test3(message);
}
}
静态默认方法
interface TestInterface{
int add(int value1,int value2);
default void test2(String message){
System.out.println("TestInterface--->test2----->"+message);
}
static void test4(String message){
System.out.println("TestInterface--->test4--->"+message);
}
default void test3(String message){
System.out.println("TestInterface--->test3----->"+message);
}
}
private void defaultStaticMethodTest(){
TestInterface.test4("defaultStaticMethodTest");
}
方法引用
作用
我们通常使用lambda表达式来创建匿名方法。然而,有时候我们仅仅是调用了一个已存在的方法
方法引用可以使语言的构造更紧凑简洁,减少冗余代码。
方法引用使用一对冒号 ::
例如:
String [] arr = {"a","c","d","b"};
Arrays.sort(arr, new Comparator() {
@Override
public int compare(String o1, String o2) {
return o1.compareToIgnoreCase(o2);
}
});//普通方式
Arrays.sort(arr,(s1,s2)->s1.compareToIgnoreCase(s2));//lambda 方式
Arrays.sort(arr,String::compareToIgnoreCase);//方法引用方式
适用场景: 当一个Lambda表达式调用了一个已存在的方法
不适用场景: 当我们需要引用的方法传其它参数的时候,不适合,
public class MethodReferenceBean {
public static void staticMethodTest(){
System.out.println("i am static method without params");
}
public static void staticMethodTest2(MethodReferenceBean bean){
System.out.println("i am static method without params");
}
}
private void test1(){
List list = new ArrayList<>();
for(int i = 0;i<10;i++){
list.add(new MethodReferenceBean());
}
list.forEach(new Consumer(){
@Override
public void accept(MethodReferenceBean t) {
// TODO Auto-generated method stub
MethodReferenceBean.staticMethodTest();
}
});
list.forEach(item->MethodReferenceBean.staticMethodTest());//可以使用
list.forEach(item->MethodReferenceBean.staticMethodTest2(item));//可以使用
list.forEach(MethodReferenceBean::staticMethodTest);//不可使用
list.forEach(MethodReferenceBean::staticMethodTest2);//可以使用;
}
构造器引用
语法:Class::new
一般同Supplier接口联合使用 可自定义类似接口 目前Android最低支持的SDKApi为 24
注意:对目标类必须存在无参的构造方法
例如:
public class Test2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Test2 testBean1 = new Test2();//方法1
Test2 testBean2 = Test2.newInstance();//方法2
Test2 testBean3 = Test2.newInstance(Test2::new);//方法3
}
public static Test2 newInstance(Supplier supplier){
return supplier.get();
}
public static Test2 newInstance(){
return new Test2();
}
}
- 下一步优化
public class InstanceFactory {
public static T getInstance(Supplier supplier){
return supplier.get();
}
}
public class Test2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Test2 testBean1 = InstanceFactory.getInstance(Test2::new);
}
}
针对构造方法传递参数的情况
@FunctionalInterface
public interface InstanceFactorys {
T getInstance(int param1,String param2,String param3);
}
public class Test2 {
private int id;
private String name;
private String address;
public Test2(int id, String name, String address) {
this.id = id;
this.name = name;
this.address = address;
}
public Test2() {
}
public static void main(String[] args) {
// TODO Auto-generated method stub
//InstanceFactorys函数式接口 接口内至存在一个方法
InstanceFactorys factorys = Test2::new;//必须存在无参的构造方法
Test2 testBean = factorys.getInstance(1,"name","address");
System.out.println("id-->"+testBean.id);
System.out.println("name-->"+testBean.name);
System.out.println("address-->"+testBean.address);
}
}
Stream API
基本概念
本质: 对集合功能的完善,以声明的形式操作集合,它就像SQL语句,我们只需告诉流需要对集合进行什么操作,它就会自动进行操作,并将执行结果交给你,无需我们自己手写代码。
这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。
例如: 获取一批学生年龄>=20并且性别为男的同学集合并按年龄降序排列打印信息
class Student {
public String name;
public int age;
public int sex;// 1 男 2 女
public Student(String name, int age, int sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
}
/**
* 获取学生数据源集合
* @return
*/
private List getDataSource() {
List dataSource = new ArrayList<>();
dataSource.add(new Student("test1", 5, 1));
dataSource.add(new Student("test2", 10, 2));
dataSource.add(new Student("test3", 15, 2));
dataSource.add(new Student("test4", 20, 1));
dataSource.add(new Student("test5", 5, 2));
dataSource.add(new Student("test6", 10, 1));
dataSource.add(new Student("test7", 15, 2));
dataSource.add(new Student("test8", 20, 1));
dataSource.add(new Student("test9", 25, 2));
dataSource.add(new Student("test10", 25, 1));
return dataSource;
}
/**
* Java7处理方式
*/
private void handlerJava7() {
List dataSource = getDataSource();
List newData = new ArrayList();
for (Student student : dataSource) {
if (student.age >= 20 && student.sex == 1) {
newData.add(student);
}
}
Collections.sort(newData, new Comparator() {
@Override
public int compare(Student s1, Student s2) {
// TODO Auto-generated method stub
return s2.age - s1.age;
}
});
for (Student s : newData) {
System.out.println("name--->"+s.name+" age------>" + s.age);
}
}
//Sql处理
select * from student where sex=1 and age >=20 order by age desc
/**
* Java8处理方式
*/
private void handlerJava8() {
List dataSource = getDataSource();
dataSource.stream().filter(s -> s.age >= 20 && s.sex == 1).sorted((s1, s2) -> s2.age - s1.age)
.collect(Collectors.toList()).forEach(s -> System.out.println("name--->"+s.name+" age--->" + s.age));
}
流的操作步骤
- 准备一个数据源
- 执行中间操作
中间操作可以有多个,它们可以串连起来形成流水线。
- 执行终端操作
执行终端操作后本次流结束,将获得一个执行结果
一个完整的Stream操作由零个或多个中间操作(intermediate operation)和一个结束操作(terminal operation)两部分组成。只有执行结束操作时,Stream定义的中间操作才会依次执行,
从操作的返回值来看:如果返回值是Stream,那么就是惰性求值;如果返回值不是Stream或者是void,那么就是及早求值。一个完整的Stream操作是有多个惰性求值和一个及早求值组成
流的获取
- 集合 这种数据源较为常用,通过stream()方法即可获取流对象
对应Collection接口
//获取串形流
default Stream stream() {
return StreamSupport.stream(this.spliterator(), false);
}
//获取并形流
default Stream parallelStream() {
return StreamSupport.stream(this.spliterator(), true);
}
例如
List lists = new ArrayList<>();
Stream stream = lists.stream();
- 数组 通过Arrays类提供的静态函数stream()获取数组的流对象
例如:
String[] names = {"chaimm","peter","john"};
Stream stream = Arrays.stream(names);
- 值 直接将几个值变成流对象
Stream stream =Stream.of("test1","test2","test3");
- 其他
generator方法,返回一个无限长度的Stream,其元素由Supplier接口的提供。在Supplier是一个函数接口,只封装了一个get()方法,其用来返回任何泛型的值,该结果在不同的时间内,返回的可能相同也可能不相同,没有特殊的要求。这种情形通常用于随机数、常量的 Stream,默认是串行(相对 parallel 而言)但无序的(相对 ordered 而言)。
/**
* Returns an infinite sequential unordered stream where each element is
* generated by the provided {@code Supplier}. This is suitable for
* generating constant streams, streams of random elements, etc.
*
* @param the type of stream elements
* @param s the {@code Supplier} of generated elements
* @return a new infinite sequential unordered {@code Stream}
*/
public static Stream generate(Supplier s) {
Objects.requireNonNull(s);
return StreamSupport.stream(
new StreamSpliterators.InfiniteSupplyingSpliterator.OfRef<>(Long.MAX_VALUE, s), false);
}
/**
* generator 生成Stream
* 配合limit 和filter 使用 否则会无限执行
*/
private void generatorSteam(){
Stream.generate(()->Math.random()).limit(10).forEach(item->System.out.println("--->"+item));;
}
iterate方法,其返回的也是一个无限长度的Stream,与generate方法不同的是,其是通过函数f迭代对给指定的元素种子而产生无限连续有序Stream,其中包含的元素可以认为是:seed,f(seed),f(f(seed))无限循环。
/**
* Returns an infinite sequential ordered {@code Stream} produced by iterative
* application of a function {@code f} to an initial element {@code seed},
* producing a {@code Stream} consisting of {@code seed}, {@code f(seed)},
* {@code f(f(seed))}, etc.
*
* The first element (position {@code 0}) in the {@code Stream} will be
* the provided {@code seed}. For {@code n > 0}, the element at position
* {@code n}, will be the result of applying the function {@code f} to the
* element at position {@code n - 1}.
*
* @param the type of stream elements
* @param seed the initial element
* @param f a function to be applied to to the previous element to produce
* a new element
* @return a new sequential {@code Stream}
*/
public static Stream iterate(final T seed, final UnaryOperator f) {
Objects.requireNonNull(f);
final Iterator iterator = new Iterator() {
@SuppressWarnings("unchecked")
T t = (T) Streams.NONE;
@Override
public boolean hasNext() {
return true;
}
@Override
public T next() {
return t = (t == Streams.NONE) ? seed : f.apply(t);
}
};
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
iterator,
Spliterator.ORDERED | Spliterator.IMMUTABLE), false);
}
/**
* iterate生成Stream
*/
private void iterateStream(){
Stream.iterate(2, item->item*item).filter(item->item!=0).forEach(item->System.out.println("---->"+item));
}
concat方法将两个Stream连接在一起,合成一个Stream。若两个输入的Stream都时排序的,则新Stream也是排序的;若输入的Stream中任何一个是并行的,则新的Stream也是并行的;若关闭新的Stream时,原两个输入的Stream都将执行关闭处理。
/**
* Creates a lazily concatenated stream whose elements are all the
* elements of the first stream followed by all the elements of the
* second stream. The resulting stream is ordered if both
* of the input streams are ordered, and parallel if either of the input
* streams is parallel. When the resulting stream is closed, the close
* handlers for both input streams are invoked.
*
* @implNote
* Use caution when constructing streams from repeated concatenation.
* Accessing an element of a deeply concatenated stream can result in deep
* call chains, or even {@code StackOverflowException}.
*
* @param The type of stream elements
* @param a the first stream
* @param b the second stream
* @return the concatenation of the two input streams
*/
public static Stream concat(Stream extends T> a, Stream extends T> b) {
Objects.requireNonNull(a);
Objects.requireNonNull(b);
@SuppressWarnings("unchecked")
Spliterator split = new Streams.ConcatSpliterator.OfRef<>(
(Spliterator) a.spliterator(), (Spliterator) b.spliterator());
Stream stream = StreamSupport.stream(split, a.isParallel() || b.isParallel());
return stream.onClose(Streams.composedClose(a, b));
}
/**
* concat 组合生成Stream
*/
private void concatStream(){
Stream.concat(Stream.of(1,2,3),Stream.of(4,5,6)).forEach(item->System.out.println("---->"+item));
}
串行流、并行流
串行流:操作由一个线程串行处理
并行流:把一个内容分成多个数据块,并用不同的线程分 别处理每个数据块的流
相互转换:对流使用parallel()方法将串行流转换为并行流。对流使用sequential()方法将并行流转换为串行流。
/**
* Returns an equivalent stream that is sequential. May return
* itself, either because the stream was already sequential, or because
* the underlying stream state was modified to be sequential.
*
* This is an intermediate
* operation.
*
* @return a sequential stream
*/
S sequential();
/**
* Returns an equivalent stream that is parallel. May return
* itself, either because the stream was already parallel, or because
* the underlying stream state was modified to be parallel.
*
* This is an intermediate
* operation.
*
* @return a parallel stream
*/
S parallel();
中间操作
中间操作负责将一个流转换为另一个流,包括 filter()(选择与条件匹配的元素)、map()(根据函数来转换元素)、distinct()(删除重复)、limit()(在特定大小处截断流)和 sorted()。
filter
对于Stream中包含的元素使用给定的过滤函数进行过滤操作,新生成的Stream只包含符合条件的元素
例如:
private void streamTest(){
Stream.of(1,2,2,3,3,4,4,5,5,6,6,7,8,9,10).filter(item->item%2 == 0).forEach(item->System.out.println("---->"+item));
}
distinct
返回去重的Stream
private void streamTest(){
Stream.of(1,2,2,3,3,4,4,5,5,6,6,7,8,9,10).filter(item->item%2 == 0).distinct().forEach(item->System.out.println("---->"+item));
}
sorted
返回一个排序的Stream。默认升序排列
private void streamTest(){
// Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).distinct().sorted().forEach(item->System.out.println("---->"+item));
Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).distinct().sorted((item1,item2)->item2-item1).forEach(item->System.out.println("---->"+item));
}
limit
返回前n个元素数据组成的Stream。属于短路操作
private void streamTest(){
Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).limit(10).filter(item->item%2 == 0).distinct().sorted((item1,item2)->item2-item1).forEach(item->System.out.println("---->"+item));
}
skip
返回第n个元素后面数据组成的Stream
private void streamTest(){
Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).skip(4).filter(item->item%2 == 0).distinct().sorted((item1,item2)->item2-item1).forEach(item->System.out.println("---->"+item));
}
map
对于Stream中包含的元素使用给定的转换函数进行转换操作,新生成的Stream只包含转换生成的元素。这个方法有三个对于原始类型的变种方法,分别是:mapToInt,mapToLong和mapToDouble。这三个方法也比较好理解,比如mapToInt就是把原始Stream转换成一个新的Stream,这个新生成的Stream中的元素都是int类型。之所以会有这样三个变种方法,可以免除自动装箱/拆箱的额外消耗;
private void streamTest(){
Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).skip(4).peek(item->System.out.println("peek--->"+item)).filter(item->item%2 == 0).distinct().map(item->item*2).sorted((item1,item2)->item2-item1).forEach(item->System.out.println("---->"+item));
}
flatMap
和map类似,不同的是其每个元素转换得到的是Stream对象,会把子Stream中的元素压缩到
private void streamTest(){
Stream.of(Arrays.asList(1,2,3),Arrays.asList(4,5,6)).flatMap(item->item.stream()).map(item->item*2).forEach(item->System.out.println("flat--->"+item));
// Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).skip(4).peek(item->System.out.println("peek--->"+item)).filter(item->item%2 == 0).distinct().map(item->item*2).sorted((item1,item2)->item2-item1).forEach(item->System.out.println("---->"+item));
}
peek
生成一个包含原Stream的所有元素的新Stream,同时会提供一个消费函数(Consumer实例),新Stream每个元素被消费的时候都会执行给定的消费函数
private void streamTest(){
Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).skip(4).peek(item->System.out.println("peek--->"+item)).filter(item->item%2 == 0).distinct().sorted((item1,item2)->item2-item1).forEach(item->System.out.println("---->"+item));
}
终端操作
数据集的处理在执行终止操作时开始,比如缩减(sum() 或 max())、应用 (forEach()) 或搜索 (findFirst()) 操作。终止操作会生成一个结果或无结果
forEach
将提供的操作应用于流的每个元素
private void streamTest(){
// Stream.of(Arrays.asList(1,2,3),Arrays.asList(4,5,6)).flatMap(item->item.stream()).map(item->item*2).forEach(item->System.out.println("flat--->"+item));
Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).skip(4).peek(item->System.out.println("peek--->"+item)).filter(item->item%2 == 0).distinct().map(item->item*2).sorted((item1,item2)->item2-item1).forEach(item->System.out.println("---->"+item));
}
toArray
使用流的元素创建一个数组
Integer[] arrays = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).distinct().toArray(item-> new Integer[item]);
collect
将流的元素聚合到一个汇总结果容器中。
List array = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).distinct().collect(Collectors.toList());
Collectors
为Stream的collect提供转换类型
toList
把流中所有元素收集到List中
返回类型: List
toSet
把流中所有元素收集到Set中,删除重复项
返回类型:Set
Set array = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).collect(Collectors.toSet());
toCollection
把流中所有元素收集到给定的供应源创建的集合中
返回类型:Collection
ArrayList array = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).collect(Collectors.toCollection(()->new ArrayList()));
counting
计算流中元素个数
返回类型:long
long count = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).collect(Collectors.counting());
summingInt
对流中元素的一个整数属性求和
返回类型:Integer
int count = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).collect(Collectors.summingInt(item->item));
averagingInt
计算流中元素integer属性的平均值
返回值类型:Double
double count = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).collect(Collectors.averagingInt(item->item));
joining
连接流中每个元素的toString方法生成的字符串
返回值类型:String
String str = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).map(item->String.valueOf(item)).collect(Collectors.joining(","));
maxBy
流中按照给定比较器选出的最大元素的optional
如果为空返回的是Optional.empty()
返回值类型:Optional
Optional value = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).collect(Collectors.maxBy((item1,item2)->item1-item2));
minBy
流中按照给定比较器选出的最大元素的optional
如果为空返回的是Optional.empty()
返回值类型:Optional
Optional value = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).collect(Collectors.minBy((item1,item2)->item1-item2));
reducing
从一个作为累加器的初始值开始,利用binaryOperator与流中的元素逐个结合,从而将流归约为单个值
返回值类型:T / Optional
int value1 = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).collect(Collectors.reducing(100,(item1,item2)->item1+item2));
int value2 = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).collect(Collectors.reducing((item1,item2)->item1+item2)).get();
groupingBy
根据流中元素的某个值对流中的元素进行分组,并将属性值做为结果map的键
返回值类型:Map>
List datas = getDataSource();
Map> data = datas.stream().collect(Collectors.groupingBy((item1)->item1.sex));
partitioningBy
根据流中每个元素应用谓语的结果来对项目进行分区
返回值类型:Map>
Map> data = datas.stream().collect(Collectors.partitioningBy(item->item.sex==1));
reduce/min/max/count
作用类似Collectors中
int value1 = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).limit(3).filter(item->item%2 == 0).reduce((item1,item2)->item1+item2).get();
int value2 = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).limit(3).filter(item->item%2 == 0).reduce(100,(item1,item2)->item1+item2);
int value3 = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).max((item1,item2)->item1-item2).get();
int value4 = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).min((item1,item2)->item1-item2).get();
anyMatch/allMatch/noneMatch
有一个符合条件返回true/全部符合条件返回true/完全不符合条件返回true
List datas = getDataSource();
boolean flag1 = datas.stream().anyMatch(item->item.sex==1);
boolean flag2 = datas.stream().anyMatch(item->item.sex==2);
boolean flag3 = datas.stream().anyMatch(item->item.sex==3);
boolean flag4 = datas.stream().noneMatch(item->item.sex == 3);
boolean flag5 = datas.stream().noneMatch(item->item.sex==2);
boolean flag6 = datas.stream().allMatch(item->item.sex == 1);
findFirst/findAny
返回流的第一个元素(如果有)/返回流的任一个元素(如果有)
Student student1 = datas.stream().findFirst().get();
Student student2 = datas.stream().findAny().get();
Optional 类
Optional 类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
Optional 类的引入很好的解决空指针异常
class TestBean {
public TestBean1 bean1;
public TestBean(TestBean1 bean1) {
this.bean1 = bean1;
}
}
class TestBean1 {
public TestBean2 bean2;
public TestBean1(TestBean2 bean) {
this.bean2 = bean;
}
}
class TestBean2 {
public String name;
public TestBean2(String name) {
this.name = name;
}
}
private void testJava7(TestBean bean) {
if(bean != null){
if(bean.bean1!=null){
if(bean.bean1.bean2 != null){
System.out.println(bean.bean1.bean2.name);
}
}
}
}
private void testJava8(TestBean bean) {
Optional.ofNullable(bean).map(item->item.bean1).map(item->item.bean2).ifPresent(t->System.out.println(t.name));
}
创建Optional对象
- of
of方法通过工厂方法创建Optional类。需要注意的是,创建对象时传入的参数不能为null。如果传入参数为null,则抛出NullPointerException
TestBean bean = new TestBean(1,"test1",15,1);
Optional test = Optional.of(bean);
TestBean bean1 = null;
Optional test1 = Optional.of(bean1);//抛出异常 java.lang.NullPointerException
- ofNullable
为指定的值创建一个Optional,如果指定的值为null,则返回一个空的Optional.ofNullable与of方法相似,唯一的区别是可以接受参数为null的情况
TestBean bean = new TestBean(1,"test1",15,1);
Optional test = Optional.ofNullable(bean);
TestBean bean1 = null;
Optional test1 = Optional.ofNullable(bean1);
isPresent
判断Optional对象中的值是否存在,若存在返回true,否则返回false
/**
* Return {@code true} if there is a value present, otherwise {@code false}.
*
* @return {@code true} if there is a value present, otherwise {@code false}
*/
public boolean isPresent() {
return value != null;
}
Optional optional1 = Optional.ofNullable("HelloWordl");
boolean flag = optional1.isPresent();
get
若Optional对象中的值存在则通过get()获取,否则抛NoSuchElementException异常
/**
* If a value is present in this {@code Optional}, returns the value,
* otherwise throws {@code NoSuchElementException}.
*
* @return the non-null value held by this {@code Optional}
* @throws NoSuchElementException if there is no value present
*
* @see Optional#isPresent()
*/
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
Optional optional = Optional.ofNullable("HelloWordl");
String str = optional.get();
ifPresent
如果 Optional 中有值,则对该值调用 consumer.accept,否则什么也不做
/**
* If a value is present, invoke the specified consumer with the value,
* otherwise do nothing.
*
* @param consumer block to be executed if a value is present
* @throws NullPointerException if value is present and {@code consumer} is
* null
*/
public void ifPresent(Consumer super T> consumer) {
if (value != null)
consumer.accept(value);
}
Optional optional = Optional.ofNullable("HelloWordl");
String str = optional.get();
optional.ifPresent(item->System.out.println(item));
orElse
如果 Optional 中有值则将其返回,否则返回 orElse 方法传入的参数
/**
* Return the value if present, otherwise return {@code other}.
*
* @param other the value to be returned if there is no value present, may
* be null
* @return the value, if present, otherwise {@code other}
*/
public T orElse(T other) {
return value != null ? value : other;
}
Optional optional = Optional.of("HelloWorld");
System.out.println(optional.orElse("Java"));
optional = Optional.ofNullable(null);
System.out.println(optional.orElse("Java"));
orElseGet
orElseGet 与 orElse 方法的区别在于,orElseGet 方法传入的参数为一个 Supplier 接口的实现 —— 当 Optional 中有值的时候,返回值;当 Optional 中没有值的时候,返回从该 Supplier 获得的值。
/**
* Return the value if present, otherwise invoke {@code other} and return
* the result of that invocation.
*
* @param other a {@code Supplier} whose result is returned if no value
* is present
* @return the value if present otherwise the result of {@code other.get()}
* @throws NullPointerException if value is not present and {@code other} is
* null
*/
public T orElseGet(Supplier extends T> other) {
return value != null ? value : other.get();
}
Optional optional = Optional.of("HelloWorld");
System.out.println(optional.orElseGet(()->"Java"));
optional = Optional.ofNullable(null);
System.out.println(optional.orElseGet(()->"Java"));
orElseThrow
orElseThrow 与 orElse 方法的区别在于,orElseThrow 方法当 Optional 中有值的时候,返回值;没有值的时候会抛出异常,抛出的异常由传入的 exceptionSupplier 提供
/**
* Return the contained value, if present, otherwise throw an exception
* to be created by the provided supplier.
*
* @apiNote A method reference to the exception constructor with an empty
* argument list can be used as the supplier. For example,
* {@code IllegalStateException::new}
*
* @param Type of the exception to be thrown
* @param exceptionSupplier The supplier which will return the exception to
* be thrown
* @return the present value
* @throws X if there is no value present
* @throws NullPointerException if no value is present and
* {@code exceptionSupplier} is null
*/
public T orElseThrow(Supplier extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
Optional optional = Optional.of("HelloWorld");
System.out.println(optional.orElseThrow(()->new StringNotFoundException("String Not Found")));
optional = Optional.ofNullable(null);
System.out.println(optional.orElseThrow(()->new StringNotFoundException("String Not Found")));
filter
如果有值并且满足断言条件返回包含该值的Optional,否则返回空Optional。
Optional optional = Optional.of("HelloWorld");
System.out.println(optional.filter(item->item.length()>10).orElse("NotFoundString"));
map
如果有值,则对其执行调用mapping函数得到返回值。如果返回值不为null,则创建包含mapping返回值的Optional作为map方法返回值,否则返回空Optional。
Optional optional = Optional.of("HelloWorld");
System.out.println(optional.filter(item->item.length()>=5).map(item->item+"----->").get());
flatMap
如果有值,为其执行mapping函数返回Optional类型返回值,否则返回空Optional。flatMap与map(Funtion)方法类似,区别在于flatMap中的mapper返回值必须是Optional。调用结束时,flatMap不会对结果用Optional封装。
Optional optional = Optional.of("HelloWorld");
System.out.println(optional.filter(item->item.length()>=5).map(item->item+"----->").flatMap(item->Optional.of(item)).get());