Lambda大法全解

含义:Lambda表达式,其实是一段可传递的代码。它的本质是以类的身份,干方法的活。
本质:Lambda表达式 = 形参列表 + 方法体
函数式接口:核心特征 -> 有且只有一个抽象方法(@FunctionalInterface检测,可不写)。Java8的接口可以添加静态方法和默认方法。
闭包:定义在一个函数内部的函数。是连接内部函数与外部函数的桥梁,通过闭包机制,内部函数可以访问外部函数的变量。

java.util.stream.Collectors	
--------------------------------------------------------------------------------
参考文献:https://www.cnblogs.com/yuanbing1226/p/9005476.html	
         https://www.cnblogs.com/yuanbing1226/p/8948055.html
本质:lambda本质就是一个匿名函数
Ps:在不会写函数式接口形参时,使用new内部类的方式实现,然后通过IDEA提示优化成最简Lambda表达式
                   
Lambda表达式的类型(函数接口类型)
--------------------------------------------------------------------------------
接口					参数			返回类型			描述
--------------------------------------------------------------------------------
Function<T, R>		T			R				(映射型接口)将一个对象转换为另一个对象。比如说要装箱或者拆箱某个对象。user -> user.getAge()
Person::getName
Consumer<T>			T			void				(消费型接口)用于接收一个对象进行处理但没有返回。x -> System.out.println(x)
BiConsumer<S, T> 	(S, T)		void				(消费者)用于接收两个对象进行处理但没有返回,accept(t, r),可以在实现做环绕处理
Supplier<T>			None		T				(供给型接口)提供一个对象,get(),可以在实现逻辑前添加mock响应,() -> {return 1+2;}
Predicate<T>			T			boolean			(断定型接口)用于判别一个对象。user -> user.getAge()>18
UnaryOperator<T>		T			T				(一元型接口)接收对象并返回同类型的对象。一般用于对对象修改属性
BinaryOperator<T>		(T, T)		T				(二元型接口)接收两个同类型的对象,并返回一个原类型对象。合并对象
Runnable                        void                 void
原线程接口,也可当作普通功能性函数,无参数

Iterable<? extends T> elements						迭代器,数组、集合的父接口
Collector<? super T, A, R> collector					收集器,集合转换
Collectors.joining("\r\n")					//回车换行符连接成字符串
Collectors.toList()					//收集成list
Collectors.toSet()						//收集成set
Collectors.toMap(Person::getName, person -> person)	//收集成map
Collectors.toMap(Person::getName, Function.identity())	//Function.identity()即为 v -> v
Collectors.toMap(Person::getName, person -> person, (preKey, nextKey) -> preKey)	//解决map的key冲突,指定保留的key
Collectors.counting()					//计数
Collectors.maxBy((p1, p2) -> p1.getAge() - p2.getAge())	//比较大小
Collectors.groupingBy(Person::getAddress)			//分组,map<string, list>
Collectors.groupingBy(Person::getAddress, Collectors.groupingBy(Person::getAge))	//嵌套分组,map<string, map<int,list>>>
Collectors.partitioningBy(person -> person.getAge() >= 18)	//条件分组
Collectors.averagingDouble(Person::getAge)			//平均值
Collectors.summarizingInt(Person::getAge)			//综合数据:总和、平均数、最大值、最小值、总数
Optional<T>			T			T				容器对象,可存null值,减少空指针
Integer value1 = null;
Integer value2 = 10;
Optional<Object> empty = Optional.empty();             //返回null对象
Optional<Integer> op1 = Optional.ofNullable(value1);   //允许存null
String str = op1.map(User::getName)).orElse("")	    //防空指针映射
boolean present = op1.isPresent();                     //判断是否非空
Integer isNullDefualt = op1.orElse(0);          	    //为null给默认值
Optional<Integer> op2 = Optional.of(value2);           //null时抛异常
Integer integer = op2.get();                           //取出里的值
Comparator<T>	  	T,T			int				比较对象,比较两个值大小
Comparator<String> comparator.compare(str1, str2);
Comparator.comparingInt(Person::getAge)
Comparator.reverseOrder()
Comparator.comparing(Person::getName, String::compareTo)

//举栗
@FunctionalInterface
public interface Comparator<T> {
    // 抽象方法(有且仅有一个)
    public void sub();
 
