这部分会详细的写jdk1.8新特性,lambda表达式的使用以及stream流的使用。
@FunctionalInterface
public interface GreetAble {
void greet();
}
public class Human {
public void sayHello(){
System.out.println("hello");
}
}
public class Husband {
public void marry(RichAble richAble){
richAble.buy();
}
public void buyHouse(){
System.out.println("买套房子!");
}
public void beHappy(){
// marry(()-> System.out.println("买套房子"));
marry(this::buyHouse);
}
}
public class Man extends Human {
@Override
public void sayHello() {
System.out.println("大家好,我是Man!");
}
public void method(GreetAble greetAble){
greetAble.greet();
}
public void show(){
//method(()->new Human().sayHello());
//使用super代替父类对象
method(super::sayHello);
}
}
public class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person(){
}
public Person(String name) {
this.name = name;
}
@Override
public String toString() {
return this.getClass().getName()+"["+name+"]";
}
}
@FunctionalInterface
public interface RichAble {
void buy();
}
/**怎么编写lambda表达式?
* 1:看参数
* 2:看返回值
*
* 下面的是函数式接口:Object中的方法除外,static方法除外,default方法除外
* jdk1.8之前的一些函数式接口
* java.lang.Runnable
* java.util.concurrent.Callable
* java.util.Comparator
* 下面介绍几个常用的:都在java.util.function包下。
* Supplier:代表一个输出
* Consumer:代表一个输入
* Predicate:输入是T,输出是boolean
* BiConsumer:代表两个输入
* Function:代表一个输入和输出
* BiFunction:代表两个输入和一个输出。
* UnaryOperator:代表一个输入,一个输出,但是,输入和输出是相同类型。
* BinaryOperator:代表两个输入,一个输出,但是全都是相同类型。
* 其他的都与上面的类似,属于上面的基础上进行的扩展。
* @author 12706
*
*1、静态方法的引用
*2、实例方法的引用
*3、对象方法的引用
*4、构造方法的引用
*/
public class LambdaExpress {
/**
* lambda的使用
* 1、看参数
* 2、看返回值
*/
@Test
public void testLambda() throws Exception {
//1、无参无返回值,没有参数括号是不能省的,只有一句代码那么{}就可以省了
Runnable r = () -> System.out.println("hello world");
//2、无参有返回值,只有一句话那么return就可以省了
Callable c = () -> 5;
Supplier<String> supplier = () -> "world";
//3、有参无返回值
Consumer<String> consumer = s -> System.out.println(s+":world");
//4、有参有返回值
Function<String,Integer> function = s -> Integer.valueOf(s);
r.run();
System.out.println(c.call());
System.out.println(supplier.get());
consumer.accept("tom");
System.out.println(function.apply("101"));
}
@Test
public void testFunction() throws Exception {
/*
最基础的:Consumer,Supplier<>,Predicate返回boolean用来测试,比如filter的参数,Function
双重:BiConsumer两个输入,BiFunctionT,U表示输入,R表示输出
BiPredicate两个输入
UnaryOperator:代表一个输入,一个输出,但是,输入和输出是相同类型。继承Function
BinaryOperator:代表两个输入,一个输出,但是全都是相同类型。继承BiFunction
IntConsumer输入int,IntSupplier输入int,IntFunction输入int,IntPredict输入int
此外还有Doublexxx,Longxxx等,另外还有些感觉用不到的,看源代码即可。
比如ToLongFunction输入是T,输出是Long
*/
Predicate<String> predicate = str -> str.charAt(0)>'a';
BiConsumer<Integer,String> biConsumer = (num,str)->System.out.println(num+":"+str);
BiFunction<Integer,String,Integer> biFunction = (num,str)->Integer.valueOf(str)+num;
BiPredicate<Integer,Integer> biPredicate = (num1,num2)->num1>num2+3;
}
/*
通过对象名引用成员方法 实例方法的引用
使用前提是对象名是已经存在的,成员方法也是已经存在 实例对象的方法能满足函数式接口的实现
就可以使用对象名来引用成员方法
*/
public String pop(){
return "hello";
}
@Test
public void objMethodRefTest(){
Supplier<String> supplier = () -> {
LambdaExpress express = new LambdaExpress();
return express.pop();
};
//使用实例方法引用改造
//对象存在 express
//方法存在 pop
LambdaExpress express = new LambdaExpress();
Supplier<String> supplier2 = express::pop;
System.out.println(supplier.get());
System.out.println(supplier2.get());
}
/**
* 静态方法的引用
*/
@Test
public void staticMethodRefTest(){
Function<Integer,Integer> f1 = num1 -> Math.abs(num1);
//静态方法引用
//类存在 Math
//静态方法存在 abs
Function<Integer,Integer> f2 = Math::abs;
System.out.println(f1.apply(-10));
System.out.println(f2.apply(-10));
}
/**
* 构造方法的引用
*/
@Test
public void constructorMethodRefTest(){
Function<String,Person> f1 = name -> new Person(name);
Function<String,Person> f2 = Person::new;
System.out.println(f1.apply("tom"));
System.out.println(f2.apply("tom"));
}
/**
* 通过super引用成员方法
*/
@Test
public void superMethodRefTest(){
Man man = new Man();
man.show();
}
/**
* 通过this引用成员方法
*/
@Test
public void thisMethodRefTest(){
Husband husband = new Husband();
husband.buyHouse();
}
/**
* 数组的构造器引用
*/
@Test
public void arrayConsMethodRefTest(){
Function<Integer,int[]> f1 = int[]::new;
System.out.println(f1.apply(10).length);
}
/**
* 对象方法的引用
* 抽象方法的第一个参数刚好是实例的类型,后面的参数和实例方法的参数类型一致(即输入参数类型和返回类型一致)
* 类名::方法名, 和静态方法引用的写法一样
* 了解就好,前面两个是重点
* 注:要求函数一定要求有参数像Suppier就不行
* 真的很诡异
*
*/
public void sayHello(String name){
System.out.println("hello,我的名字叫:"+name);
}
@Test
public void abstractMethodRefTest(){
LambdaExpress express = new LambdaExpress();
BiConsumer<LambdaExpress,String> biConsumer = (l, name)->l.sayHello(name);
biConsumer.accept(express,"jinBingmin");
BiConsumer<LambdaExpress,String> biConsumer2 = LambdaExpress::sayHello;
biConsumer2.accept(express,"Jack");
}
}
/**
* 创建Stream
* @author 12706
*
*终止操作:
*循环:forEach
*计算:max,min,count,average
*匹配:anyMatch,allMatch,noneMatch,findFirst,findAny
*汇聚:reduce
*收集器:toArray,collect
*
*中间操作:
*过滤:filter
*去重 :distinct
*排序:sorted
*截取:limit,skip
*转换:map/flatMap
*其他:peek
*
*/
public class StreamTest {
/**
* 1、使用数组创建 int数组不行,泛型会是int[]
* stream.of(泛型数组)
*/
static void gen1(){
Integer[] arr = {1,2,3,4};
Stream<Integer> s = Stream.of(arr);
s.forEach(System.out::println);
}
/**
* 2、使用集合 collection.stream()
*/
static void gen2(){
Stream<Character> stream = Arrays.asList('a', 'b', 'c', 'd').stream();
stream.forEach(System.out::println);
}
/**
* 3、使用generate
*/
static void gen3(){//不限制10条则会一直打印2
Stream<Integer> stream = Stream.generate(() -> 2).limit(10);
stream.forEach(System.out::println);
}
/**
* 4、使用iterate
* * @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)
*
*/
static void gen4(){
Stream<Integer> stream = Stream.iterate(1, x -> x + 1).limit(10);
stream.forEach(System.out::println);
}
/**
* 5、其他api创建
* @throws IOException
*/
static void gen5() throws IOException {//打印97-101
String s = "abcde";
IntStream chars = s.chars();
chars.forEach(System.out::println);
//一行一行读取
Stream<String> lines = Files.lines(Paths.get("D:\\workspaces\\maven-test2\\src\\main\\resources\\hello.txt"));
lines.forEach(System.out::println);
}
public static void main(String[] args) throws IOException {
// StreamTest.gen5();
// *终止操作:
// *循环:forEach
// *计算:max,min,count,average
// *匹配:anyMatch,allMatch,noneMatch,findFirst,findAny
// *汇聚:reduce
// *收集器:toArray,collect
//先介绍下中间操作filter:具有延迟计算特性,必须终止才执行 打印偶数
Arrays.asList(1,2,3,4,5,6).stream().filter(x->x%2==0).forEach(System.out::println);
//偶数求和sum() 注:sum()是InteStream才有的函数,Stream是没有的所以要转mapToInt
int s = Arrays.asList(1, 2, 3, 4, 5, 6).stream().filter(x -> x % 2 == 0).mapToInt(x -> x).sum();
System.out.println(s);
//求偶数最小值(最大值也一样)
Optional<Integer> minVal = Arrays.asList(1, 2, 3, 4, 5, 6).stream().filter(x -> x % 2 == 0).min((a, b) -> a - b);
if(minVal.isPresent()) System.out.println(minVal.get());
//找出第一个满足条件的
Optional<Integer> fVal = Arrays.asList(1, 2, 3, 4, 5, 6).stream().filter(x -> x % 2 == 0).findFirst();//或者findAny
//从1-50里面的所有偶数找出来,放到一个list里面
List<Integer> list = Stream.iterate(1, x -> x + 1).limit(50).filter(x -> x % 2 == 0).collect(Collectors.toList());
// *中间操作:
// *过滤:filter
// *去重 :distinct
// *排序:sorted
// *截取:limit,skip
// *转换:map/flatMap
// *其他:peek
// */
//去重排序后找最小的
Optional<Integer> first = Arrays.asList(3, 2, 10, 8, 10, 4, 4).stream().distinct().sorted().findFirst();
//自定义排序
List<String> list1 = Arrays.asList("aaa", "abbdf", "a", "aa").stream().sorted((s1, s2) -> s1.length() - s2.length()).collect(Collectors.toList());
System.out.println(list1);
//去重distinct,或者使用toSet
List<Integer> list2 = Arrays.asList(1, 1, 2, 2, 3, 3, 4, 5).stream().distinct().collect(Collectors.toList());
Set<Integer> set = Arrays.asList(1, 1, 2, 2, 3, 3, 4, 5).stream().collect(Collectors.toSet());
//skip(10)表示忽略前十个,limit和skip可以用来做分页。
//skip(0),limit(10),表示取第一页,取10个.skip(10)表示第二页
List<Integer> list3 = Stream.iterate(1, x -> x + 1).limit(50).filter(x -> x % 2 == 0).skip(5).limit(5).collect(Collectors.toList());
//转换操作
//将字符串分割,依次转换成int,然后求和 map要求传入的是Function
/*
* IntStream mapToInt(ToIntFunction super T> mapper);
* 而ToIntFunction要求实现int applyAsInt(T value);即传入T,返回Integer
*/
String str = "11,22,33,44,55";
int sum = Stream.of(str.split(",")).map(Integer::valueOf).mapToInt(x -> x).sum();
System.out.println(sum);
//或者一步到位
Stream.of(str.split(",")).mapToInt(Integer::valueOf).sum();
//字符串转换为对象map
String str2 = "tomcat,nginx,apache,jetty";
Stream.of(str2.split(",")).map(Person::new).forEach(System.out::println);
//其他 类似于记个日志,把每个元素取出来做个操作
Stream.of(str2.split(",")).peek(System.out::println).map(Person::new).forEach(System.out::println);
}
}
public class StreamInAction {
static class Book{
private int id;
private String name;
private double price;
private String type;
private LocalDate date;
public Book(int id,String name,double price,String type,LocalDate localDate){
this.id = id;
this.name = name;
this.price = price;
this.type = type;
this.date = localDate;
}
@Override
public String toString() {
return this.getClass().getName()+"["+this.getId()+","+this.getName()+","+this.getPrice()+","+this.getType()+","+this.getDate()+"]";
}
public String getName() {
return name;
}
public int getId() {
return id;
}
public String getType() {
return type;
}
public double getPrice() {
return price;
}
public LocalDate getDate() {
return date;
}
}
private static final List<Book> BOOK_LIST = books();
private static List<Book> books() {
List<Book> books = new ArrayList<>();
books.add(new Book(1,"tomcat",50d,"服务器",LocalDate.parse("2014-05-17")));
books.add(new Book(2,"nginx",60d,"服务器",LocalDate.parse("2014-06-17")));
books.add(new Book(3,"java",70d,"编程语言",LocalDate.parse("2013-03-17")));
books.add(new Book(4,"ruby",50d,"编程语言",LocalDate.parse("2014-05-27")));
books.add(new Book(5,"hadoop",80d,"其它",LocalDate.parse("2015-11-17")));
books.add(new Book(6,"spark",45d,"其它",LocalDate.parse("2012-03-17")));
books.add(new Book(7,"storm",55d,"其它",LocalDate.parse("2014-10-17")));
books.add(new Book(8,"kafka",60d,"其它",LocalDate.parse("2016-03-14")));
books.add(new Book(9,"lucene",70d,"其它",LocalDate.parse("2012-05-17")));
books.add(new Book(10,"solr",35d,"其它",LocalDate.parse("2013-05-17")));
books.add(new Book(11,"jetty",90d,"服务器",LocalDate.parse("2014-05-17")));
books.add(new Book(12,"设计模式",60d,"其它",LocalDate.parse("2015-05-17")));
books.add(new Book(13,"数据结构",70d,"其它",LocalDate.parse("2011-05-17")));
books.add(new Book(14,"敏捷开发",50d,"其它",LocalDate.parse("2010-05-17")));
books.add(new Book(15,"算法导论",20d,"其它",LocalDate.parse("1999-05-17")));
books.add(new Book(16,"算法导论",90d,"其它",LocalDate.parse("2017-05-17")));
return books;
}
@Test
public void t1(){
BOOK_LIST.stream().forEach(x-> System.out.println(x.getName()));
}
//ip地址中的参数转换为map index.do?itemId = 1 & userId = 19202 & token = 1111
@Test
public void t2(){
String queryStr = "itemId = 1 & userId = 19202 & token = 1111";
List<String[]> list = Arrays.asList(queryStr.split("&")).stream().map(x -> x.split("=")).collect(Collectors.toList());
list.forEach(x->{
System.out.println(Arrays.toString(x));
});
}
@Test
public void t3(){
String queryStr = "itemId = 1 & userId = 19202 & token = 1111";
Map<String, String> map = Arrays.asList(queryStr.split("&")).stream().map(x -> x.split("=")).collect(Collectors.toMap(x -> x[0], x -> x[1]));
System.out.println(map);
}
//非常常见
@Test
public void t4(){
//把所有书的id取出来放到list中
List<Integer> list = BOOK_LIST.stream().map(x -> x.getId()).collect(Collectors.toList());
System.out.println(list);//[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
//转换成(1,2,3,4,5)这种形式 这种形式必须转为string
String s = BOOK_LIST.stream().map(x -> x.getId() + "").collect(Collectors.joining(",", "(", ")"));
System.out.println(s);
}
@Test
public void t5(){
//类型全部取出来并且去重 distinct或者set
List<String> list = BOOK_LIST.stream().map(x -> x.getType()).distinct().collect(Collectors.toList());
System.out.println(list);
}
@Test
public void t6(){
//价格由高到低排序
List<Book> list = BOOK_LIST.stream().sorted((a, b) -> (int) (b.getPrice() - a.getPrice())).collect(Collectors.toList());
list.forEach(x-> System.out.println(x.getPrice()));
System.out.println("=========================");
/** LocalDate a = LocalDate.of(2012, 6, 30);源码这样解释的
* LocalDate b = LocalDate.of(2012, 7, 1);
* a.isAfter(b) == false
* a.isAfter(a) == false
* b.isAfter(a) == true*/
//价格相同的由时间由近到远排
// Compares its two arguments for order. Returns a negative integer, zero, or
// a positive integer as the first argument is less than, equal to, or greater
// than the second. compare(a,b)方法 也就是说如果是-1就表示前面的比较小,他要排到前面
Comparator<Book> comparator = (a,b)->(int)(b.getPrice()-a.getPrice());
/*
可以这样来看:a.date在b.date后面的时候返回-1,说明此时a排在了b前面,再回来看
a.date此时是after b.date的,说明时间近的a排在了时间远的b前面 符合
*/
List<Book> list1 = BOOK_LIST.stream().sorted(comparator.thenComparing((a, b) -> a.getDate().isAfter(b.getDate()) ? -1 : 1)).collect(Collectors.toList());
list1.forEach(x->{
System.out.println(x.getPrice()+":"+x.getDate());
});
System.out.println("=================================");
//使用Comparator(comparing要求传入的是Function,代表被排序的类型和按照上面排序,但是它判断不出来传入的类型)
List<Book> list2 = BOOK_LIST.stream().sorted(Comparator.comparing((Book b) -> b.getPrice()).reversed().thenComparing((Book b) -> b.getDate())).collect(Collectors.toList());
list1.forEach(x->{
System.out.println(x.getPrice()+":"+x.getDate());
});
}
@Test
public void t7(){
//转为map,key为数的id
Map<Integer, Double> map = BOOK_LIST.stream().collect(Collectors.toMap(x -> x.getId(), x -> x.getPrice()));
System.out.println(map);
}
@Test
public void t8(){
//求平均价格
OptionalDouble average = BOOK_LIST.stream().map(x -> x.getPrice()).mapToDouble(x -> x).average();
if(average.isPresent()) System.out.println(average.orElseGet(()->0.0));
Double price = BOOK_LIST.stream().collect(Collectors.averagingDouble(x -> x.getPrice()));
System.out.println(price);
}
@Test
public void t9(){
//找最大最小
Optional<Book> book = BOOK_LIST.stream().collect(Collectors.maxBy(Comparator.comparing((Book x) -> x.getPrice())));
Optional<Book> book1 = BOOK_LIST.stream().collect(Collectors.minBy(Comparator.comparing((Book x) -> x.getPrice())));
System.out.println(book.get().getPrice()+":"+book1.get().getPrice());
//时间最早的
Optional<Book> book2 = BOOK_LIST.stream().collect(Collectors.maxBy(Comparator.comparing((Book x) -> x.getDate())));
System.out.println(book2.get().getDate());
//最贵的,时间是最早的
Comparator<Book> comparator1 = Comparator.comparing((Book x)->x.getPrice());
Comparator<Book> comparator2 = Comparator.comparing((Book x) -> x.getDate()).reversed();
Optional<Book> book3 = BOOK_LIST.stream().collect(Collectors.maxBy(comparator1.thenComparing(comparator2)));
System.out.println(book3.get().getDate()+":"+book3.get().getPrice());
}
@Test//分组
public void t10(){
//按照类别分组 对象方法的引用在这里使用到了
Map<String, List<Book>> map = BOOK_LIST.stream().collect(Collectors.groupingBy(Book::getType));
map.entrySet().forEach(x->{
System.out.println(x.getKey()+":"+x.getValue());
});
//分组后计算数量 第二个参数也是传入一个Collectors
Map<String, Long> map1 = BOOK_LIST.stream().collect(Collectors.groupingBy(x -> x.getType(), Collectors.counting()));
map1.entrySet().forEach(x->{
System.out.println(x.getKey()+":"+x.getValue());
});
//分组后计算价格 对象方法引用看来还是有用的
Map<String, Double> map2 = BOOK_LIST.stream().collect(Collectors.groupingBy(Book::getType, Collectors.summingDouble(Book::getPrice)));
map2.entrySet().forEach(x->{
System.out.println(x.getKey()+":"+x.getValue());
});
//分组和计算平均
Map<String, Double> map3 = BOOK_LIST.stream().collect(Collectors.groupingBy(Book::getType, Collectors.averagingDouble(Book::getPrice)));
map2.entrySet().forEach(x->{
System.out.println(x.getKey()+":"+x.getValue());
});
//分组后最贵的那本
Map<String, Optional<Book>> map4 = BOOK_LIST.stream().collect(Collectors.groupingBy(Book::getType, Collectors.maxBy(Comparator.comparing((Book x) -> x.getPrice()))));
map4.entrySet().forEach(x->{
System.out.println(x.getKey()+":"+x.getValue().get());
});
//分组后最晚出售的
Map<String, Optional<Book>> map5 = BOOK_LIST.stream().collect(Collectors.groupingBy(Book::getType, Collectors.maxBy(Comparator.comparing((Book x) -> x.getDate()))));
map5.entrySet().forEach(x->{
System.out.println(x.getKey()+":"+x.getValue().get());
});
}
@Test//价格大于80,日期由近到远
public void t11(){
List<Book> list = BOOK_LIST.stream().filter(x -> x.getPrice() >= 80).sorted(Comparator.comparing((Book x) -> x.getDate()).reversed()).collect(Collectors.toList());
list.forEach(System.out::println);
}
}