Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/370.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么在编译时不检查lambda返回类型?_Java_Generics_Lambda_Type Inference_Method Reference - Fatal编程技术网

Java 为什么在编译时不检查lambda返回类型?

Java 为什么在编译时不检查lambda返回类型?,java,generics,lambda,type-inference,method-reference,Java,Generics,Lambda,Type Inference,Method Reference,使用的方法引用具有返回类型Integer。但在下面的示例中,允许使用不兼容的字符串 如何使用声明修复方法,以在不手动强制转换的情况下获得方法引用类型安全 import java.util.function.Function; public class MinimalExample { static public class Builder<T> { final Class<T> clazz; Builder(Class<T> clazz

使用的方法引用具有返回类型
Integer
。但在下面的示例中,允许使用不兼容的
字符串

如何使用声明修复方法
,以在不手动强制转换的情况下获得方法引用类型安全

import java.util.function.Function;

public class MinimalExample {
  static public class Builder<T> {
    final Class<T> clazz;

    Builder(Class<T> clazz) {
      this.clazz = clazz;
    }

    static <T> Builder<T> of(Class<T> clazz) {
      return new Builder<T>(clazz);
    }

    <R> Builder<T> with(Function<T, R> getter, R returnValue) {
      return null; //TODO
    }

  }

  static public interface MyInterface {
    Integer getLength();
  }

  public static void main(String[] args) {
// missing compiletimecheck is inaceptable:
    Builder.of(MyInterface.class).with(MyInterface::getLength, "I am NOT an Integer");

// compile time error OK: 
    Builder.of(MyInterface.class).with((Function<MyInterface, Integer> )MyInterface::getLength, "I am NOT an Integer");
// The method with(Function<MinimalExample.MyInterface,R>, R) in the type MinimalExample.Builder<MinimalExample.MyInterface> is not applicable for the arguments (Function<MinimalExample.MyInterface,Integer>, String)
  }

}
import java.util.function.function;
公共类示例{
静态公共类生成器{
最后一节课;
建筑商(班级){
this.clazz=clazz;
}
静态生成器(clazz类){
返回新的构建器(clazz);
}
具有(函数getter,R returnValue)的生成器{
返回null;//TODO
}
}
静态公共接口MyInterface{
整数getLength();
}
公共静态void main(字符串[]args){
//无法接受缺少的compiletimecheck:
Builder.of(MyInterface.class).with(MyInterface::getLength,“我不是整数”);
//编译时错误确定:
使用((函数)MyInterface::getLength,“我不是整数”);
//MinimalExample.Builder类型中带有(Function,R)的方法不适用于参数(Function,String)
}
}

用例:类型安全但通用的生成器。 我试图实现一个没有注释处理(autovalue)或编译器插件(lombok)的通用生成器

import java.lang.reflect.Array;
导入java.lang.reflect.InvocationHandler;
导入java.lang.reflect.Method;
导入java.lang.reflect.Proxy;
导入java.util.HashMap;
导入java.util.concurrent.AtomicReference;
导入java.util.function.function;
公共类生成器示例{
静态公共类生成器实现调用处理程序{
最后一节课;
HashMap methodReturnValues=新的HashMap();
建筑商(班级){
this.clazz=clazz;
}
静态生成器(clazz类){
返回新的构建器(clazz);
}
生成器withMethod(方法,对象返回值){
类returnType=method.getReturnType();
if(returnType.isPrimitive()){
if(returnValue==null){
抛出新的IllegalArgumentException(“原语值不能为null:“+method”);
}否则{
试一试{
布尔值isConvertable=getDefaultValue(returnType).getClass().isAssignableFrom(returnValue.getClass());
如果(!isConvertable){
抛出新的ClassCastException(对于“+方法”,returnValue.getClass()+”不能转换为“+returnType+”;
}
}捕获(IllegalArgumentException | SecurityException e){
抛出新的运行时异常(e);
}
}
}else if(returnValue!=null&&!returnType.isAssignableFrom(returnValue.getClass()){
抛出新的ClassCastException(对于“+方法”,returnValue.getClass()+”不能转换为“+returnType+”;
}
Object previuos=methodReturnValues.put(方法,returnValue);
if(previous!=null){
抛出新的IllegalArgumentException(“为“+方法设置的值alread”);
}
归还这个;
}
静态HashMap defaultValues=新HashMap();
私有静态T getDefaultValue(类clazz){
if(clazz==null | |!clazz.isPrimitive()){
返回null;
}
@抑制警告(“未选中”)
T cachedDefaultValue=(T)defaultValues.get(clazz);
如果(cachedDefaultValue!=null){
返回cachedDefaultValue;
}
@抑制警告(“未选中”)
T defaultValue=(T)Array.get(Array.newInstance(clazz,1),0);
defaultValues.put(clazz,defaultValue);
返回默认值;
}
公共同步静态方法getMethod(类clazz,java.util.function.function resolve){
AtomicReference methodReference=新的AtomicReference();
@抑制警告(“未选中”)
T proxy=(T)proxy.newProxyInstance(clazz.getClassLoader(),新类[]{clazz},新调用处理程序(){
@凌驾
公共对象调用(对象p,方法,对象[]args){
方法oldMethod=methodReference.getAndSet(方法);
if(oldMethod!=null){
抛出新的IllegalArgumentException(“方法已被调用”+oldMethod);
}
类returnType=method.getReturnType();
返回getDefaultValue(返回类型);
}
});
决议。申请(代理);
Method=methodReference.get();
if(方法==null){
抛出新的RuntimeException(newNoSuchMethodException());
}
返回法;
}
//R将接受公共类型对象:-(//请参阅https://stackoverflow.com/questions/58337639
具有(函数getter,V returnValue)的生成器{
方法=getMethod(clazz,getter);
返回方法(方法,返回值);
}
//类型安全:-)但是我不想避免实现所有类型
生成器withValue(函数getter,long returnValue){
返回(getter,returnValue);
}
生成器withValue(函数getter,字符串returnValue){
返回(getter,returnValue);
}
T build(){
@抑制警告(“未选中”)
T proxy=(T)proxy.newProxyInstance(clazz.getClassLoader(),新类[]{clazz},this);
返回代理;
}
@凌驾
公共对象调用(对象代理、方法、对象[]参数){
objectreturnvalue=methodReturnValues.get(方法);
if(returnValue==null){
类returnType=method.getReturnType();
返回getDefaultValue(返回类型);
}
返回值;
}
}
静态公共接口MyInterface{
字符串getName();
long getLength();
Long getNullLength();
Long getFullLength();
Number getNumber();
}
公共静态void main(字符串[]args){
MyInterface x=Builder.of(MyInterface.class)。with(MyInterface::getName,“1”)。with(MyInterface::getLength,1L)。with(MyInterface::getNullLength,null)。with(MyInterface::getFullLength,new Long(2))。with(MyInterface::getNumber,3L)。bu
import java.lang.reflect.Array;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;

public class BuilderExample {
  static public class Builder<T> implements InvocationHandler {
    final Class<T> clazz;
    HashMap<Method, Object> methodReturnValues = new HashMap<>();

    Builder(Class<T> clazz) {
      this.clazz = clazz;
    }

    static <T> Builder<T> of(Class<T> clazz) {
      return new Builder<T>(clazz);
    }

    Builder<T> withMethod(Method method, Object returnValue) {
      Class<?> returnType = method.getReturnType();
      if (returnType.isPrimitive()) {
        if (returnValue == null) {
          throw new IllegalArgumentException("Primitive value cannot be null:" + method);
        } else {
          try {
            boolean isConvertable = getDefaultValue(returnType).getClass().isAssignableFrom(returnValue.getClass());
            if (!isConvertable) {
              throw new ClassCastException(returnValue.getClass() + " cannot be cast to " + returnType + " for " + method);
            }
          } catch (IllegalArgumentException | SecurityException e) {
            throw new RuntimeException(e);
          }
        }
      } else if (returnValue != null && !returnType.isAssignableFrom(returnValue.getClass())) {
        throw new ClassCastException(returnValue.getClass() + " cannot be cast to " + returnType + " for " + method);
      }
      Object previuos = methodReturnValues.put(method, returnValue);
      if (previuos != null) {
        throw new IllegalArgumentException("Value alread set for " + method);
      }
      return this;
    }

    static HashMap<Class, Object> defaultValues = new HashMap<>();

    private static <T> T getDefaultValue(Class<T> clazz) {
      if (clazz == null || !clazz.isPrimitive()) {
        return null;
      }
      @SuppressWarnings("unchecked")
      T cachedDefaultValue = (T) defaultValues.get(clazz);
      if (cachedDefaultValue != null) {
        return cachedDefaultValue;
      }
      @SuppressWarnings("unchecked")
      T defaultValue = (T) Array.get(Array.newInstance(clazz, 1), 0);
      defaultValues.put(clazz, defaultValue);
      return defaultValue;
    }

    public synchronized static <T> Method getMethod(Class<T> clazz, java.util.function.Function<T, ?> resolve) {
      AtomicReference<Method> methodReference = new AtomicReference<>();
      @SuppressWarnings("unchecked")
      T proxy = (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[] { clazz }, new InvocationHandler() {

        @Override
        public Object invoke(Object p, Method method, Object[] args) {

          Method oldMethod = methodReference.getAndSet(method);
          if (oldMethod != null) {
            throw new IllegalArgumentException("Method was already called " + oldMethod);
          }
          Class<?> returnType = method.getReturnType();
          return getDefaultValue(returnType);
        }
      });

      resolve.apply(proxy);
      Method method = methodReference.get();
      if (method == null) {
        throw new RuntimeException(new NoSuchMethodException());
      }
      return method;
    }

    // R will accep common type Object :-( // see https://stackoverflow.com/questions/58337639
    <R, V extends R> Builder<T> with(Function<T, R> getter, V returnValue) {
      Method method = getMethod(clazz, getter);
      return withMethod(method, returnValue);
    }

    //typesafe :-) but i dont want to avoid implementing all types
    Builder<T> withValue(Function<T, Long> getter, long returnValue) {
      return with(getter, returnValue);
    }

    Builder<T> withValue(Function<T, String> getter, String returnValue) {
      return with(getter, returnValue);
    }

    T build() {
      @SuppressWarnings("unchecked")
      T proxy = (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[] { clazz }, this);
      return proxy;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) {
      Object returnValue = methodReturnValues.get(method);
      if (returnValue == null) {
        Class<?> returnType = method.getReturnType();
        return getDefaultValue(returnType);
      }
      return returnValue;
    }
  }

  static public interface MyInterface {
    String getName();

    long getLength();

    Long getNullLength();

    Long getFullLength();

    Number getNumber();
  }

  public static void main(String[] args) {
    MyInterface x = Builder.of(MyInterface.class).with(MyInterface::getName, "1").with(MyInterface::getLength, 1L).with(MyInterface::getNullLength, null).with(MyInterface::getFullLength, new Long(2)).with(MyInterface::getNumber, 3L).build();
    System.out.println("name:" + x.getName());
    System.out.println("length:" + x.getLength());
    System.out.println("nullLength:" + x.getNullLength());
    System.out.println("fullLength:" + x.getFullLength());
    System.out.println("number:" + x.getNumber());

    // java.lang.ClassCastException: class java.lang.String cannot be cast to long:
    // RuntimeException only :-(
    MyInterface y = Builder.of(MyInterface.class).with(MyInterface::getLength, "NOT A NUMBER").build();

    // java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Long
    // RuntimeException only :-(
    System.out.println("length:" + y.getLength());
  }

}
Builder.of(MyInterface.class).with((Function<MyInterface, Object>) MyInterface::getLength, "I am NOT an Integer");
// it compiles since String is a Serializable
Function<MyInterface, Serializable> function = MyInterface::getLength;
Builder.of(MyInterface.class).with(function, "I am NOT an Integer");
// it doesn't compile since String isn't an Integer
Function<MyInterface, Integer> function = MyInterface::getLength;
Builder.of(MyInterface.class).with(function, "I am NOT an Integer");
<R> Builder<T> with(Function<T, R> getter, R returnValue)
Builder.of(MyInterface.class).with(MyInterface::getLength, "I am NOT an Integer");
Serializable, Comparable<? extends Serializable & Comparable<?>>
Builder.of(MyInterface.class).<Integer>with(MyInterface::getLength, "not valid");
class Builder<T> {
...
class BuilderMethod<R> {
  final Function<T, R> getter;

  BuilderMethod(Function<T, R> getter) {
    this.getter = getter;
  }

  Builder<T> returning(R returnValue) {
    return Builder.this.with(getter, returnValue);
  }
}

<R> BuilderMethod<R> with(Function<T, R> getter) {
  return new BuilderMethod<>(getter);
}
...
}

MyInterface z = Builder.of(MyInterface.class).with(MyInterface::getLength).returning(1L).with(MyInterface::getNullLength).returning(null).build();
System.out.println("length:" + z.getLength());

// YIPPIE COMPILATION ERRROR:
// The method returning(Long) in the type BuilderExample.Builder<BuilderExample.MyInterface>.BuilderMethod<Long> is not applicable for the arguments (String)
MyInterface zz = Builder.of(MyInterface.class).with(MyInterface::getLength).returning("NOT A NUMBER").build();
System.out.println("length:" + zz.getLength());