    // java.lang.Object中的方法不是抽象方法
    public boolean equals(Object var1);
 
    // default不是抽象方法
    public default void defaultMethod(){   }

    // static不是抽象方法
    public static void staticMethod(){    }
}

--------------------------------------------------------------------------------
java中提供了以下方式来生成流
创建流

Collection.stream() 使用集合创建流;
Collection.parallelStream() 并行流,适用于无顺序要求的操作;
Arrays.stream(Object[]);
Stream.of(Object[]), IntStream.range(int, int) 或 Stream.iterate(Object, UnaryOperator), Stream.empty(), Stream.generate(Supplier f);  //Stream.iterate(1, x -> x + 1).limit(10);
BufferedReader.lines();
Random.ints();
BitSet.stream(), Pattern.splitAsStream(java.lang.CharSequence),和JarFile.stream()。
中间操作(无副作用)

filter(Predicate)与预期匹配的流的元素
map(Function<T, U>)将提供的函数应用于流的元素的结果
mapToInt(Function<T, U>)   Stream<Integer>转IntStream
boxed()   IntStream转Stream<Integer>
flatMap(Function<T, Stream> 将提供的流处理函数应用于流元素后获得的流元素
distinct()去重
sorted() 按自然顺序排序的流元素
Sorted(Comparator) 按提供的比较符排序的流元素
limit(long)截断至所提供长度的流元素
skip(long)丢弃了前 N 个元素的流元素,配合limit可实现分页
peek(o -> o.setAge(100))	消费操作,用于设值或打印值的变化
takeWhile(Predicate)(仅限 Java 9)在第一个提供的预期不是 true 的元素处阶段的流元素
dropWhile(Predicate)(仅限 Java 9)丢弃了所提供的预期为 true 的初始元素分段的流元素
终止操作

forEach(Consumer action) 将提供的操作应用于流的每个元素。
peek()  跟foreach相同,但不是终止操作
toArray() 使用流的元素创建一个数组。
reduce(...) 将流的元素聚合为一个汇总值。
collect(...) 将流的元素聚合到一个汇总结果容器中。
min(Comparator) 通过比较符返回流的最小元素。
max(Comparator) 通过比较符返回流的最大元素。
count() 返回流的大小。
sum()	总和
summaryStatistics()     获取一组数据的综合值(均值、最值、总和、计数)对象
anyMatch(Predicate),  allMatch(Predicate),   noneMatch(Predicate)   短路操作,预期匹配返回布尔值
findFirst() 返回流的第一个元素(如果有)。
findAny()  匹配任何一个


stream
--------------------------------------------------------------------------------
IntStream ints = new Random().ints();	//随机整数
IntStream intStream = IntStream.range(1, 10);   //1-10的整数
Stream<Integer> stream = intStream.boxed();  //int流转化为普通流
Stream<FileTaskBean> stream = list.stream();

Stream<FileTaskBean> pStream = list.parallelStream();

Stream<Integer> intStream = Stream.of(1, 2, 3);
IntStream stream = Arrays.stream(new int[10]);

Stream<Integer> intStream = Stream.iterate(0, (x) -> x + 2).limit(6);   		//0开始+2生成6个数

Stream<Double> stream = Stream.generate(Math::random).limit(10);		//10个[0,1]的数
IntStream.generate(random::nextInt).limit(10).toArray();  //10个int数
Stream<String> lineStream = new BufferedReader(new FileReader(path)).lines();	//IO流

Stream<String> strStream = Pattern.compile(",").splitAsStream("a,b,c,d");	//分隔流
Stream<T> stream = Stream.concat(stream1<T>,stream2<T>);			//合并流
map.entrySet().stream().max(Map.Entry.comparingByValue()).get();     //获取map中value值最大的元素
Comparator.comparingInt(String::length).compare(str1,str2);  //获取长度较长的长度
map.keySet().stream().max(Comparator.comparingInt(String::length)).orElse("0123456789").length();  //获取key名称最长的长度,默认10
map.keySet().stream().map(String::length).mapToInt(Integer::intValue).max().orElse(10).length();  //获取key名称最长的长度,默认10

拓展:



--------------------------------------------------------------------------------
一、实现线程
//内部类实现
	new Thread(new Runnable() {
		@Override
		public void run() {
			System.out.println("匿名内部类 run thread ...");
		}
	}).start();

	//lambda实现
	new Thread(() -> {
		System.out.println("lambda run thread ...");
	}).start();

--------------------------------------------------------------------------------
二、实现接口
Runnable runnable = () -> System.out.println("lambda 实现接口");
runnable.run();

@FunctionalInterface
interface FuncLambIface{
        //抽象方法
        int calc(int num1, int num2);
        //非抽象方法
        default int calc2(int num1, int num2){
            return num1 - num2;
        }
        static int calc3(int num1, int num2){
            return num1 / num2;
        }
 }

    //lambda表达式重写接口抽象方法(唯一)实现实例化
    static void calcByLamb(int num1, int num2){
        FuncLambIface funcLambIface = (n1, n2) -> n1 + n2;
        System.out.println("非抽象方法:" + funcLambIface.calc2(num1, num2));
        System.out.println("抽象方法:" + funcLambIface.calc(num1, num2));
    }

--------------------------------------------------------------------------------
三、与stream结合使用
1.字母转大写
2.合并多个list
3.取list最大值
4.数组值累加
5.并行流操作
6.数组排序
7.条件过滤
8.list分组
9.嵌套filter

List<String> list = Stream.of("a", "b", "c")
    .map(str -> str.toUpperCase())		//将一个流中的值转换成一个新的流
    .collect(Collectors.toList());
String str = String.join(",", list);		//转换成以逗号隔开的字符串
String.join(",", values)	//guava中的Joiner.on(",").join(list)
String[] split = str .split(",");			//字符拆分成数组
Stream.of("1", "2", "3").collect(Collectors.joining(",", "[", "]"))		//拼接字符串
List<Integer> list = Stream.of(Arrays.asList(1, 2), Arrays.asList(3, 4))
      .flatMap(num -> num.stream())		//将多个小流合并成一个大流
      .collect(Collectors.toList());
list.forEach(System.out::println);

list.forEach(this::checkDate);  	//遍历调用当前类的检查方法

//自定义实现Funtion<T,R>接口,实现对象copy
stream.map(dto -> new MyFunction().apply());

List<Integer> list = Arrays.asList(3, 5, 2, 9, 1);
int maxInt = list.stream()
                 	.max(Integer::compareTo)	//获取最大值	Integer::compareTo 叫做 "方法引用" 等价于 (int1, int2) -> int1.compareTo(int2)
                 	.get(); 					//Entry::getKey(方法引用) => 类.静态方法 => 实例.方法 => 入参,方法返回值 => Function<T, R> func
 

int result = Stream.of(1, 2, 3, 4)
.reduce(0, (acc, element) -> acc + element);		//从一组值中生成一个值,0为初始值,等价于 0+1+2+3+4


int result = Stream.iterate(1L, i -> i + 1)				//流迭代器
                  		    .limit(n)
                                    .parallel()
                                    .reduce(0L, Long::sum)
 .get();


int sumSize = Stream.of("Apple", "Banana", "Orange", "Pear")
      .parallel()			//并行流操作 stream.parallel()或list.parallelStream()
      .map(s -> s.length())
      .reduce(Integer::sum)
      .get();

//指定范围随机数
Random random = new Random(2);  //种子相同的Random对象,生成的随机数序列是一样的

for (int i = 0; i < 10; i++) {

	System.out.println(random.nextInt(9999-1000) + 1000);

}

Stream.of(2, 4, 1, 3)
    .sorted()		//升序排序
    .collect(Collectors.toList())
    .forEach(System.out::println);

BaseStream longStream = LongStream.rangeClosed(0, 100);    //范围流[0,100],使用range则为[0, 100)

//stream抛异常
WeekDay[] weekDays = WeekDay.values();

Arrays.stream(weekDays)

		.filter(week -> week.getCode().equals(code))

		.findAny()

		.orElseThrow(() -> new IllegalArgumentException("无效的code!"));

IntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics();
stats.getCount()		//获取最值、均值等数据

List<String> list = Arrays.asList("1one", "two", "three", "4four");
list.stream()	// 1.得到容器的Steam
    	   .filter(str -> Character.isDigit(str.charAt(0)))		// 2.选出以数字开头的字符串
   	   .forEach(str -> System.out.println(str));	// 3.输出字符串


List<String> list = Arrays.asList("1one", "two", "three", "4four");
Set<String> newList = list.stream()		// 1.得到容器的Stream
                   .filter(str -> !Character.isDigit(str.charAt(0)))	// 2.选出不以数字开头的字符串
            	   .map(String::toUpperCase)		// 3.转换成大写形式
            	   .collect(Collectors.toSet());		// 4.生成结果集

//list结果转map
Map<String,String> map= list.stream().collect(Collectors.toMap(x->x.getId(), x->x.getName()));

List<Stu> list = new ArrayList <>();
list.add(new Stu(1,"petter","male",18));
list.add(new Stu(2,"halen","famale",19));
list.add(new Stu(3,"alex","male",20));
list.add(new Stu(4,"kola","famale",21));		
Map <String, List <Stu>> map = list.stream().collect(Collectors.groupingBy(e -> e.getSex()));	//根据性别分组
//结果 {famale=[Stu{id=2, name='halen', sex='famale', age=19}, Stu{id=4, name='kola', sex='famale', age=21}], male=[Stu{id=1, name='petter', sex='male', age=18}, Stu{id=3, name='alex', sex='male', age=20}]}

 Map <Boolean, List <Stu>> collect = list.stream().collect(Collectors.partitioningBy(e -> e.getSex() == "male")[,toSet()]);		//根据成立条件分组
//结果 {false=[Stu{id=2, name='halen', sex='famale', age=19}, Stu{id=4, name='kola', sex='famale', age=21}], true=[Stu{id=1, name='petter', sex='male', age=18}, Stu{id=3, name='alex', sex='male', age=20}]}

//以省份分组,并返回学生姓名的集合
Map<String, List<String>> map = students.stream().collect(Collectors.groupingBy(Student::getFrom, Collectors.mapping(Student::getName,Collectors. toList())));

//以省份分组到Set中。并返回一个TreeMap
Map<String, Set<String>> map = students.stream().collect(groupingBy(Student::getFrom, TreeMap::new, toSet()));

//返回身高最高的学生
Student stu = students.stream().collect(maxBy(Comparator.comparingDouble(Student::getHeight))).get();

//返回一个班级中每个省份的身高最高的学生
Map<String, Optional<Student>>  map = students.stream().collect(groupingBy(Student::getFrom, reducing(BinaryOperator.maxBy(Comparator.comparing(Student::getHeight)))));

//foreach指定起步位置获取下标
public class ForEachUtils {
    public static <T> void forEach(int startIndex,Iterable<? extends T> elements, BiConsumer<Integer, ? super T> action) {
        Objects.requireNonNull(elements);
        Objects.requireNonNull(action);
        if(startIndex < 0) {
            startIndex = 0;
        }
        int index = 0;
        for (T element : elements) {
            index++;
            if(index <= startIndex) {
                continue;
            }
            action.accept(index-1, element);
        }
    }
}

//比较两个值大小
int x = Comparator.comparingInt(String::length).compare(str1, str2);
//获取某个字段最大的对象
Student student = 
stu.stream.max(Comparator.comparing(Student::getRecord)).get();

//拼接数组元素
StringJoiner sj = new StringJoiner(",");
Arrays.Stream(arr).forEach(sh::add);
sj.toString();

//list 排序(int compare(T o1, T o2) ,返回正数,零,负数各代表大于,等于,小于)
list.stream().sorted(Comparator.reverseOrder());    //stream倒序

list.stream().sorted(Comparator.comparing(Student::getAge).reversed());	//stream倒序

list.stream().sorted(Comparator.comparing(Student::getAge,Comparator.reverseOrder()));		//age倒序

list.sort(Comparator.comparing(Integer::intValue).reversed());	//list倒序

Collections.sort(list, Comparator.comparing(Student::getAge));    //Collections升序

list.sort(Comparator.comparingInt(Computer::getSpeed).reversed().thenComparingInt(Computer::getPrice));   //先按Speed倒序,再按Price升序
list.stream().sorted(Comparator.comparing(Student::getName).reversed().thenComparing(Student::getAge,Comparator.reverseOrder()));     //name降序,再age降序

//自定义排序
Comparator instance = Collator.getInstance(Locale.CHINA);
//内部类
      Collections.sort(stus, new Comparator<Student>() {
			@Override
			public int compare(Student s1, Student s2) {
				return instance.compare(s1.getName(), s2.getName());
			}
	});
//lambda
        list.sort((o1, o2) -> instance.compare(o1.getName(), o2.getName()));

//list多字段排序
Comparator<SumTotalAmountBean> byTotalNumber = Comparator.comparing(t -> new BigDecimal(t.getTotalNumber()));
Comparator<SumTotalAmountBean> bySumAmount = Comparator.comparing(s -> new BigDecimal(s.getSumAmount()));
bySumAmount.reversed(); 	//倒序
list.sort(byTotalNumber.thenComparing(bySumAmount));

//根据某字段去重
方法一
List<Student> studentList = studentList.stream().collect(

	Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Student::getName))), ArrayList::new)

);
方法二
public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {

	//Map<Object, Boolean> seen = new ConcurrentHashMap<>();

	//return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    //存在返回true
Set<Object> seen = ConcurrentHashMap.newKeySet();

return t -> seen.add(keyExtractor.apply(t));
}
List<BizTypeBean> collect = list.stream().filter(distinctByKey(item -> item.getBizTypeName()+"_"+item.getBillType())).collect(Collectors.toList());

