Api Java标准库:库中哪些方法的参数最多?

Api Java标准库:库中哪些方法的参数最多?,api,api-design,java,library-design,Api,Api Design,Java,Library Design,在Java标准库中,哪些方法具有最多的参数 注意:变量参数(Varargs)应计为数组类型的1个参数,而不是无限多个参数 原因:我正在尝试设计更好的库,我正在考虑禁止使用超过4个参数的方法,也许。。。 因此,我试图在标准库中找到具有大量参数的方法,研究该方法,并思考是否需要这样定义,以及是否有一个有效的案例具有4个以上的参数。对于实际提出的问题,我没有答案,但我确实认为我对潜在的问题有一些有用的见解你们试图回答的问题 这里我要提到的是,平均每个人一次可以记住7件事(注意北美当地的电话号码是7位数

在Java标准库中,哪些方法具有最多的参数

注意:变量参数(Varargs)应计为数组类型的1个参数,而不是无限多个参数

原因:我正在尝试设计更好的库,我正在考虑禁止使用超过4个参数的方法,也许。。。
因此,我试图在标准库中找到具有大量参数的方法,研究该方法,并思考是否需要这样定义,以及是否有一个有效的案例具有4个以上的参数。

对于实际提出的问题,我没有答案,但我确实认为我对潜在的问题有一些有用的见解你们试图回答的问题

这里我要提到的是,平均每个人一次可以记住7件事(注意北美当地的电话号码是7位数)

<>这意味着,当你看到大约7的东西时,你应该考虑打破和使用构图。例如:

  • 每包7节课
  • 每个接口7种方法
  • 函数的7个参数
等等

之后,您可以考虑:

  • 使用多个接口(特别是如果您可以看到分离,或者有机会遵守接口分离原则
  • 为包中的一个子类创建子包或新的顶级包
  • 利用Helper类,它可以帮助吸收函数的一些参数
  • 在无法创建助手的情况下,请考虑构造器

这是灵活的(例如,法律规定它实际上是+2或-2)但我认为它可以作为一个有用的基准。

限制自己的公共API中参数数量的目标当然是一个好的目标,但人们不应该盲目地遵守任意规则,然后应用古怪的变通方法来遵循它们。而且,有时应该只是如何不解决某些问题的启发


也就是说,回答实际问题有点困难。你想

  • 只关注
    公共
    受保护的
    方法
  • 只考虑<代码>公共< /代码>类>
  • 在类中包含JavaFX之类的方法
  • 公共的
    类中包含方法,但包含专有API

然而,我很好奇。使用(+1!)、加载它们(并公然忽略错误)、从有效类中获取所有方法并查看它们的参数计数,我可以找到一些结果:

  • 总的赢家似乎来自JavaFX运行时的一个类,名为
    com.sun.scenario.effect.impl.sw.sse.SSEPhongLighting\u SPOTPeer
    。该方法是一个
    本机
    方法,简单地称为
    过滤器
    ,并接收到一个巨大的37个参数
    私有静态本机void com.sun.scenario、 effect.impl.sw.sse.SSEPhongLighting_SPOTPeer.filter(int[],int,int,int,int,int,int[],float,float,float,float,int,int,int,int,int,int,int,float,float,float,float,float,int[],float,float,float,float,float,float,int,int,float,float,float)

    但是,该方法是
    private
    native
    ,在OpenJDK JavaFX运行时repo中甚至找不到该类,因此我假设它是以某种方式自动生成的

  • 将整个搜索限制为
    public
    类和方法,这些类和方法也是
    public
    受保护的
    (而不是
    本机的
    )这一次,它在
    com.sun.prism.impl.VertexBuffer
    类中,它有一个名为
    addMappedPgram
    的方法,有24个参数:
    public final void com.sun.prism.impl.VertexBuffer.addMappedPgram(浮动、浮动、浮动、浮动、浮动、浮动、浮动、浮动、浮动、浮动、浮动、浮动、浮动、浮动、浮动、浮动、浮动、浮动、浮动、浮动、浮动、浮动、浮动、浮动、浮动、浮动、浮动、浮动)
    ,回购协议还包含

    这是一个大多数编码准则都会说参数数量太多的方法示例。但是参数太“常规”(遵循命名模式,可能与四边形的4个角有关)我认为这样的东西仍然是合理的,但是这个类仍然不应该被客户端使用,必须被视为“专有API”

  • 省略以
    “sun.”
    “com.sun.”开头的包中的类。
    将我们带到可能被认为是“正确答案”的地方问题:类
    org.w3c.dom.events.MouseEvent
    包含一个名为
    initMouseEvent
    的方法,该方法仍然接收15个参数:
    public abstract void org.w3c.dom.events.MouseEvent.initMouseEvent(java.lang.String、boolean、boolean、org.w3c.dom.views.AbstractView、int、int、int、int、boolean、boolean、short、org.w3c.dom.events.EventTarget)

(一个相关的旁注:到目前为止,我遇到的客户端应该使用的参数数量最多的函数是一个参数31的函数。)

更新 作为对评论的回应,我现在还介绍了构造函数

javafx.scene.input.ScrollEvent
有两个构造函数,其中23个参数,即
public javafx.scene.input.ScrollEvent(javafx.event.EventType、double、double、double、boolean、boolean、double、double、double、double、double、double、double、javafx.scene.input.ScrollEvent$HorizontalTextScrollUnits、double、int、javafx.scene.input.PickResult)
公共javafx.scene.input.ScrollEvent(java.lang.Object,java
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Enumeration;
import java.util.List;
import java.util.function.Predicate;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class ArgCounting
{
    static class Entry
    {
        Class<?> clazz;
        Executable executable;
        int numParams;
    }

    public static void main(String[] args) throws Exception
    {
        List<Entry> entries = new ArrayList<Entry>();
        ClassFinder.findClasses(new Visitor<String>()
        {
            @Override
            public boolean visit(String clazz)
            {
                try
                {
                    System.out.println(clazz);
                    Class<?> c = Class.forName(clazz);
                    Method[] methods = c.getDeclaredMethods();
                    for (Method method : methods)
                    {
                        Entry entry = new Entry();
                        entry.clazz = c;
                        entry.executable = method;
                        entry.numParams = method.getParameterCount();
                        entries.add(entry);
                    }
                    Constructor<?>[] constructors = c.getDeclaredConstructors();
                    for (Constructor<?> constructor : constructors)
                    {
                        Entry entry = new Entry();
                        entry.clazz = c;
                        entry.executable = constructor;
                        entry.numParams = constructor.getParameterCount();
                        entries.add(entry);
                    }
                }
                catch (Throwable e)
                {
                    System.out.println("Ignoring: " + e);
                }
                return true;
            }
        });

        System.out.println("There are " + entries.size() + " executables");

        Predicate<Entry> executableIsNotNative = 
            e -> !Modifier.isNative(e.executable.getModifiers());
        Predicate<Entry> executableIsPublic = 
            e -> Modifier.isPublic(e.executable.getModifiers());
        Predicate<Entry> executableIsProtected = 
            e -> Modifier.isProtected(e.executable.getModifiers());
        Predicate<Entry> classIsPublic = 
            e -> Modifier.isPublic(e.clazz.getModifiers());

        List<String> skippedPackagePrefixes = Arrays.asList(
            "sun.", "com.sun.");
        Predicate<Entry> isSkipped = e -> 
        {
            for (String prefix : skippedPackagePrefixes) 
            {
                Package p = e.clazz.getPackage();
                if (p != null)
                {
                    if (p.getName().startsWith(prefix))
                    {
                        return true;
                    }
                }
            }
            return false;
        };
        Predicate<Entry> isNotSkipped = isSkipped.negate();

        Predicate<Entry> executableIsRelevant = 
                executableIsNotNative.and(executableIsPublic.or(executableIsProtected));

        System.out.println("Methods:");
        printAllMax(entries, 
            classIsPublic.and(executableIsRelevant).and(isNotSkipped).and(e -> e.executable instanceof Method));

        System.out.println("Constructors:");
        printAllMax(entries, 
            classIsPublic.and(executableIsRelevant).and(isNotSkipped).and(e -> e.executable instanceof Constructor));
    }

    private static void printAllMax(Collection<Entry> entries, Predicate<Entry> filter)
    {
        int max = entries.stream()
                .filter(filter)
                .mapToInt(e -> e.numParams)
                .max()
                .getAsInt();

        System.out.println("Having " + max + " parameters:");
        entries.stream().filter(filter.and(e -> e.numParams == max)).forEach(e -> 
        {
            System.out.println(e.executable);
        });
    }

}

// From https://stackoverflow.com/a/19554704/3182664
interface Visitor<T>
{
    /**
     * @return {@code true} if the algorithm should visit more results,
     *         {@code false} if it should terminate now.
     */
    public boolean visit(T t);
}

// From https://stackoverflow.com/a/19554704/3182664
class ClassFinder
{
    public static void findClasses(Visitor<String> visitor)
    {
        String classpath = System.getProperty("java.class.path");
        String[] paths = classpath.split(System.getProperty("path.separator"));

        String javaHome = System.getProperty("java.home");
        File file = new File(javaHome + File.separator + "lib");
        if (file.exists())
        {
            findClasses(file, file, true, visitor);
        }

        for (String path : paths)
        {
            file = new File(path);
            if (file.exists())
            {
                findClasses(file, file, false, visitor);
            }
        }
    }

    private static boolean findClasses(File root, File file,
        boolean includeJars, Visitor<String> visitor)
    {
        if (file.isDirectory())
        {
            for (File child : file.listFiles())
            {
                if (!findClasses(root, child, includeJars, visitor))
                {
                    return false;
                }
            }
        }
        else
        {
            if (file.getName().toLowerCase().endsWith(".jar") && includeJars)
            {
                JarFile jar = null;
                try
                {
                    jar = new JarFile(file);
                }
                catch (Exception ex)
                {

                }
                if (jar != null)
                {
                    Enumeration<JarEntry> entries = jar.entries();
                    while (entries.hasMoreElements())
                    {
                        JarEntry entry = entries.nextElement();
                        String name = entry.getName();
                        int extIndex = name.lastIndexOf(".class");
                        if (extIndex > 0)
                        {
                            if (!visitor.visit(
                                name.substring(0, extIndex).replace("/", ".")))
                            {
                                return false;
                            }
                        }
                    }
                }
            }
            else if (file.getName().toLowerCase().endsWith(".class"))
            {
                if (!visitor.visit(createClassName(root, file)))
                {
                    return false;
                }
            }
        }

        return true;
    }

    private static String createClassName(File root, File file)
    {
        StringBuffer sb = new StringBuffer();
        String fileName = file.getName();
        sb.append(fileName.substring(0, fileName.lastIndexOf(".class")));
        file = file.getParentFile();
        while (file != null && !file.equals(root))
        {
            sb.insert(0, '.').insert(0, file.getName());
            file = file.getParentFile();
        }
        return sb.toString();
    }
}