Related
I would like to check that string that is a filename contains a illegal argument from the ILLEGAL_CHARACTERS. Simply I could use for loop, but I want to do this by Streams.
My code:
package shared;
import java.util.Arrays;
public class Validator {
private static final Character[] ILLEGAL_CHARACTERS =
{'/','\n','\r','\t','\0','\f','`','?','*','\\','<','>','|','\"',':'};
public static boolean fileNameIsValid(String fileName) {
return Arrays.stream(ILLEGAL_CHARACTERS).anyMatch(fileName::contains);
}
}
Problem is in contains method cuz It needs a CharSequence instead of char. Is there any way to do this by stream without changing Character[] type to String[]?
Streams might not the best fit here. Also, now your solution has quadratic complexity (N*M, where N is the file name length, and M is the size of your illegal character array), which is not very performant. As proposed in the comments, you could use a regular expression:
private static final Pattern ILLEGAL_CHARACTERS_REGEX =
Pattern.compile("[/\n\r\t\0\f`?*\\\\<>|\":]");
public static boolean fileNameIsValidRegex(String fileName) {
return !ILLEGAL_CHARACTERS_REGEX.matcher(fileName).find();
}
Or, if your illegal character set is limited to ASCII, you could play around with a bitset to squeeze some performance:
private static final BitSet ILLEGAL_CHARACTERS = new BitSet();
static {
for (char c : new char[]{
'/','\n','\r','\t','\0','\f','`','?','*','\\','<','>','|','\"',':'}) {
ILLEGAL_CHARACTERS.set(c);
}
}
public static boolean fileNameIsValid(String fileName) {
return fileName.chars().noneMatch(ILLEGAL_CHARACTERS::get);
}
You can try to use indexOf:
return Arrays.stream(ILLEGAL_CHARACTERS)
.map(fileName::indexOf)
.anyMatch(i -> i >= 0);
First, I would recommend that you use a Set instead of an array, because you don't have any need for indexing your stuff, then Stream over the characters from the given string, and check if there is any match with your set.
Get the chars from the chars() method on a string, this will give you a array of integeres, which you then can cast to an char "array"
Here's all you need:
private static final Set<Character> ILLEGAL_CHARACTERS = Set.of(
'/','\n','\r','\t','\0','\f','`','?','*','\\','<','>','|','\"',':');
public static boolean fileNameIsValid(String fileName) {
return fileName.chars()
.mapToObj(c -> (char) c)
.noneMatch(ILLEGAL_CHARACTERS::contains);
}
If contains method needs a CharSequence instead of char, then you can give it to it:
Arrays.stream(ILLEGAL_CHARACTERS)
.map(String::valueOf)
.anyMatch(fileName::contains);
But under the hood in the String class, this method uses indexOf(String str) method:
public boolean contains(CharSequence s) {
return indexOf(s.toString()) > -1;
}
So, to avoid redundant type conversion, you can use another indexOf(int ch) method:
Arrays.stream(ILLEGAL_CHARACTERS).anyMatch(ch -> fileName.indexOf(ch) > -1);
See also: How to “subtract” 2 given strings In Java?
Two bellow snippets with the same output, one with using Functional interface and lambda expression, while the other snippet uses two simple method and easy to understand. What are the benefits first snippet code while it increases complexity.
First:
interface StringFunction {
String run(String str);
}
public class Main {
public static void main(String[] args) {
StringFunction exclaim = (s) -> s + "!";
StringFunction ask = (s) -> s + "?";
printFormatted("Hello", exclaim);
printFormatted("Hello", ask);
}
public static void printFormatted(String str, StringFunction format) {
String result = format.run(str);
System.out.println(result);
}
}
Second:
public class Main {
public static void main(String[] args) {
System.out.println(exclaim("Hello"));
System.out.println(ask("Hello"));
}
static String exclaim(String s) {
return s + "!";
}
static String ask(String s) {
return s + "?";
}
}
In the first example, you are passing a behaviour which you can change for every call in a much cleaner and succinct way than your second way e.g.
StringFunction exclaim = s -> s + "!";
printFormatted("Hello", exclaim);
exclaim = s -> s + "!!!";
printFormatted("Hello", exclaim);
If you have to do it in your second way, you will have to write another method for it.
On a side note, in your lambda expression, you do not need the parenthesis in case of a single parameter i.e. you can write it simply as (I've already done this way in the code above):
StringFunction exclaim = s -> s + "!";
StringFunction ask = s -> s + "?";
Biggest advantage of lambda expressions is they are focused on expression instead of object's state.
That means you specify exactly what you wants without dealing with object you pass
there. This allows you to use any object and get result you are expecting.
After all lambdas are still interfaces defining behavior as any other interfaces and depends on their implementation in concrete class.
Your provided code snippet is missing bigger complexity so lambda seems to be overkill there. But in complex systems it supports better maintainability and get rid of tight coupling
I am not understanding the reason, for having the compilation error for the below program. Where am I going wrong? I want to print the value of the string as output using method reference.
public class ConsumerDemo{
public static void main(String[] args) {
test("hello", (str)-> str::toUpperCase);
}
public static void test(String str, Consumer<String> consumer) {
consumer.accept(str);
}
}
test("hello", String::toUpperCase)
should be the correct syntax.
In order to print the upper case of the input, you can use:
String str = "hello"; // any input value
test(str.toUpperCase(), System.out::println);
you cannot combine lambda syntax and method reference syntax as such.
You're either looking for:
test("hello", String::toUpperCase);
or:
test("hello", s -> s.toUpperCase());
but this then means the result of String::toUpperCase/s -> s.toUpperCase() is ignored hence, you'll need to perform something more useful. for example:
test("hello", s -> System.out.println(s.toUpperCase()));
Is there any way in Java to create a method, which is expecting two different varargs?
I know, with the same object kind it isn't possible because the compiler doesn't know where to start or to end. But why it also isn't possible with two different Object types?
For example:
public void doSomething(String... s, int... i){
//...
//...
}
Is there any way to create a method like this?
Thank you!
Only one vararg, sorry. But using asList() makes it almost as convenient:
public void myMethod(List<Integer> args1, List<Integer> args2) {
...
}
-----------
import static java.util.Arrays.asList;
myMethod(asList(1,2,3), asList(4,5,6));
In Java, only one varargs argument is allowed and it must be the last parameter of the signature.
But all it does it convert it to an array anyway, so you should just make your two parameters explicit arrays:
public void doSomething(String[] s, int[] i){
A possible API design in which the calling code looks like
doSomething("a", "b").with(1,2);
through "fluent" API
public Intermediary doSomething(String... strings)
{
return new Intermediary(strings);
}
class Intermediary
{
...
public void with(int... ints)
{
reallyDoSomething(strings, ints);
}
}
void reallyDoSomething(String[] strings, int[] ints)
{
...
}
The danger is if the programmer forgot to call with(...)
doSomething("a", "b"); // nothing is done
Maybe this is a little better
with("a", "b").and(1, 2).doSomething();
Only one vararg is allowed. This is because multiple vararg arguments are ambiguous. For example, what if you passed in two varargs of the same class?
public void doSomething(String...args1, String...args2);
Where does args1 end and args2 begin? Or how about something more confusing here.
class SuperClass{}
class ChildClass extends SuperClass{}
public void doSomething(SuperClass...args1, ChildClass...args2);
ChildClass extends SuperClass, and so is can legally exist in args1, or args2. This confusion is why only one varargs is allowed.
varargs must also appear at the end of a method declaration.
Just declare the specific type instead as 2 arrays.
Although this kind of thing is occasionally useful, usually if you find that you are hitting a restriction in Java you could probably redesign something and come out much better. Here are some possible other ways to look at it...
If the two lists are related at all you probably want to create a wrapper class for the two different lists and pass in the wrapper. Wrappers around collections are almost always a good idea--they give you a place to add code that relates to the collection.
If this is a way to initialize data, parse it from a string. For instance, "abc, 123:def, 456:jhi,789" is almost embarassingly easy to split up with 2 split statements and a loop (2-3 lines of code). You can even make a little custom parser class that parses a string like that into a structure you feed into your method.
Hmm--honestly asside from initializing data I don't even know why you'd want to do this anyway, any other case and I expect you'd be passing in 2 collections and wouldn't be interested in varags at all.
You can do something like this, then you can cast and add additional logic inside that method.
public void doSomething(Object... stringOrIntValues) {
...
...
}
And use this method like so:
doSomething(stringValue1, stringValue2, intValue1, intValue2,
intValue3);
This is an old thread, but I thought this would be helpful regardless.
The solution I found isn't very neat but it works. I created a separate class to handle the heavy lifting. It only has the two variables I needed and their getters. The constructor handles the set methods on its own.
I needed to pass direction objects and a respective Data object. This also solves the possible problem of uneven data pairs, but that is probably only for my usage needs.
public class DataDirectionPair{
Data dat;
Directions dir;
public DataDirectionPair(Data dat, Directions dir) {
super();
this.dat = dat;
this.dir = dir;
}
/**
* #return the node
*/
public Node getNode() {
return node;
}
/**
* #return the direction
*/
public Directions getDir() {
return dir;
}
}
I would then just pass this class as the vararg for the method
public void method(DataDirectionPair... ndPair){
for(DataDirectionPair temp : ndPair){
this.node = temp.getNode();
this.direction = temp.getDir();
//or use it however you want
}
}
It is not possible because the Java Language Specification says so (see 8.4.1. Formal Parameters):
The last formal parameter of a method or constructor is special: it
may be a variable arity parameter, indicated by an ellipsis
following the type.
Note that the ellipsis (...) is a token unto itself (§3.11). It is possible to put whitespace between it and the type, but this is
discouraged as a matter of style.
If the last formal parameter is a variable arity parameter, the method
is a variable arity method. Otherwise, it is a fixed arity method.
As to why only one and only the last parameter, that would be a guess, but probably because allowing that could lead to undecidable or ambiguous problems (eg consider what happens with method(String... strings, Object... objects)), and only allowing non-intersecting types would lead to complications (eg considering refactorings where previously non-intersecting types suddenly are), lack of clarity when it does or does not work, and complexity for the compiler to decide when it is applicable or not.
I just read another question about this "pattern", but it is already removed, so I would like to propose a different approach to this problem, as I didn't see here this solution.
Instead to force the developer to wrapping the inputs parameter on List or Array, it will be useful to use a "curry" approach, or better the builder pattern.
Consider the following code:
/**
* Just a trivial implementation
*/
public class JavaWithCurry {
private List<Integer> numbers = new ArrayList<Integer>();
private List<String> strings = new ArrayList<String>();
public JavaWithCurry doSomething(int n) {
numbers.add(n);
return this;
}
public JavaWithCurry doSomething(String s) {
strings.add(s);
return this;
}
public void result() {
int sum = -1;
for (int n : numbers) {
sum += n;
}
StringBuilder out = new StringBuilder();
for (String s : strings) {
out.append(s).append(" ");
}
System.out.println(out.toString() + sum);
}
public static void main(String[] args) {
JavaWithCurry jwc = new JavaWithCurry();
jwc.doSomething(1)
.doSomething(2)
.doSomething(3)
.doSomething(4)
.doSomething(5)
.doSomething("a")
.doSomething("b")
.doSomething("c")
.result();
}
}
As you can see you in this way, you could add new elements of which type you need when you need.
All the implementation is wrapped.
If you are not going to be passing a large number of Strings most of the time for the first argument you could provide a bunch of overloads that take different numbers of Strings and wrap them in an array before calling a method that takes the array as the first argument.
public void doSomething(int... i){
doSomething(new String[0], i);
}
public void doSomething(String s, int... i){
doSomething(new String[]{ s }, i);
}
public void doSomething(String s1, String s2, int... i){
doSomething(new String[]{ s1, s2 }, i);
}
public void doSomething(String s1, String s2, String s3, int... i){
doSomething(new String[]{ s1, s2, s3 }, i);
}
public void doSomething(String[] s, int... i) {
// ...
// ...
}
follwing on Lemuel Adane (cant comment on the post, due to lack of rep :))
if you use
public void f(Object... args){}
then you may loop using How to determine an object's class (in Java)?
like for instance
{
int i = 0;
while(i< args.length && args[i] instanceof String){
System.out.println((String) args[i]);
i++ ;
}
int sum = 0;
while(i< args.length){
sum += (int) args[i];
i++ ;
}
System.out.println(sum);
}
or anything you intend to do.
You can convert your varargs to arrays
public void doSomething(String[] s, int[] i) {
...
}
then with some helper methods to convert your varargs to array like this:
public static int[] intsAsArray(int... ints) {
return ints;
}
public static <T> T[] asArray(T... ts) {
return ts;
}
Then you can use those helper methods to convert your vararged parameters.
doSomething(asArray("a", "b", "c", "d"), intsAsArray(1, 2, 3));
I am asked to "Write a static method which, given a String as an input parameter, will return another String representing the input string with all vowels removed."
I'm not exactly sure what they mean by this. I wrote this below. What would I need to change to the answer? Thanks
public static void main(String[] args) {
String s = "Hello there";
String s1 = s.replaceAll("[AaEeIiOoUu]", "");
System.out.print(s1);
}
Check answers from #NicksTyagi and others for the static method. However, I wanted to point out that you can optimize your regex like this: (?i)[aeiouy].
(?i) is an inline flag that indicates that the part of the regex that follows it, is case insensitive. By using this flag it's not necessary to put the letters in upper case.
Feel free to remove the y from the regex if it isn't considered as a vowel in your language.
Sample code
public static String removeVowels(String input) {
return input.replaceAll("(?i)[aeiouy]", "");
}
The static method you copied and pasted into your question is called main. It's kind of special, it takes a string[] as an argument, and it always returns void. In order to complete your assignment, you need to write another static method.
First, you need to give it a name.
static myFunction() {
}
Next, give it a return (output) type. Your assignment was to return a String.
static String myfunction() {
}
Then, you need to let it accept a parameter (input) of type String.
static String myFunction(String input) {
}
Almost last, we'll add in the logic to transform the input into an output.
static String myFunction(String input) {
input = input.replaceAll("[AaEeIiOoUu]", "");
}
Finally, we need to return the output.
static String myFunction(String input) {
String output = input.replaceAll("[AaEeIiOoUu]", "");
return output;
}
Viola. You are done! You won't need to know much more about the static keyword until you study object-oriented programming. The correct definition is that static methods are bound to a class, while non-static methods are bound to an instance of a class. Here is a gruesome example.
A static method could accept a Person and return a Person with all of its arms chopped off.
I am a person. I could use my very own non-static method to remove all of my arms.
Hope that helps you remember!
The class must be as below :
public class Demo {
public static String replaceVowel(String input)
{
input = input.replaceAll("[AaEeIiOoUu]", "");
return input;
}
public static void main(String[] args) {
String output = Demo.replaceVowel("Hello World");
System.out.println(output);
}
}
You just need to create another method with the static keyword. Call this method from main.
public static void main(Strings args[]){
removeVowels("Hello World");
}
public static String removeVowels(String textWithVowels){
return textWithVowels.replaceAll("[AaEeIiOoUu]", "");
}