使用lambda提供基于堆栈的上下文(例如,文件操作的路径)
我有一种微妙的方式(可能已经实现和讨论过)在Groovy(取自
Groovy documentation here)中做了相同的操作,我试图改进它,如果可能的话:
ant.sequential { echo("inside sequential") def myDir = "target/AntTest/" mkdir(dir: myDir) copy(todir: myDir) { fileset(dir: "src/test") { include(name: "**/*.groovy") } } echo("done") } 这个例子很好,但我没有做基于Ant的程序:我想做一些流畅的API来操作文件和目录(让我们称之为FileManipulator,我的名字很糟糕:)). 基本上这将是: new DefaultFileManipulator(Paths.get("root")).with(() -> { newFile("file1"); // create file root/file1 newFile("file2"); // create file root/file2 cd("directory1",() -> { // create directory root/directory1 newFile("file1"); // create file root/directory1/file1 cd("directory1",() -> { // create direcotry root/directory1/directory1 newFile("file1"); // create file root/directory1/directory1/file1 }); newFile("file2"); // create file root/directory1/file2 }); }); 使用以下界面: interface FileManipulator { FileManipulator with(LambdaFileManipulator m); FileManipulator cd(String path,LambdaFileManipulator m); Path newFile(String path) throws IOException; } @FunctionalInterface interface LambdaFileManipulator extends FileManipulator { void execute() throws IOException; default FileManipulator with(LambdaFileManipulator m) { return FileManipulatorStack.manipulatorFor(this).with(m); } // for each non default method of FileManipulator,the same call to FileManipulatorStack.manipulatorFor(this). } DefaultFileManipulator只是实现FileManipulator并使用下面定义的AbstractFileManipulator. 因为我希望路径是相对的,我需要以某种方式保持lambda上下文(我不想弄乱当前的工作目录):我使用这样操作的堆栈: // visibility package,because that's technical stuff! class FileManipulatorStack { private static final Map<LambdaFileManipulator,ArrayDeque<LambdaFileManipulatorDelegator>> stacks = new ConcurrentHashMap<>(); static LambdaFileManipulatorDelegator manipulatorFor(final LambdaFileManipulator delegatee) { final ArrayDeque<LambdaFileManipulatorDelegator> stack = stacks.get(delegatee); if (null == stack) { throw new IllegalStateException("state is empty for [" + delegatee + "]"); } return stack.getLast(); } static void delegate(final Path scopedPath,final LambdaFileManipulator delegatee) { final LambdaFileManipulatorDelegator handler = new LambdaFileManipulatorDelegator(scopedPath); final ArrayDeque<LambdaFileManipulatorDelegator> stack = stacks.computeIfAbsent(delegatee,key -> new ArrayDeque<>()); stack.addLast(handler); try { delegatee.execute(); } catch (final Exception e) { throw new DelegatedFileCreatorHandlerUndeclaredException(e); } finally { final LambdaFileManipulatorDelegator ss = stack.removeLast(); if (ss != handler) { throw new IllegalStateException("invalid stack"); } if (stack.isEmpty()) { stacks.remove(delegatee); } } } static class LambdaFileManipulatorDelegator extends AbstractFileManipulator { ... constructor ... } } abstract class AbstractFileManipulator implements FileManipulator { private final Path root; public AbstractFileManipulator(Path root) { this.root = requireNonNull(root,"root"); } public final FileManipulator with(LambdaFileManipulator m) { FileManipulatorStack.delegate(root,m); return this; } public final FileManipulator cd(String path,LambdaFileManipulator m) { FileManipulatorStack.delegate(root.resolve(path),m); return this; } public final Path newFile(String path) { Path p = root.resolve(path); Files.createFile(p); return p; } } 对于Stackoverflow规则,我的问题可能不是“好”,但这里是: 如何在不将FileManipulator作为参数添加到lambda的情况下改进这一点(我会使用Consumer来代替)? 使用lambda作为地图的关键是否有问题? (在this comment,它说lambda将动态转换为LambdaFileManipulator的一个实例,然后我可能不需要堆栈映射). 我是否错过了Java 8的一些功能,它允许我将lambda作为某个类的实现方法? 编辑:我回答了我自己的问题…这不起作用,因为lambda不会/永远不会知道它是FileManipulator的一个实现.所以,它不能调用那些方法.它可能使用静态方法(和一些上下文),但我认为它比有一个参数更糟糕. 解决方法
我没有看到它如何看起来像所示的示例,其中调用newfile()和cd()而没有在它们前面的对象.
它们不是静态函数,并且封闭类没有理由实现它们. 我提出这个不使用lambdas但可以运行非常接近你的例子的东西. enum FileActionType { CD,NEWFIlE; } class FileAction { final public String name; final public FileActionType type; final public FileAction actions[]; public FileAction(String name,FileActionType type,FileAction[] actions) { this.name = name; this.type = type; this.actions = actions; } } 实现静态功能: public static void execute(File f,FileAction... actions) { f.mkdirs(); for (int i = 0; i < actions.length; i++) { FileAction action = actions[i]; switch (action.type) { case CD: execute(new File(f,action.name),action.actions); break; case NEWFIlE: try { Files.createFile(new File(f,action.name).toPath()); } catch (IOException ex) { } break; } } } public static FileAction cd(String name,FileAction... actions) { return new FileAction(name,FileActionType.CD,actions); } public static FileAction newFile(String name) { return new FileAction(name,FileActionType.NEWFIlE,null); } 使用这样: execute( new File("/tmp/test"),newFile("file1"),// create file root/file1 newFile("file2"),// create file root/file2 cd( "directory1",// create file root/directory1/file1 cd("directory1",// create direcotry root/directory1/directory1 newFile("file1") // create file root/directory1/directory1/file1 ),newFile("file2") // create file root/directory1/file2 ) ); (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |