首页 > 解决方案 > Java 标准库:库中哪些方法的参数数量最多?

问题描述

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

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

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

标签: apiapi-designjavalibrary-design

解决方案


限制自己的公共 API 中的参数数量当然是一个很好的目标,但不应盲目地遵守任意规则,然后应用古怪的变通方法来遵循它们。此外,其他人的代码有时应该只是如何解决问题的灵感......


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

  • 只关注public还是protected方法?
  • 只考虑public类?
  • 在 JavaFX 之类的类中包含方法?
  • public是否在属于专有 API的类中包含方法?
  • ...

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

  • 总冠军似乎来自 JavaFX 运行时的一个类,称为com.sun.scenario.effect.impl.sw.sse.SSEPhongLighting_SPOTPeer. 该方法是一种native简单调用的方法,它filter接收多达37 个参数private static native 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,float,float[],float,float,float,float,float,float,float,float,float,float,int[],float,float,float,float,int,int,int,float,float,float)

    但是,该方法是privateand native,并且在 OpenJDK JavaFX 运行时存储库中甚至找不到该类,因此我假设它是自动生成的。

  • 将整个搜索限制在public也是publicprotected(而不是native)的类和方法仍会导致 JavaFX 类之一。这一次,它在com.sun.prism.impl.VertexBuffer类中,它有一个名为 的方法addMappedPgram,有24 个参数: public final void com.sun.prism.impl.VertexBuffer.addMappedPgram(float,float,float,float,float,float,float,float,float,float,float,float,float,float,float,float,float,float,float,float,float,float,float,float),并且 repo 也包含该方法的源代码

    这是大多数编码指南会说参数数量太多的方法示例。但是参数是如此“常规”(遵循命名模式,可能与四边形的 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,int,boolean,boolean,boolean,boolean,short,org.w3c.dom.events.EventTarget)。这是该方法的 JavaDoc API 文档

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

更新

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

该类javafx.scene.input.ScrollEvent有两个带有23 个参数的构造函数,即public javafx.scene.input.ScrollEvent(javafx.event.EventType,double,double,double,double,boolean,boolean,boolean,boolean,boolean,boolean,double,double,double,double,double,double,javafx.scene.input.ScrollEvent$HorizontalTextScrollUnits,double,javafx.scene.input.ScrollEvent$VerticalTextScrollUnits,double,int,javafx.scene.input.PickResult)public javafx.scene.input.ScrollEvent(java.lang.Object,javafx.event.EventTarget,javafx.event.EventType,double,double,double,double,boolean,boolean,boolean,boolean,boolean,boolean,double,double,double,double,javafx.scene.input.ScrollEvent$HorizontalTextScrollUnits,double,javafx.scene.input.ScrollEvent$VerticalTextScrollUnits,double,int,javafx.scene.input.PickResult)。这是后者的 API 文档的链接。


我用于测试的代码 - 这很难看而且很hacky,但我认为应该在此处添加:

(编辑也涵盖了构造函数,以回应评论:)

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();
    }
}

(注意:ClassFinder来自https://stackoverflow.com/a/19554704/3182664!)


推荐阅读