Lambda表达式:
为匿名内部类提供了简便的写法
了解内部类的使用
public static void main1(String[] args) {
//在方法内部定义内部类
class MyClass{
public void say(){
System.out.printf("我是内部类");
}
}
//使用内部类创建对象
MyClass myClass = new MyClass();
myClass.say();
//简便写法
new MyClass().say();
}
优化成匿名内部类
public interface MyInferface1 {
void run();
}
在代码中使用创建对象
public static void main2(String[] args) {
//匿名内部类
//匿名内部类,必须继承其他类或者是实现某个接口
MyInferface1 myInferface1 = new MyInferface1() {
@Override
public void run() {
System.out.println("我是匿名内部类");
}
};
myInferface1.run();
/省略引用
new MyInferface1(){
@Override
public void run() {
System.out.println("我是匿名内部类2");
}
}.run();
}
lambda表达式的优化
必须是接口,而且只能有一个抽象方法
public interface MyInterface{
void run();
}
必须通过引用接收创建对象
public static void main3(String[] args) {
//lambda表达式对匿名内部类的优化
//1,必须是接口
//2, 只能有一个未实现的方法
MyInferface1 myInferface1 = ()->{
System.out.println("lambda表达式");
};
myInferface1.run();
}
主要是把接口当参数传递到别的方法中(用来模拟函数的引用传递)
定义接口
public interface MyForEachInterface {
void each(Object o);
}
定义调用方法
//实现了一个方法,可以遍历集合
public static void myForEach(List list,
MyForEachInterface eachInterface){
for(int i=0;i<list.size();i++){
//调用了传递进入来的接口的方法
eachInterface.each(list.get(i));
}
}
使用这个myForEach方法的时候,通过lambda表达式传递方法的引用
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
for (int i=0;i<10;i++){
list.add(i);
}
//使用lambda表达式遍历
list.forEach(obj->{
System.out.println("打印方式1"+obj);
});
myForEach(list,obj->{
System.out.println("打印方式2"+obj.toString());
});
}
函数接口:
在java中不能将方法作为参数传递到别的方法中,但是C或者是js都是可以的
在java中把只有一个方法的接口叫做函数接口,然后在利用lambda表达式,让接口的传递看起来像函数传递
为保证函数接口的规范,jdk1.8推出了一些规则
在接口上使用@FunctionalInterface,检查这个接口是不是函数接口
@FunctionalInterface
public interface MyInterface2 {
void accept();
}
为了方便使用jdk1.8自带了一些接口
Consumer<T>:定义一个抽象方法可以传值,但没有返回,消费接口
Supplier<T>:有返回没参数,只有返回结果,提供接口
Function<T,R>:有参数有返回结果,功能接口
Predicate<T>:可以传入参数,返回类型是boolean类型,断言接口
方法引用:
在lambda表达式基础上进一步简化
//使用lambda表达式输出
list.forEach(integer -> {
System.out.println(integer);
});
//使用方法引用进一步简化
list.forEach(System.out::println);
可以使用方法引用的条件
lambda表达式中只有一行代码
调用方法,和lambda传入的接口的方法的参数和返回保持一致
常用的简化形式
类::静态方法:一般用于静态方法
对象::实例方法:一般用于对象直接调用方法(传入的对象,被作为参数被省略的方法引用作为参数调用)
//使用lambda表达式输出
list.forEach(integer -> {
System.out.println(integer);
});
//使用方法引用进一步简化
list.forEach(System.out::println);
类::实例方法,这个实例方法是通过调用类代替对象调用的(调用传入对象的方法).
在类实现一个非static方法
public void say(){
System.out.println("我是"+this.getName()+",今年"+this.getAge());
}
在使用lambda表达式的时候使用传入的参数对象,调用say()方法
list.forEach(s->{
s.say();
});
在省略参数的时候,由于没有可以调用方法的媒介,可以直接使用类进行调用
list.forEach(Student::say);
类::new 对象
当返回结果是一个对象的时候,并且函数体时创建对象,那么可以使用方法引用省略
在调用的时候,构造返回的参数要和接口应用的参数保持一致
public static void main(String[] args) {
//匿名内部类的写法
wrap(new Supplier<String>() {
@Override
public String get() {
return new String();
}
});
//lambda表达式
wrap(()->{
return new String();
});
//进一步简化
wrap(()-> new String());
//使用引用简化
wrap(String::new);
}
public static void wrap(Supplier<String> supplier){
System.out.println("包装开始");
String result = supplier.get();
System.out.println("获取包装结果");
}
简化小结:
匿名内部类:
wrap("12", new Function<String, Object>() {
@Override
public Object apply(String s) {
return new Short(s);
}
});
匿名内部类,在实现接口的情况下,并且接口之后只有一个方法,那么就可以简化成lambda表达式
wrap("15", s -> {
return new Integer(s);
});
lambda表达式中,如果之后一行代码,那么{}可以省略,如果带返回值的话那么return也会省略
wrap("15", s -> new Integer(
如果调用一行代码,参数和返回与接口的抽象方法,保持一致,那么则可以使用方法引用
wrap("15",Integer::new);
Stream
流可以对集合进行筛选,快速获得想要的结果
如果没有流要么遍历多次,要么就要别的集合来进行辅助操作
public static void main2(String[] args) {
List<String> list = new ArrayList<>();
Collections.addAll(list, "张无忌", "周芷若", "赵敏", "张强", "张三丰");
// 需求:1.拿到所有姓张的 2.拿到名字长度为3个字的 3.打印这些数据
//获取所有姓张的
List<String> nameList = new ArrayList<>();
for (int i=0;i<list.size();i++){
String name = list.get(i);
if(name.contains("张")){
nameList.add(name);
}
}
//在原有的基础上再次进行遍历
List<String> lengthList = new ArrayList<>();
for (int i=0;i<nameList.size();i++){
String name = nameList.get(i);
if(name.length()==3){
lengthList.add(name);
}
}
//将结果打印
for (int i=0;i<lengthList.size();i++){
String name = lengthList.get(i);
System.out.println(name);
}
}
使用流简化操作
public static void main(String[] args) {
List<String> list = new ArrayList<>();
Collections.addAll(list, "张无忌", "周芷若", "赵敏", "张强", "张三丰");
// 需求:1.拿到所有姓张的 2.拿到名字长度为3个字的 3.打印这些数据
//获取流
Stream<String> stream = list.stream();
//过滤获取所有姓名张的
/*
stream
.filter(new Predicate<String>() {//过滤方法
@Override
public boolean test(String o) {
if(o.contains("张")){
return true;
}
return false;
}
}).filter(new Predicate<String>() {//筛选
@Override
public boolean test(String s) {
if(s.length()==3){
return true;
}
return false;
}
}) .forEach(s->{//终结遍历方法
System.out.println(s);
});*/
//过滤方法
//筛选
stream
.filter(o -> o.contains("张"))
.filter(s ->s.length()==3)
.forEach(System.out::println
);
}
流的特点:
Stream自己不会储存元素
Stream不会改变源对象.相反,它们会返回一个有结果的新Steam
Stream是延迟执行,会等到需要结果的时候执行
流的基本使用;
通过Collection对象的Stream()或parallelStream()方法
通过ArrayList类的stream()方法
通过Stream接口的of(),iterate(),generate()方法
//自动无限生产数据
Stream s2 = Stream.generate(new Supplier<Integer>() {
@Override
public Integer get() {
return new Random().nextInt(100);
}
});
s2.limit(5) //只获取5个数据
.forEach(i->{
System.out.println(i);
});
通过IntStream、LongStream、DoubleStream接口中的of、range、rangeClosed方法。
流的中间操作方法
filter:过滤器操作
limit:限制只有几个
skip:跳过元素
distinct:去掉重复,对象的话要重写equals方法
sorted:排序
s2.limit(10)
.sorted((o1, o2) -> o2-o1)
.forEach(i->{
System.out.println(i);
});
流的终极操作
foreach:循环
max:最大值
reduce:可以根据自定义规则计算数据
collect:将筛选出来的结果保存在新集合中