一、函数式编程思想和Lambda表达式定义格式
面向对象思想:是Java的核心编程思想
强调的是找对象,帮我们做事儿
比如->去北京->强调的是怎么去,火车,高铁,飞机,汽车,自行车,腿儿
jdk8开始又了个新的思想:函数式编程思想
强调的是结果,不强调过程
比如:去北京->只强调去了还是没去
Lambda表达式:
定义格式:()->{}
各部分解释:():重写方法的参数位置
->:将参数传递到方法体中
{}:重写方法的方法体
public class Demo01Lambda {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("我执行了");
}
}).start();
System.out.println("=========");
//lambda表达式
new Thread(()-> { System.out.println("我执行了"); }).start();
}
}
Lambda表达式使用前提
- 必须是函数式接口做方法传递
- 啥叫函数式接口:
有且只有一个抽象方法的接口,用@FunctionInterface去检测
Lambda表达式省略规则
怎么写?
- 观察是否是函数式接口做方法参数传递
- 如果是,考虑使用Lambda表达式
- 调用方法,以匿名内部类的形式传递实参
- 从new接口开始到重写方法的方法名结束,选中,删除,别忘记在删除一个右半个大括号
- 在重写方法的参数后面,方法体的大括号前面加上 ->
省略规则:
重写方法的参数类型可以干掉
如果重写方法只有一个参数,所在的小括号可以干掉
如果方法体中只有一句话,那么所在的大括号以及分号部分可以干掉
如果方法体中只有一句话并且带return的,那么所在的大括号分号以及return可以干掉
/*
1.观察是否是函数式接口做方法参数传递
2.如果是,考虑使用Lambda表达式
3.调用方法,以匿名内部类的形式传递实参
4.从new接口开始到重写方法的方法名结束,选中,删除,别忘记在删除一个右半个大括号
5.在重写方法的参数后面,方法体的大括号前面加上 ->*/
public class Demo02Lambda {
public static void main(String[] args) {
method(new USB() {
@Override
public void open() {
System.out.println("让usb打开了");
}
});
System.out.println("==========lambda表达式===========");
method(() ->{ System.out.println("让usb打开了"); });
method(() ->System.out.println("让usb打开了"));
}
/*
*
*
*
* @param usb
* */
private static void method(USB usb) {
usb.open();
}
}
@FunctionalInterface
public interface USB {
void open();
}
public class Person {
private String name;
private Integer age;
public Person() {
}
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class Demo03Lambda {
public static void main(String[] args) {
ArrayList<Person> list = new ArrayList<>();
list.add(new Person("张三",10));
list.add(new Person("李四",9));
list.add(new Person("王五",8));
Collections.sort(list, new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return o1.getAge()-o2.getAge();
}
});
System.out.println("======================Lambda==============");
Collections.sort(list, (Person o1, Person o2) ->{ return o1.getAge()-o2.getAge(); });
System.out.println("======================Lambda简化==============");
Collections.sort(list, ( o1, o2) -> o1.getAge()-o2.getAge());
System.out.println(list);
}
}
二、函数式接口
函数式接口:有且只有一个抽象方法的接口
检测:@FunctionalInterface
@FunctionalInterface
public interface USB {
void open(String s);
}
public class Test01 {
public static void main(String[] args) {
method(new USB() {
@Override
public void open(String s) {
System.out.println(s+"开启了");
}
});
System.out.println("===========Lambda======");
method((String s)-> {
System.out.println(s+"开启了");
});
System.out.println("===========Lambda======");
method(s-> System.out.println(s+"开启了"));
}
public static void method(USB usb){
usb.open("鼠标");
}
}
1.Supplier接口
java.util.function.Supplier<T>接口,它意味着“供给”->我们想要什么就给什么
方法:
T get()->我们想要什么,get方法就可以返回什么
需求:使用Supplier接口作为方法的参数
用Lambda表达式求出int数组中的最大值
泛型:<引用数据类型>->规定了我们操作的数据是什么类型
<>最终只能写引用数据类型,不能写基本数据类型
import java.util.Arrays;
import java.util.function.Supplier;
public class Demo01Supplier {
public static void main(String[] args) {
method(new Supplier<Integer>() {
@Override
public Integer get() {
int[] arr={4,3,4,6,7};
Arrays.sort(arr);
return arr[arr.length-1];
}
});
System.out.println("====================");
method(() ->{
int[] arr={4,3,4,6,7};
Arrays.sort(arr);
return arr[arr.length-1];
});
}
public static void method(Supplier<Integer> supplier){
Integer max=supplier.get();//让get方法返回一个数组最大值
System.out.println("max="+max);
}
}
2.Consumer
java.util.function.Consumer<T>->消费型接口->操作
方法:void accept(T t)意为消费一个指定泛型的数据
“消费”就是“操作”,至于怎么操作,就看重写accept方法之后,方法体怎么写了
import java.util.function.Consumer;
public class Demo02Consumer {
public static void main(String[] args) {
method(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s.length());
}
},"abcdefg");
System.out.println("================");
method(s-> System.out.println(s.length()),"abcdefg");
}
public static void method(Consumer<String> consumer,String s){
consumer.accept(s);
}
}
3.Function
java.util.function.Function<T,R>接口用来根据一个类型的数据得到另一个类型的数据
方法:
R apply(T t)根据类型T参数获取类型R的结果
import java.util.function.Function;
public class Demo03Function {
public static void main(String[] args) {
method(new Function<Integer, String>() {
@Override
public String apply(Integer integer) {
return integer+"";
}
},100);
System.out.println("=============");
method(integer-> integer+"",100);
}
public static void method(Function<Integer,String> function,Integer number){
String s=function.apply(number);
System.out.println("s="+(s+1));
}
}
4.Predicate
java.util.function.Predicate<T>接口->判断型接口
boolean test(T t)->用于判断的方法,返回值为boolean型
import java.util.function.Predicate;
public class Demo04Predicate {
public static void main(String[] args) {
method(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.length()==7;
}
},"abcdefg");
System.out.println("============");
method(s->s.length()==7,"abcdefg");
}
public static void method(Predicate<String> predicate,String s){
boolean test=predicate.test(s);
System.out.println("test="+test);
}
}
三、Stream流
Stream流中的“流”不是特指“IO流”它是一种“流式编程”(编程方式),可以看做是“流水线”
1.Stream的获取
针对集合:Collection中的方法
Stream<E> stream()
针对数组:Stream接口中的静态方法
static<T> Stream<T> of(T.....values)
import java.util.ArrayList;
import java.util.stream.Stream;
public class Demo01Stream {
public static void main(String[] args) {
//针对集合:collection中的方法
ArrayList<String> list = new ArrayList<>();
list.add("张三");
list.add("李四");
list.add("王五");
Stream<String> stream = list.stream();
System.out.println(stream);
//针对数组String接口中的静态方法
Stream<String> stream1=Stream.of("武松","李青","李逵");
System.out.println(stream1);
}
}
2.Stream的方法
(1)Stream中的forEach方法:void forEach(Consumer<? super T>action)
forEach:逐一处理->遍历
void ForEach(Consumer<? super T>action)
注意:forEach方法是一个终结2方法,使用完之后,Stream流不能使用了
(2)Stream中的long count()方法
作用:统计元素个数
注意:count也是一个终结方法
(3)Stream中的long count()方法
作用:统计元素个数
注意:count也是一个终结方法
(4)Stream中的Stream<T> filter(Predicate<? super T>predicate)方法
方法:Stream中的Stream<T> filter(Predicate<? super T>predicate)方法,返回一个新的Stream流对象
作用:根据某个条件进行元素过滤
(5)Stream<T> limit(long maxSize):获取Stream流对象按那个中的前n个元素返回一个新的Stream流对象
Stream<T> limit(long maxSize):获取Stream流对象按那个中的前n个元素返回一个新的Stream流对象
(6)Stream<T> slip(long n):跳过Stream流对象中的前n个元素,返回一个新的Stream流对象
Stream<T> slip(long n):跳过Stream流对象中的前n个元素,返回一个新的Stream流对象
(7)static<T> Stream<T> concat(Stream<? extends T>a,Stream<? extend T>b):两个流合成一个流
static<T> Stream<T> concat(Stream<? extends T>a,Stream<? extend T>b):两个流合成一个流
import java.util.function.Consumer;
import java.util.stream.Stream;
public class Demo02Stream {
public static void main(String[] args) {
//foreach();
// count();
// filter();
// limit();
// slip();
concat();
}
private static void concat(){
Stream<String> stream1=Stream.of("武松","李青","李逵","诸葛");
Stream<String> stream2=Stream.of("武","李","李","诸");
Stream.concat(stream1,stream2).forEach(s -> System.out.println(s));
}
private static void slip() {
Stream<String> stream1=Stream.of("武松","李青","李逵","诸葛");
stream1.skip(2).forEach(s -> System.out.println(s));
}
private static void limit() {
Stream<String> stream1=Stream.of("武松","李青","李逵","诸葛");
stream1.limit(3).forEach(s -> System.out.println(s));
}
private static void filter() {
Stream<String> stream1=Stream.of("武松","李青","李逵","诸葛");
/*stream1.filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.length()==2;
}
}).forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});*/
System.out.println("==============");
stream1.filter(s -> s.length()==2).forEach(s -> System.out.println(s));
/*newStream.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
*/
}
/*
*
*
* 统计元素个数
*
* */
private static void count() {
Stream<String> stream1=Stream.of("武松","李青","李逵");
long count=stream1.count();
System.out.println("count="+count);
}
/*
* 逐一处理,可以用来遍历
*
* */
private static void foreach() {
Stream<String> stream1=Stream.of("武松","李青","李逵");
stream1.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
System.out.println("=================");
stream1.forEach( s-> System.out.println(s));
}
}
四、方法引用
1.方法引用介绍
概述:引用方法
啥时候使用:
被引用的方法要写在重写方法里面
被引用的方法从参数上,返回值上要和所在的重写方法一致,而且引用的方法最好是操作重写方法的参数值的
干掉重写方法的参数;干掉->;干掉被引用方法的参数->将被饮用方法的.改成::
import java.util.function.Consumer;
import java.util.stream.Stream;
public class Demo01Method {
public static void main(String[] args) {
Stream<String> stream = Stream.of("今天", "明天", "后天");
/*
* accept是重写方法:参数类型string 无返回值
*
* accept方法里面有println方法:println参数类型位String被引用的方法操作重写方参数值println没有返回值
*
* */
/*stream.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
*/
System.out.println("==================");
// stream.forEach( s-> System.out.println(s));
System.out.println("==================");
stream.forEach( System.out::println);
}
}
2.对象名-引用成员方法
使用对象名引用成员方法
格式:
对象::成员方法名
需求:
函数式接口:Supplier
java.util.function.Supplier<T>接口
抽象方法:
T get()用来获取一个泛型参数指定类型的对象数据
Supplier接口使用什么泛型,就可以使用get方法获取一个什么类型的数据
import java.util.function.Supplier;
public class Demo02Method {
public static void main(String[] args) {
/*
*
* get为重写方法无参的返回值位string
* trim方法在get中无参的返回值为string
* 考虑使用方法引用
*
* */
method(new Supplier<String>() {
@Override
public String get() {
return " abc ".trim();
}
});
System.out.println("=============");
method(()->" abc ".trim());
System.out.println("====================");
method(" abc "::trim);
}
public static void method(Supplier<String> supplier){
String s=supplier.get();
System.out.println("s="+s);
}
}
3.类名-引用静态方法
类名-引用静态方法
格式:
类名::静态成员方法
4.类-构造引用
类-构造方法引用
格式:
构造方法名称::new
5.数组-数组引用
数组-数组引用
格式:
数组中的数据类型[]::new
int[]::new 创建一个int型的数组
double[]::new 创建于一个double型的数据