//lambda表达式声明接口
static <T> T doSomething(Function<UserEntity, T> function){
    UserEntity userEntity = new UserEntity().setAge(10).setName("张三");
    System.out.println("function 前置处理 -> id:" + userEntity.getId());
    T t = function.apply(userEntity);
    return t;
}
//测试
public static void main(String[] args) {
    String rs = StremHelper.doSomething(userEntity -> {
        userEntity.setId((short) 1001);
        System.out.println("function 主体实现 -> id:" + userEntity.getId());
        return "OK";
    });
    System.out.println("处理结果:" + rs);
}

//map中若key对应的value为空,会将第二个参数的返回值存入该key并返回
       Object key2 = map.computeIfAbsent("key", k -> new Object());

//map生成新map
map.forEach((k, v) -> newMap.put(k, v+"@"));

//url参数拼接
String param = list.stream().map(m -> { return String.format("&%s=%s", m.getKey(), URLEncoder.encode(m.getValue(), "UTF-8")); }).collect(Collectors.joining());

//空指针对象
Optional<String> o = Optional.ofNullable(str);
String val = o.orElse("");
o.orElseThrow(() -> new Exceiption("error"));
if(o.isPresent()){
    String o2 = o.get();
}

//避免空指针操作
Optional.ofNullable(list).isPresent(ls -> ls.forEach(e -> { }));
--再封装
ifPresentDo(userDto, UserDto::getName, System.out::println);
public static <T, U> void ifPresentDo(T value, Funtion<? super T, ? extends U> mapper, Consumer<? super U> consumer){     Optional.ofNullable(value).map(mapper).isPresent(consumer);
}

