Java刷题中要熟练使用的Stream流、Lambda表达式、容器Api
- 1.Stream流
- 1.概述
- 2.分类
- 3.具体用法
- 流的常用创建方法
- 2.Lambda表达式
- 函数式接口
- Lambda书写语法
- 方法引用
- 3.各类Api
1.Stream流
1.概述
Stream Api是「集合操作」的一种简化表达形式。其特点是惰性求值,流在中间处理过程中,只是对操作进行了记录,并不会立即执行,需要等到执行终止操作的时候才会进行实际的计算。
2.分类
参考Java 8 stream 的详细用法,其分类如下:
-
无状态:指元素的处理不受之前元素的影响;
-
有状态:指该操作只有拿到所有元素之后才能继续下去。
-
非短路操作:指必须处理所有元素才能得到最终结果;
-
短路操作:指遇到某些符合条件的元素就可以得到最终结果,如 A || B,只要A为true,则无需判断B的结果。
3.具体用法
流的常用创建方法
- Collection(包括List、Set、Map键和值)下的 stream() 和 parallelStream() 方法获取流
List<String> list = new ArrayList<>();
Stream<String> stream = list.stream(); //获取一个顺序流
Stream<String> parallelStream = list.parallelStream(); //获取一个并行流
- 数组获取流
Integer[] nums = new Integer[10];
Stream<Integer> stream = Arrays.stream(nums);
还可以
Stream<Integer> stream1=Stream.of(nums);
- 使用Stream中的静态方法:of()、iterate()、generate()
Stream<Integer> stream = Stream.of(1,2,3,4,5,6);
Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 2).limit(6);
stream2.forEach(System.out::println); // 0 2 4 6 8 10
Stream<Double> stream3 = Stream.generate(Math::random).limit(2);
stream3.forEach(System.out::println);
常用操作:
- Collection容器(list[Integer])转换成数组(int[]):将
Collection<Integer>
类型的容器转换为IntStream
,然后再用IntStream.toArray()
方法将IntStream
转换为int[]
数组。
List<Integer> list=new LinkedList<>();
int []arr=list.stream().mapToInt(x->x).toArray();
- 数组(int[])转换成Collection容器(list[Integer]):使用
Arrays.stream
将int[]
转换成IntStream
;使用IntStream
中的boxed()装箱
,将IntStream
转换成Stream<Integer>
;使用Stream
的collect()
,将Stream<T>
转换成List<T>
,因此正是List<Integer>
。
int []data=new int[10];
List<Integer> list=Arrays.stream(data).boxed().collect(Collectors.toList());
2.Lambda表达式
Lambda表达式是「创建匿名内部类对象」的一种简化方式。
Lambda表达式常见的用法就是将其创建的对象作为参数传递给方法。
函数式接口
Lambda表达式的目标类型必须是「函数式接口」,函数式接口是只包含一个抽象方法的接口,可以使用@FunctionalInterface 注解进行检查。函数式接口可以包含多个默认方法、类方法,但仅能声明一个抽象方法。感性理解来看,实现接口中的抽象方法,我们就能使用该被实现的接口创建匿名内部类对象,正是对这个过程进行简化。例如:
//自定义函数式接口
@FunctionalInterface
interface eat {
void eatFood();
}
public static void main(String[] args) {
//override实现抽象方法,创建匿名内部类
eat e1 = new eat(){
@Override
public void eatFood(){
System.out.println("传统方法创建对象");
}
};
e1.eatFood();
//lambda表达式进行匿名内部类创建简化
eat e2 = () -> System.out.println("lambda方式创建对象");
e2.eatFood();
}
自定义函数式接口:
@FunctionalInterface //此注解用来表明是函数式接口
public interface MyInterface<T> {
//函数式接口中只能有一个抽象方法
void getValue(T t);
}
//自定义函数的Lambda表达式实现
MyInterface<String> myinter= (x)-> System.out.println(x);
JDK中常用的函数式接口:
常见的还有Comparator<T>
更全面的总结可以参考Java8中Function函数式接口详解及使用。
Lambda书写语法
lambda表达式的语法格式如下:
(实现的这个接口中的抽象方法中的形参列表parameters) -> 抽象方法的处理expression;
或
(实现的这个接口中的抽象方法中的形参列表parameters) ->{抽象方法的处理 statements; };
- 可选参数类型声明:可以不声明参数类型。
- 可选的参数圆括号:一个参数无需定义圆括号。
- 可选的方法体大括号:expression只有一条语句,可以不用大括号。
- 可选的return关键字:expression只有一个返回值,可以不写返回关键字。
无返回值的抽象方法:
//抽象方法无返回值
public interface MyInterface {
public abstract void show(int a,int b);
}
public class MyTest1 {
public static void main(String[] args) {
//传统的匿名内部类中重写方法
MyInterface myInter = new MyInterface() {
@Override
public void show(int a, int b) {
System.out.println(a + b);
}
};
myInter.show(20, 30);//50
//简写1:标准的lambda简化,抽象方法实现
MyInterface myInter1 = (int a, int b) -> {
System.out.println(a + b);
};
myInter1.show(20, 40);//60
//简写2:省略形参列表中的形参类型
MyInterface myInter2 = (a, b) -> {
System.out.println(a + b);//70
};
myInter2.show(20, 50);
//简写3:方法体中只有一行代码,进行简化
MyInterface myInter3 = (a, b) -> System.out.println(a + b);
myInter3.show(20, 60);//80
}
}
有返回值的抽象方法:
//抽象方法有int返回值
public interface MyInterface {
public abstract int test(int a,int b);
}
public class MyTest2 {
public static void main(String[] args) {
//传统的匿名内部类写法
MyInterface test1 = new MyInterface() {
@Override
public int test(int a, int b) {
return a - b;
}
};
System.out.println(test1.test(90, 8));//82
//简写1:标准的lambda简化,抽象方法实现
MyInterface test2 = (int a, int b) -> {
return a - b;
};
System.out.println(test2.test(20, 10));//10
//简写2:省略形参列表中的形参类型
MyInterface test3 = (a, b) -> {return a - b;};
System.out.println(test3.test(30, 10));//20
//简写3:方法中只有一行代码,可以简化,同时去掉return关键字
MyInterface test4 = (a, b) -> a - b;
System.out.println(test4.test(40, 10));//30
}
}
只有一个形参的抽象方法:
//抽象方法只有一个形参
public interface MyInterface {
public abstract int show(int a);
}
public class MyTest3 {
public static void main(String[] args) {
//传统的匿名内部类写法
MyInterface myInter = new MyInterface(){
@Override
public int show(int a){
return a-20;
}
};
System.out.println(myInter.show(20););//0
//简写1:标准的lambda简化,抽象方法实现
MyInterface myInter1= (int a)->{
return a-20;
};
System.out.println(myInter1.show(30););//10
//简写2:省略形参列表中的形参类型
MyInterface myInter2=(a)->{
return a-20;
};
System.out.println(myInter2.show(40););//20
//简写3:方法中只有一行代码,可以简化,同时去掉return关键字
MyInterface myInter3=(a)->a-20;
System.out.println(myInter3.show(50););//30
//简写4:一个形参可以不写圆括号
MyInterface myInter4=a->a-20;
System.out.println(myInter4.show(50););//30
}
}
方法引用
当Lambda方法体中的操作,已经有别的对象或类实现了,就可以尝试引用已实现的方法。
传入方法的参数和方法内部调用方法的入参是一样的。
分类:
静态方法引用:
Consumer<String> c1 = r -> Integer.parseInt(r);
c1.accept("1");
Consumer<String> c2 =Integer::parseInt;
c1.accept("2");
实例方法引用:
Consumer<String> ins1 = r -> System.out.print(r);
c1.accept("1");
Consumer<String> ins2 =System.out::print;
c1.accept("2");
对象方法引用:
Comparator<String> comparator = (o1, o2)->o1.compareTo(o2);
System.out.println(comparator.compare("20", "12"));//1
Comparator<String> comparator1 = String::compareTo;
System.out.println(comparator1.compare("20", "12"));//1
构造方法引用:
Consumer<String> n1 = r ->new BigDecimal(r);
c1.accept("1");
Consumer<String> n2 =BigDecimal::new;
c1.accept("2");
3.各类Api
// list类型转换为数组
List<Integer> list=new LinkedList<>();
list.stream().mapToInt(x->x).toArray();
// 数组转换为list
int []arr=new int[]{1,2,3};
Arrays.asList(arr);
// lambda实现int[]转List<Integer>
List<Integer> list1= new LinkedList<>();
Arrays.stream(arr).boxed().collect(Collectors.toList());
// set类型转换为数组
Set<Integer> set=new HashSet<>();
set.stream().mapToInt(x->x).toArray();