stream问题清单
获取集合中对象某个属性的最大值的那条记录
CallLogInfo callLogInfo = infos.stream().max((obj1, obj2) -> obj1.duration > obj2.duration ? 1 : -1).get();
根据对象的某些属性去重
- 对象是pojo(可采取treeset去重)
- 对象是map
//PageData是自定义的map的子类
public List<PageData> getAllGoods() {
List<PageData> pageDataList = goodsDao.selectAllGoods();
//使用map去重
List<PageData> unique2 = pageDataList.stream()
.filter(distinctByKey(o -> o.get("id")))
.collect(Collectors.toList());
// System.out.println(unique2);
return unique2;
}
public static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) {
Map<Object, Boolean> seen = new ConcurrentHashMap<>();
//System.out.println("这个函数将应用到每一个item");
return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}
将对象列表List< Object >转Map
视频学习
函数式编程(lambda表达式)
- 不使用lambda表达式的代码:
Comparator<Integer>com=new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
/**
* 相等返回0,o1大返回1,o1小返回-1,默认是降序排列
* 也可写成 Integer.compare(o1,o2);
*/
return o1-o2;
}
};
TreeSet<Integer> treeSet=new TreeSet<>(com); //treeset是一个有序集合(com是定义排序的规则)
使用之后
TreeSet<Integer> ltreeSet=new TreeSet<>((x,y)->y-x);
函数编程的写法
无参的
@FunctionalInterface
public interface FunInteface {
/**
Consumer<T>: 消费型接口,接收数据并处理【无返回值】
*/
void test(); //使用时:
/**
Predicate<T>: 断言型接口,检测入参是否符合条件(符合则返回true)【返回类型为boolean】
*/
boolean test(int a,T t); //(x,y)-> x>y;
}
/**
Function<T, R>: 函数型接口,接收参数,返回结果【有返回类型】
*/
int test(int a,T t); //FunInteface<Integer> ft=(x,y)-> x-y; int res= ft.test(1,5);
/**
Supplier<T>: 供给型接口,对外提供数据【给什么就返回什么】
*/
T test(int a,T t); // FunInteface<Integer> ft=(x,y)-> x-y; int res= ft.test(1,5);
//------------------------------------
@Test
public void test5Fun(){
FunInteface ft=()-> System.out.println("无参");
ft.test();
}
多参的,多语句的
@FunctionalInterface
public interface FunInteface<T> {
void test(int a,T t);
}
@Test
public void test5Fun(){
FunInteface<Integer> ft=(x,y)-> {Integer b=x-y;System.out.println(b);};
ft.test(1,5);
}
四大核心函数接口的用法如下:
/**
* @author gc
* 方法引用:若lambda体中的内容有方法已经实现了,我们可以使用“方法引用”
* (可以理解为方法引用是lambda表达式的另外一种表达形式)
* 主要有三种语法格式:
* 对象::实例方法名
* 类::静态方法名
* 类::实例方法名
* 注意:
* 1.lambda体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的参数列表和返回值类型一致
* 2.若lambda参数列表 中的第一个参数是实例方法的调用者,而第二个参数是实例方法的参数时,可以使用className::method
*
* 二、构造器引用
* 格式:
* ClassName::new
Function<String,Employee> fun=Employee::new; //构造方法的参数最多1个
BiFunction<String,Integer,Employee> funm=Employee::new; //构造方法的参数最多2个
*/
public class TestMethodRef {
//--------消费类型的
//对象::实例方法名
@Test
public void test() {
Consumer<String> consuemr = (x) -> System.out.println(x);
consuemr.accept("aaaa");
PrintStream ps = System.out;
Consumer<String> consumer2 = ps::println;
consumer2.accept("asdf");
}
//-----供应者类型
@Test
public void test2() {
User user= new User("gc",20,200000);
//这里是无参,所以左边使用了()
Supplier<String> sup = () -> user.getName();
System.out.println(sup.get());
//这里对lambda表达式进行了省略。() -> user.getAge() == user::getAge
Supplier<Integer> sup2 = user::getAge;
System.out.println(sup2.get());
}
//-----函数类型
//类::静态方法名
public void test3() {
Comparator<Integer> com = (x,y) -> Integer.compare(x, y);
//这里因为入参和lambda实现方法要调用的入参一样。所以两边都省略了
Comparator<Integer> com1 = Integer::compare;
}
//------断言类型
//类::实例方法名
public void test4() {
BiPredicate<String, String> bp = (x,y) -> x.equals(y);
//这里是两个入参,而且满足第一个参数是新方法调用者,第二个参数是入参的情况
//理论而言都用上面的表达式即可,看起来比较简单,但是不能避免别人不会使用简写方式,看不懂岂不是很尴尬
BiPredicate<String, String> bp2 = String::equals;
}
@Test
public void test5() {
//函数式接口生产数据的方式是new User();
Supplier<User> sup = () -> new User();
//这里功能同上,简写方式
Supplier<User> sup2 = User::new; //----方法引用:注意由于是Supplier所以参数类型和返回类型要一致
System.out.println(sup2.get());
}
}
stream api
List<Employee> list = Arrays.asList(new Employee("张三", 18, 1200), new Employee("李四", 20, 1300), new Employee("王五", 16, 800));
//获取工资大于500的前两名员工的姓名
list.stream().filter(x -> x.getSalary() > 500).limit(2).map(Employee::getName).forEach(System.out::println);
//map(里面是一个函数式接口:遍历List<Employee> list---new arraylist<String>().add(调用Employee.getName方法拿到名字))---------》将集合中对象的方法应用到每个元素上
中间操作
归约最后得到的是一个计算结果,而非集合/hash,收集返回的才是一个集合/hash
String sentence="to be or not to be,that is a question";
String[] wordList = sentence.split("[\\s|,]");
String reduce = Arrays.stream(wordList).reduce("", (x, y) -> x +" "+y);
System.out.println(reduce); //打印结果: to be or not to be that is a question
map+reduce模式【映射+归约】----大数据和云计算的实现----实现累加
【假如add和addAll都传入一个List】add(Object obj)整个集合添加到当前集合(即map()整个集合放入流中),addAll(Collection coll)集合中的每个元素添加到当前集合(即(flatMap()集合里面的每个元素放入流中))
map映射的用法
排序
查找和匹配
最大值最小值和统计
Optional<Employee>op=employeeList.stream().filter().findFirst() 里面有op.orElse(other);机制,类似if(obj==null){} else{obj.getName;}来防止为空
收集流式运算的结果
使用练习
番外篇
fork/join框架使用案例
class ForkJoinCalulate extends RecursiveTask<Long>{
@Override
protected Long compute() {
return null;
}
}
其他特性
接口中的默认实现方法和静态方法
日期操作
给人读的
给计算机读的
计算时间的间隔
时间校正器【获得下周的时间,每年的第一天】
时间格式化
@Test
void time(){
//DateTimeFormatter isoDateTime = DateTimeFormatter.ISO_DATE_TIME;//默认的----2020-04-30T11:33:32.607
DateTimeFormatter isoDateTime = DateTimeFormatter.ISO_DATE;//默认的----2020-04-30
/**
* 2020年04月30日: 11:37:34
* ldt.parse(fm2,df2) -- 2020-04-30T11:39:27
* Set<String> availableZoneIds = ZoneId.getAvailableZoneIds(); //获得所有支持的时区
*/
DateTimeFormatter df2 = DateTimeFormatter.ofPattern("yyyy年MM月dd日: HH:mm:ss");
LocalDateTime ldt = LocalDateTime.now();
String fm2 = ldt.format(df2);
}
带时区的操作