//多层嵌套取值空指针,避免多层判断,如有一层为空返回Optional空对象
Optional<String> name = Optional.ofNullable(grader)
.map(Grader::getFather)
.map(Father::getSon)
.map(Son::getName);
if(name.isPresent()){
     name.get();
}

//map对象取值,避免null
Optional<String> opt = Optional.ofNullable(this.getMap())
.map(m -> (String)m.get("ID"));
String str1 = opt.orElse(null);
String str2 = opt.map(s -> s.substring(2)).orElse(null);

//嵌套filter
# list1剔除掉包含list2的数据
 list1.stream().filter(f -> list2.stream().noneMatch(a -> a.equals(f))).collect(Collectors.toList());
# list1剔除掉包含list2的数据
 list2.forEach(list1::remove);

//合并流和小流合成大流
方法一:
Stream.concat(stream1, stream2);
方法二:
List<list<String>> lists;
lists.stream.flatMap(lt -> lt.stream.filter(Objects::nonNull)).collect(Collectors.toList());

//debug
Long sum = LongStream.rangeClosed(1,4)  //[1,4]
.boxed()  //Long::ofValue装箱
.collect(Collectors.toList()).stream()
.peek(e -> System.out.println("Debug: " + e)) //调试
.reduce((x,y) -> x*y) //1*2*3*4=24
.orElse(0L);

