一、说点废话?
Java是面向对象编程,调用一个函数必须通过对象,函数不能独立存在,不能作为参数不能作为返回值。
二、函数式编程?
Java8引入了函数编程,函数可以作为一等公民,可以独立存在,可以作为参数。
三、Lambda?
java8编译支持Lambda风格,Lambda是一种匿名函数,函数编程的一种实现方式,形式如下:
入参 -> 表达式 // x -> x == 1;
四、Java8提供的几种函数?
1、Function<T,R> 有输入有输出
/**
* Applies this function to the given argument.
*
* @param t the function argument
* @return the function result
*/
R apply(T t);
//入参 -> 表达式
//lambda imple apply of Function<T, R>
Function<Integer, Integer> functionAddByLambda = x -> x + 10;
System.out.println(functionAddByLambda.apply(10));//20
//common way 匿名内部类类似Runnable interface
Function<Integer, Integer> functionAddCommon = new Function<Integer, Integer>() {
@Override
public Integer apply(Integer integer) {
return integer + 10;
}
};
System.out.println(functionAddCommon.apply(10));//20
lambda要比common way 方式更简洁
2、Consumer 只有输入,没有输出即消费
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
// accept method of consumer
Consumer<Integer> consumer = x -> System.out.println(x);
consumer.accept(1);
3、Supplier 没有输入,只有输出,get a result
/**
* Gets a result.
*
* @return a result
*/
T get();
// get method for supplier
Supplier<Integer> supplier = () -> 1;
Integer result = supplier.get();
System.out.println(result);//1
4、Predicate 对输入参数校验,return true or false
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);
//test method of predicate
Predicate<String> predicate = x -> x != null;
boolean a = predicate.test("a");//true
System.out.println(a);
六、Stream?
1、为啥要有Stream?
Stream 流是增强对集合的操作,支持并行和串行,能够充分利用多核处理器的优势,支持各种聚合操作,同时借助Lambda表达式,使得对集合的遍历处理效率更高更简洁。
2、什么是Stream
传统的Iterator,如果需要对数据做聚合操作,需要一个一个遍历并且写相关过滤筛选逻辑,Stream流不是集合,不是数据结构也不存储元素,是高级版本的Iterator,使用者只需要指定操作即可,Stream会在内部遍历,不存储元素意思不像Iterator那样可以获取元素,流不能获取元素,流不能够复用,比如:
//stream has already been operated upon or closed exception
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6);
Stream<Integer> numStream = nums.stream().filter(x -> x <= 4);
numStream.forEach(x -> System.out.println(x));
numStream.forEach(x -> System.out.println(x));
3、流的执行过程
(1)、流的执行流程
根据流(Stream)获取一个数据源(Source)->数据转换->执行Terminal操作获取最终结果,每一次转换都会返回一个新的流,整个流程就像一个管道一样。
(2)、流的操作
Intermedate(转换操作):一个流可以后面跟随零个或多个 intermediate 操作,然后返回一个新的流,交给下一个操作使用。这类操作都是惰性化的(lazy),就是说,仅仅表示声明这类方法,并没有真正执行流的遍历。
Terminal(终止操作):一个流只能有一个 terminal 操作,当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。Terminal 操作的执行,才会真正开始流的遍历,并且会生成一个结果。
3、流的使用
(1)、获取流
// 1. 指定 values
Stream stream = Stream.of(1, 2,3);
// 2. 数组
Integer [] array = new Integer[]{1, 2, 3};
stream = Stream.of(array);
stream = Arrays.stream(array);
// 3. 集合
List<Integer> list = Arrays.asList(array);
stream = list.stream();
需要注意的是,对于基本数值型,目前有三种对应的包装类型 Stream:
IntStream、LongStream、DoubleStream。当然我们也可以用 Stream<Integer>、Stream<Long> >、Stream<Double>,但是 装箱和 拆箱会影响效率,所以特别为这三种基本数值型提供了对应的 Stream。
(2)常见的Intermedate操作
map、flatMap、 filter、 distinct、 sorted、 limit、 skip、
(3)常见的Terminal操作
forEach、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、
// map操作 转换大写
List<String> wordList = Arrays.asList("a","b","c");
List<String> wordUpperList = wordList.stream().map(String::toUpperCase).collect(Collectors.toList());
wordUpperList.forEach( x -> System.out.println(x));
//map操作 平方运算
List<Integer> nums = Arrays.asList(1,2,3);
nums.stream().map(x -> x*x).collect(Collectors.toList());
//filter 取出小于3的数据并输出
List<Integer> toFilterNums = Arrays.asList(1, 2, 3, 4, 5);
Integer[] filterNums = toFilterNums.stream().filter(x -> x < 3).toArray(Integer[]::new);
Arrays.stream(filterNums).forEach(x -> System.out.println(x));
//limit skip 分页操作
List<Integer> results = toFilterNums .stream().skip(pageSize*(pageNum-1)).limit(pageSize).collect(Collectors.toList());
4、流的操作还有很多,后面补齐demo..