I'm new to scala and I'm trying to get used to the language. I was looking for an equivalent to the following Java synchronisation technique.
private final Map<String, Future<Boolean>> requestMap = new HashMap<>();
public void updateMap(String key) {
synchronized(requestMap) {
// update contents of requestMap
}
}
I think the syntax below is the Scala equivalent of the Java above.
private val requestMap = new mutable.LinkedHashMap[String, Future[Boolean]]
def updateMap(key: String): Unit = {
requestMap.synchronized {
// update contents of requestMap
}
}
What I'm trying to achieve here is ensuring that only one thread can manipulate the requestMap object at any given time in the updateMap method. I want to know are the two examples above equivalent and where can I find this Scala usage of synchronized documented?
You are right, these are equivalent:
//Java
synchronized(foo) { statements ... }
//Scala
foo.synchronized { statements ... }
In scala, synchronized is a library construct (although a synthetic one) - that is, it is a method on AnyRef
Referring to the same discussion can we have something like this and will it make the code inside AnyRef.synchronized, thread safe?
Object abc {
...
*AnyRef*.synchronized{
val ff = new FunClass()
ff.displayTs()
}
}
class FunClass() {
def displayTs(): Unit{
println(timestamp)
}
}
...
}
Related
In Java we can not reassign a reference inside a method.
So the following does not work:
class SomeClass {
List<PaidOrders> paidOrders;
List<PendingOrders> pendingOrders;
List<CancelledOrders> cancelledOrders;
private void process(List<OrderStatus> data, List<Orders> currentOrderlist) {
List<Order> newOrders = fromOrderStatus(data);
currentOrderlist = newOrders;
}
}
But the following does work:
class SomeClass {
private void process(List<OrderStatus> data, List<Orders> currentOrderlist) {
List<Order> newOrders = fromOrderStatus(data);
currentOrderlist.clear();
currentOrderlist.addAll(newOrders); // <- extra linear loop
}
}
The problem is that the second example does an extra linear loop to copy from one list to the other.
Question:
I was wondering, is there some design approach so that I could neatly just replace the references instead? I.e. somehow make the first snippet work with some change in the parameters or something?
Update
After the comments I would like to clarify that the currentOrderList can be any of the paidOrders, pendingOrders, cancelledOrders.
The code for process is the same for all types.
Hm. I see two possibilities here. Either you use some wrapper object such as AtomicReference (might be a bit overpowered because of the multi-threading issues) as the argument and then just set it there or you use a consumer.
In the second case your method would look like this:
public void process(List<OrderStatus> data, Consumer<List<Orders>> target) {
List<Person> newOrders = fromOrderStatus(data);
target.accept(newOrders);
}
Then on the calling side you would implement it like this:
process(data, e-> <<targetList>> = e);
If your list will be wrapped by a different object (for example - AtomicReference), then you will be able to change it.
public static void doSomething(AtomicReference<List<Integer>> listAtomicReference){
List<Integer> newIntegers = new ArrayList<>();
listAtomicReference.set(newIntegers);
}
public static void main(String[] args) {
AtomicReference<List<Integer>> listAtomicReference = new AtomicReference<>(Arrays.asList(4));
doSomething(listAtomicReference);
System.out.println(listAtomicReference.get());
}
Output:
[]
Making a public member variable in a class.
With that being said, I wouldn't recommend walking this path.
Is premature optimization really the root of all evil?
I am trying to convert the python code provided by our instructor into the equivalent Java code. This portion of code is supposed to read from a txt file, parse the data with regex, and store them as an array of words. A restriction for this exercise is that the "data_storage_obj" is used to imitate JavaScript Object, and we have to keep them in that key-value format.
The instruction indicates that a data structure in Java that is closest to a JavaScript Object is "HashMap". However, because key each maps to a different data structure for storing the corresponding information, the best type I can think of so far is "Object". However, one of the keys maps to a lambda function, so I get this error message saying "error: incompatible types: Object is not a functional interface". I'm wondering what type I should be using to cover all the types I am going to store as the map values.
A snippet of code provided by the instructor:
def extract_words(obj, path_to_file):
with open(path_to_file) as f:
obj['data'] = f.read()
pattern = re.compile('[\W_]+')
data_str = ''.join(pattern.sub(' ', obj['data']).lower())
obj['data'] = data_str.split()
data_storage_obj = {
'data' : [],
'init' : lambda path_to_file : extract_words(data_storage_obj, path_to_file),
'words' : lambda : data_storage_obj['data']
}
data_storage_obj['init'](sys.argv[1])
Java code I have been working on:
public class Twelve{
static void extract_words(Object obj, String path_to_file){
System.out.println("extract_words()");
if(obj instanceof HashMap){
HashMap<String, Object> hashMap = (HashMap<String, Object>) obj;
String file_data = "";
try {
file_data = (new String(Files.readAllBytes(Paths.get(path_to_file)))).replaceAll("[\\W_]+", " ").toLowerCase();
} catch (IOException e) {
e.printStackTrace();
}
hashMap.put("data", Arrays.asList(file_data.split(" ")));
obj = hashMap;
}
}
static HashMap<String, Object> data_storage_obj = new HashMap<>();
public static void main(String[] args){
ArrayList<String> data = new ArrayList<String>();
data_storage_obj.put("data", data);
data_storage_obj.put("init", path_to_file -> extract_words(data_storage_obj, path_to_file));
data_storage_obj.put("words", data_storage_obj.get("data"));
}
}
To represent an object with "static" properties, you can use a Singleton:
class DataStorage {
ArrayList<String> data = new ArrayList<String>();
void init(String pathToFile) { // ¹
// ²
try {
this.data = (new String(Files.readAllBytes(Paths.get(pathToFile)))).replaceAll("[\\W_]+", " ").toLowerCase();
} catch (IOException e) {
e.printStackTrace();
}
}
ArrayList<String> getWords() { // ³
return this.data;
}
}
When transpiling from a scripting language (Python, JavaScript) into a statically typed language (Java), you cannot just keep the dynamic structure. Instead you have to add adequate types, and as Java only has classes, you need another class here.
When transpiling, you should adapt the common practices from the language you are transpiling into:
¹: Use camelCase for methods / variables.
²: As there are no standalone functions in Java, extract_words could be directly merged with the init method (or you add it as a static method to DataStorage).
³: As there are no real getters/setters in Java, you have to fall back to the "method as getter" pattern.
I have an Try<Option<Foo>>. I want to flatMap Foo into a Bar, using it using an operation that can fail. It's not a failure if my Option<Foo> is an Option.none(), (and the Try was a success) and in this case there's nothing to do.
So I have code like this, which does work:
Try<Option<Bar>> myFlatMappingFunc(Option<Foo> fooOpt) {
return fooOpt.map(foo -> mappingFunc(foo).map(Option::of) /* ew */)
.getOrElse(Try.success(Option.none()); // double ew
}
Try<Bar> mappingFunc(Foo foo) throws IOException {
// do some mapping schtuff
// Note that I can never return null, and a failure here is a legitimate problem.
// FWIW it's Jackson's readValue(String, Class<?>)
}
I then call it like:
fooOptionTry.flatMap(this::myFlatMappingFunc);
This does work, but it looks really ugly.
Is there a better way to flip the Try and Option around?
Note 1: I actively do not want to call Option.get() and catch that within the Try as it's not semantically correct. I suppose I could recover the NoSuchElementException but that seems even worse, code-wise.
Note 2 (to explain the title): Naively, the obvious thing to do is:
Option<Try<Bar>> myFlatMappingFunc(Option<Foo> fooOpt) {
return fooOpt.map(foo -> mappingFunc(foo));
}
except this has the wrong signature and doesn't let me map with the previous operation that could have failed and also returned a successful lack of value.
When you are working with monads, each monad type combine only with monads of same type. This is usually a problem because the code will come very unreadable.
In the Scala world, there are some solutions, like the OptionT or EitherT transformers, but do this kind of abstractions in Java could be difficult.
The simple solution is to use only one monad type.
For this case, I can think in two alternatives:
transform fooOpt to Try<Foo> using .toTry()
transform both to Either using .toEither()
Functional programmers are usually more comfortable with Either because exceptions will have weird behaviors, instead Either usually not, and both works when you just want to know why and where something failed.
Your example using Either will look like this:
Either<String, Bar> myFlatMappingFunc(Option<Foo> fooOpt) {
Either<String, Foo> fooE = fooOpt.toEither("Foo not found.");
return fooE.flatMap(foo -> mappingFunc(foo));
}
// Look mom!, not "throws IOException" or any unexpected thing!
Either<String, Bar> mappingFunc(Foo foo) {
return Try.of(() -> /*do something dangerous with Foo and return Bar*/)
.toEither().mapLeft(Throwable::getLocalizedMessage);
}
I believe this is simply a sequence function (https://static.javadoc.io/io.vavr/vavr/0.9.2/io/vavr/control/Try.html#sequence-java.lang.Iterable-) that you are looking for:
Try.sequence(optionalTry)
You can combine Try.sequence and headOption functions and create a new transform function with a little better look, in my opinion, also you can use generic types to get a more reusable function :) :
private static <T> Try<Option<T>> transform(Option<Try<T>> optT) {
return Try.sequence(optT.toArray()).map(Traversable::headOption);
}
If I understand correctly, you want to :
keep the first failure if happens
swap the second when mapping to json for an empty option.
Isn t it simpler if you decompose your function in such a way:
public void keepOriginalFailureAndSwapSecondOneToEmpty() {
Try<Option<Foo>> tryOptFoo = null;
Try<Option<Bar>> tryOptBar = tryOptFoo
.flatMap(optFoo ->
tryOptionBar(optFoo)
);
}
private Try<Option<Bar>> tryOptionBar(Option<Foo> optFoo) {
return Try.of(() -> optFoo
.map(foo -> toBar(foo)))
.orElse(success(none())
);
}
Bar toBar(Foo foo) throws RuntimeException {
return null;
}
static class Bar {
}
static class Foo {
}
The solution of throughnothing and durron597 helped me there. This is my groovy test case:
def "checkSomeTry"() {
given:
def ex = new RuntimeException("failure")
Option<Try<String>> test1 = Option.none()
Option<Try<String>> test2 = Option.some(Try.success("success"))
Option<Try<String>> test3 = Option.some(Try.failure(ex))
when:
def actual1 = Try.sequence(test1).map({ t -> t.toOption() })
def actual2 = Try.sequence(test2).map({ t -> t.toOption() })
def actual3 = Try.sequence(test3).map({ t -> t.toOption() })
then:
actual1 == Try.success(Option.none())
actual2 == Try.success(Option.some("success"))
actual3 == Try.failure(ex)
}
How can I port a java inner function from here
which fully is contained in to Scala?
JavaPairRDD<Envelope, HashSet<Point>> castedResult = joinListResultAfterAggregation.mapValues(new Function<HashSet<Geometry>,HashSet<Point>>()
{
#Override
public HashSet<Point> call(HashSet<Geometry> spatialObjects) throws Exception {
HashSet<Point> castedSpatialObjects = new HashSet<Point>();
Iterator spatialObjectIterator = spatialObjects.iterator();
while(spatialObjectIterator.hasNext())
{
castedSpatialObjects.add((Point)spatialObjectIterator.next());
}
return castedSpatialObjects;
}
});
return castedResult;
My approach as outlined below would not compile due to some NotinferredU
val castedResult = joinListResultAfterAggregation.mapValues(new Function[java.util.HashSet[Geometry], java.util.HashSet[Point]]() {
def call(spatialObjects: java.util.HashSet[Geometry]): java.util.HashSet[Point] = {
val castedSpatialObjects = new java.util.HashSet[Point]
val spatialObjectIterator = spatialObjects.iterator
while (spatialObjectIterator.hasNext) castedSpatialObjects.add(spatialObjectIterator.next.asInstanceOf[Point])
castedSpatialObjects
}
})
When asking a question about compilation errors please provide the exact error, especially when your code doesn't stand on its own.
The inner function itself is fine; my guess would be that due to changes above joinListResultAfterAggregation isn't a JavaPairRDD anymore, but a normal RDD[(Envelope, Something)] (where Something could be java.util.HashSet, scala.collection.Set or some subtype), so its mapValues takes a Scala function, not a org.apache.spark.api.java.function.Function. Scala functions are written as lambdas: spatialObjects: Something => ... (the body will depend on what Something actually is, and the argument type can be omitted in some circumstances).
How about this ?
val castedResult = joinListResultAfterAggregation.mapValues(spatialObjects => {
spatialObjects.map(obj => (Point) obj)
})
The following code works and is readable but it seems to me I have intermediate operations that feel like they shouldn't be necessary. I've written this simplified version as the actual code is part of a much larger process.
I've got a Collection of Widget, each with a name and multiple types (indicated by constants of the WidgetType enum). These multiple types are gettable as a Stream<WidgetType> though, if necessary, I could return those as some other type. (For various reasons, it is strongly desirable that these be returned as a Stream<WidgetType> because of how these widgets are used later in the actual code.)
These widgets are added to an EnumMap<WidgetType, List<Widget>> which is, later, translated into an EnumMap<WidgetType, Widget[]>.
If each Widget only had a single WidgetType, this would be a trivial solve but, since any Widget could have 1 or more types, I am tripping all over myself with the syntax of the Collectors.groupingBy() method (and its overloads).
Here's the code example, again, fully functional and gives me the exact result I need.
class StackOverFlowExample {
private final Map<WidgetType, Widget[]> widgetMap = new EnumMap<>(WidgetType.class);
public static void main(String[] args) { new StackOverFlowExample(); }
StackOverFlowExample() {
Collection<Widget> widgetList = getWidgetsFromWhereverWidgetsComeFrom();
{
final Map<WidgetType, List<Widget>> intermediateMap = new EnumMap<>(WidgetType.class);
widgetList.forEach(w ->
w.getWidgetTypes().forEach(wt -> {
intermediateMap.putIfAbsent(wt, new ArrayList<>());
intermediateMap.get(wt).add(w);
})
);
intermediateMap.entrySet().forEach(e -> widgetMap.put(e.getKey(), e.getValue().toArray(new Widget[0])));
}
Arrays.stream(WidgetType.values()).forEach(wt -> System.out.println(wt + ": " + Arrays.toString(widgetMap.get(wt))));
}
private Collection<Widget> getWidgetsFromWhereverWidgetsComeFrom() {
return Arrays.asList(
new Widget("1st", WidgetType.TYPE_A, WidgetType.TYPE_B),
new Widget("2nd", WidgetType.TYPE_A, WidgetType.TYPE_C),
new Widget("3rd", WidgetType.TYPE_A, WidgetType.TYPE_D),
new Widget("4th", WidgetType.TYPE_C, WidgetType.TYPE_D)
);
}
}
This outputs:
TYPE_A: [1st, 2nd, 3rd]
TYPE_B: [1st]
TYPE_C: [2nd, 4th]
TYPE_D: [3rd, 4th]
For completeness sake, here's the Widget class and the WidgetType enum:
class Widget {
private final String name;
private final WidgetType[] widgetTypes;
Widget(String n, WidgetType ... wt) { name = n; widgetTypes = wt; }
public String getName() { return name; }
public Stream<WidgetType> getWidgetTypes() { return Arrays.stream(widgetTypes).distinct(); }
#Override public String toString() { return name; }
}
enum WidgetType { TYPE_A, TYPE_B, TYPE_C, TYPE_D }
Any ideas on a better way to execute this logic are welcome. Thanks!
IMHO, the key is to convert a Widget instance to a Stream<Pair<WidgetType, Widget>> instance. Once we have that, we can flatMap a stream of widgets and collect on the resulting stream. Of course we don't have Pair in Java, so have to use AbstractMap.SimpleEntry instead.
widgets.stream()
// Convert a stream of widgets to a stream of (type, widget)
.flatMap(w -> w.getTypes().map(t->new AbstractMap.SimpleEntry<>(t, w)))
// Grouping by the key, and do additional mapping to get the widget
.collect(groupingBy(e->e.getKey(),
mapping(e->e.getValue,
collectingAndThen(toList(), l->l.toArray(new Widget[0])))));
P.S. this is an occasion where IntelliJ's suggestion doesn't shorten a lambda with method reference.
This is a bit convoluted, but it produces the same output, not necessarily in the same order. It uses a static import of java.util.stream.Collectors.*.
widgetMap = widgetList.stream()
.flatMap(w -> w.getWidgetTypes().map(t -> new AbstractMap.SimpleEntry<>(t, w)))
.collect(groupingBy(Map.Entry::getKey, collectingAndThen(mapping(Map.Entry::getValue, toSet()), s -> s.stream().toArray(Widget[]::new))));
Output on my machine:
TYPE_A: [1st, 3rd, 2nd]
TYPE_B: [1st]
TYPE_C: [2nd, 4th]
TYPE_D: [3rd, 4th]