//流转换+倒序+换行打印
IntStream.rangeClosed(1,5).mapToObj(i -> String.valueOf(i).concat("%n")).sorted(Comparator.reverseOrder()).forEach(System.out::printf);

//遍历Map按key最长的补全进行右对齐打印kv
-- 取最长key长度值
Stream<Object> stream = System.getProperties().keySet().stream();
final int maxLen = stream.map(k -> String.valueOf(k).length()).max(Comparator.ComparingInt(o ->  o)).orElse(20);
或者
final int maxLen = stream.map(String::valueOf).max(Comparator.comparing(String::length)).map(String::length).orElse(20);
-- 打印
int actLen = Math.min(maxLen, 50); //最大50
System.getProperties().forEach((k,v) -> System.out.printf("%"+actLen+"s = %s%n, k, v));

--------------------------------------------------------------------------------
四、string、array 、list、set、map之间的相互转换
1.array 与 list
List list = Lists.newArrayList();
//法一
List<String> list = Arrays.asList(array);
String[] array = list.toArray(new String[list.size()]);
//法二
Collections.addAll(list, array);
//法三
Arrays.stream(array).collect(Collectors.toList());
Arrays.stream(as).forEach(System.out::print);
//法四
JSON.parseArray("[1,2,3]", Integer.class);
//法五
stream.toArray(String::[])
或
stream.toArray(size -> new String[size])

2.list 、set与 map
//法一之流
Map<String, Object> map = Maps.newHashMap();
List<Object> list = new ArrayList<>(map.values());
List<Object> list = map.entrySet().stream().sorted(Map.Entry.comparingByKey()).map(e -> e.getValue()).collect(Collectors.toList());			//map正序后转list
List<Object> list = map.entrySet().stream().sorted(Map.Entry.<String,Object>comparingByKey().reversed()).map(Map.Entry::getValue).collect(Collectors.toList());      //map倒序后转list
Map<String, User> map = list.stream().collect(Collectors.toMap(User::getUserId, user -> user));

List list = new ArrayList(new HashSet());
Set<Object> set = new HashSet(map.values());
或
Map<String, User> map = list.stream().collect(toMap(User::getUserId, User::getName));
List<User> list = 	.stream().collect(toCollection(ArrayList::new));

//法二之Guava
Map<String, User> maps = Maps.uniqueIndex(list, new Function<User, String>() {
    @Override
    public Long apply(User user) {
        return user.getUserId();
    }
});

3. array 与 string
//法一之流
String[] array = str.split(",");
String join = String.join(",", array);	 
//法一之Guava
String str = Joiner.on(",").join(array);

4.动态数组转list
String... args
List<String> list = new ArrayList<>();
Arrays.stream(args).forEach(list::add);

5.Object数组转String数组
Arrays.stream(objArr).toArray(String[]::new);

6.两个数组合并成为一个有序map
String[] keyArr = {"k1", "k2", "k3"};
String[] valArr = {"1", "2", "3"};
Map<String, String> map = IntStream.range(0,  keyArr.length).boxed()
                        .collect(Collectors.toMap(i -> keyArr[i], i -> valArr[i], (v1, v2) -> v1, LinkedHashMap::new);


--------------------------------------------------------------------------------
五、java泛型
代码模板本质:底层用Object接收一切对象,用泛型+编译器限定特定对象,用多态支持类型强转。
1.分类
泛型类型:
          [1]List<E> list = new ArrayList<>();				存E,取E,赋值E
          [2]List<? extends E> list = new ArrayList>();		不可存,取E,赋值<=E,适合查询
 	  [3]List<? super E> list = new ArrayList<>();			存<=E,取Object,赋值>=E,适合存值
 	  [4]List<?> list = new ArrayList<>();				不可存,取Object,赋值ALL
   [5]List list = new ArrayList<>();					 存ALL,取Object,赋值ALL
泛型的限定:
           ? extends E: 上界通配符,接收E类型或者E的子类型。适用取值,不易存值,PECS法则
           ?super E: 下界通配符,接收E类型或者E的父类型。适用存值,不易取值





2.区别
“<T>"和"<?>",首先要区分开两种不同的场景:
第一,声明一个泛型类或泛型方法。
第二,使用泛型类或泛型方法。
类型参数“<T>”主要用于第一种,声明泛型类或泛型方法。
无界通配符“<?>”主要用于第二种,使用泛型类或泛型方法

3.举栗
//泛型类、接口:一个类拥有多种同类型方法时使用
public interface Dao<T>{
List<T> getList(){};
}
public static <T> void show(List<T> list){
sout(list)
}
List<?> list = new ArrayList<String>();
Plate<? extends Fruit> p = new Plate<Apple>(new Apple());

public static <T, U extends Comparable<? super U>> Comparator<T> comparing(Function<? super T, ? extends U> keyExtractor) { }

4.ist<Object> 泛型转换 List<Map<String,Object>>
注:T必须要有setter/getter方法
public <T> List<Map<String, Object>> listConvert(List<T> list) {
    List<Map<String, Object>> listMap = new ArrayList<>();
    for (T t : list) {
            Field[] fields = t.getClass().getDeclaredFields();
            Map<String, Object> m = new HashMap<>();
            for(Field field : fields){
                String keyName = field.getName();
                if (!"this$0".equals(keyName)) {
                    PropertyDescriptor pd = new PropertyDescriptor(keyName, t.getClass());
                    Method getMethod = pd.getReadMethod();
                    Object o = getMethod.invoke(t);
                    m.put(keyName, o);
                }
     }
    return listMap;
}

//泛型方法:一个方法处理多种类型时使用。通过<T>声明返回值是一个泛型 T,T只是个占位符,随便写哪个字母,但一定要是和< >里面相同的字母
public class TesCusResponseDto <T>{

    private long totalRecords;

    private List<T> data;

}
public <T> TesCusResponseDto<T> doThing(Map<String,Object> params) {
return  (TesCusResponseDto<T>)HttpClientUtils.getAndReturnJson(url, parameterMap, TesCusResponseDto.class);;
}
TesCusResponseDto<User> respDto = doThing(params);

//形参为Class<T>,实参为List<User>.class编译不通过
先转出String.class,然后通过JSON+TypeReference反序列化成想要的泛型,互转字段需要一致
List<OceanReceiptRelDto> list =  new ObjectMapper().readValue(jsonStr, new TypeReference<List<OceanReceiptRelDto>>(){});

//T泛型接收响应数据时,默认为LinkedHashMap,转换成对应的实体
List<User> list = JSON.parseObject(JSON.toJSONString(List<LinkedHashMap对象>), new TypeReference<List<User>>() { });

//接口lambda实现
//接口
public interface QueryFunction<R> {
    List<R> apply();
}
//作形参
queryAndWrap(QueryFunction queryFunction, QueryPageBean queryPageBean)
//调用lambda实现
queryAndWrap(() -> mapper.queryList(queryBean), queryBean)
//处理逻辑
List<T> list = queryFunction.apply();

//举例
ErpOperationUtil.processExportResult(jarvisApiBean, param,
        ReceivableCreateReqParam.class, ReceivableCreateRspResult.class,
        (s, t) -> {
            boolean isInvoice = BigDecimal.ZERO.compareTo(s.getAmount()) < 0;
            t.setBatchId(s.getImsId());
            t.setSourceId(s.getImsId());
            t.setTransactionClass(isInvoice ? TransactionClass_INVOICE : TransactionClass_CREDIT_MEMO);
            t.setTransactionSource(isInvoice ? "IMS - IN" : "IMS - CM");
            t.setRemark("import from IMS");},
        (p) -> receivableBizService.updateForExporting(p),
        (p) -> receivableBizService.updateForError(p));

 public static <TErp extends ErpStatusBean, TCreatePayload extends CreatePayload, TCreateReqParam extends CreateReqParam, TRspResult extends RspResult<TCreatePayload>>
    ErpOperationResult processExportResult(JarvisApiBean jarvisApiBean,
                                           ErpOperationParam<TErp> param,
                                           Class<TCreateReqParam> t3Class,
                                           Class<TRspResult> t4Class,
                                           BiConsumer<TErp, TCreateReqParam> consumer,
                                           Consumer<TErp> ingHandle,
                                           Consumer<TErp> errHandle){
        ErpOperationResult result = new ErpOperationResult();
        result.setHasError(false);
        List<ErpOperationResult.Result> innerResult = new ArrayList<>();

        String status;
        String message;
        List<TCreatePayload> payloadList = new ArrayList<>();
        try {
            BeanMapper beanMapper = SpringApplicationContexts.getJarvisServerAppContext().getBean(BeanMapper.class);
            List<TCreateReqParam> reqParamList = beanMapper.convertList(param.getList(), t3Class, consumer);
            TRspResult rspResult = ErpApiHelper.export(jarvisApiBean, reqParamList, t4Class);
            status = rspResult.getStatus();
            message = rspResult.getMessage();
            payloadList = rspResult.getPayloadList();
        } catch (Exception ex){
            status = ErpStatusEnum.E.getCode();
            message = ex.getMessage();
        }
        Map<String, TCreatePayload> payloadMap = payloadList.stream().collect(Collectors.toMap(TCreatePayload::getSourceId, m -> m, (k1, k2) -> k1));

        if (ErpStatusEnum.S.getCode().equals(status)){
            result.setHasError(false);
            for (TErp item : param.getList()) {
                if (ingHandle != null) {
                    item.setExportStatus(ExportStatusEnum.EXPORTING.getExportStatus());
                    item.setExportMsg(null);
                    ingHandle.accept(item);
                }

                ErpOperationResult.Result s = new ErpOperationResult.Result();
                s.setId(item.getImsId());
                s.setErrorCode(ErpStatusEnum.S.getCode());
                innerResult.add(s);
            }
        } else{
            result.setHasError(true);
            for (TErp item : param.getList()){
                TCreatePayload payload = payloadMap.get(item.getImsId());
                if (payload != null){
                    if (ErpStatusEnum.E.getCode().equals(payload.getProcessStatus())){
                        if (errHandle != null){
                            item.setExportStatus(ExportStatusEnum.ERROR.getExportStatus());
                            item.setExportMsg(payload.getProcessMessage());
                            errHandle.accept(item);
                        }
                    }
                    ErpOperationResult.Result s = new ErpOperationResult.Result();
                    s.setId(item.getImsId());
                    s.setErrorCode(payload.getProcessStatus());
                    s.setErrorMsg(payload.getProcessMessage());
                    innerResult.add(s);
                }
            }
        }
        result.setResultList(innerResult);
        result.setMessage(message);
        return result;
    }
}

//ShutdownHook使用
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
    System.out.println(Thread.currentThread().getName()+"--"+ "垃圾回收完毕,退出JVM.");
}, "Hook"));

IntStream.range(1, 10).forEach((f) -> {
    try {
        TimeUnit.MILLISECONDS.sleep(1000L);
        System.out.println(Thread.currentThread().getName()+"--"+ new Date().toString());
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
});

【接口与抽象类的区别】
--------------------------------------------------------------------------------
* 抽象类要被子类继承,接口要被类实现。
* 接口只能做方法声明,抽象类中可以作方法声明,也可以做方法实现。
* 接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。
* 接口是设计的结果,抽象类是重构的结果。
* 抽象类和接口都是用来抽象具体对象的,但是接口的抽象级别最高。
* 抽象类可以有具体的方法和属性,接口只能有抽象方法和不可变常量。
* 抽象类主要用来抽象类别,接口主要用来抽象功能。

//lambda获取字段名称
String colName = fnToColumName(UserDto::getName);
-- ConditionFunc<T, R> extends Function<T, R>, Serializable
public static <T> String fnToColumName(ConditionFunc<T, ?> fn){
    Method m = fn.getClass().getDeclaredMethod("writeReplace");
   m.setAccessible(true);
   SerializedLambda serLambda = (SerializedLambda) m.invoke(fn);
   String getterName = serLambda.getImplMethodName();
   getterName = getterName.substring(3);
   return Introspector.decapitalize(getterName);
}

【闭包】
--------------------------------------------------------------------------------
闭包就是把函数以及变量包起来,使得变量的生存周期延长。闭包跟面向对象是一棵树上的两条枝,实现的功能是等价的
public static InnerObject<Integer> closure(){
    final int index = 100;
    return new Supplier<Integer>() {
        @Override
        public Integer get() {
            return index;
        }
    };
}

public interface InnerObject<T> {
    T get();
}

PS: stream.forEarch里不支持break跳出,return相当于continue

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值